Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/libmetal/demos/irq_shmem_demo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
collect (PROJECT_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/common")
add_subdirectory(${ROLE})
30 changes: 30 additions & 0 deletions examples/libmetal/demos/irq_shmem_demo/common/irq_shmem_demo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2026, Advanced Micro Devices, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef __IRQ_SHMEM_DEMO_H__
#define __IRQ_SHMEM_DEMO_H__

#include <stdint.h>

#include <metal/io.h>

/*
* Common transport state shared by the host and remote implementations of the
* IRQ shared-memory demo. Platform- or OS-private wait state is kept behind
* machine_ctx to avoid duplicating this layout in each machine header.
*/
struct channel_s {
struct metal_io_region *host_to_remote_desc_io; /* host to remote descriptors */
struct metal_io_region *remote_to_host_desc_io; /* remote to host descriptors */
struct metal_io_region *ipi_io; /* IPI metal i/o region */
struct metal_io_region *shm_io; /* Shared memory metal i/o region */
struct metal_io_region *ttc_io; /* TTC metal i/o region */
void *machine_ctx; /* Platform- or OS-private channel state */
uint32_t ipi_mask; /* RPU IPI mask */
int irq_vector_id; /* IRQ number. */
};

#endif /* __IRQ_SHMEM_DEMO_H__ */
8 changes: 6 additions & 2 deletions examples/libmetal/demos/irq_shmem_demo/host/irq_shmem_demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ static inline void dump_buffer(void *buf, unsigned int len)
*/
static int irq_shmem_echo(struct channel_s *ch)
{
struct channel_machine_ctx_s *machine = channel_machine_ctx(ch);
struct metal_io_region *desc_host_to_remote = ch->host_to_remote_desc_io;
struct metal_io_region *desc_remote_to_host = ch->remote_to_host_desc_io;
struct metal_io_region *payload_io = ch->shm_io;
Expand Down Expand Up @@ -241,7 +242,7 @@ static int irq_shmem_echo(struct channel_s *ch)

while (i != PKGS_TOTAL) {

wait_for_notified(&ch->remote_nkicked);
wait_for_notified(&machine->remote_nkicked);

rx_avail = metal_io_read32(desc_remote_to_host, rx_avail_offset);
while (i != rx_avail) {
Expand Down Expand Up @@ -376,7 +377,10 @@ static int irq_shmem_echo(struct channel_s *ch)

int main(void)
{
struct channel_s ch_s;
struct channel_machine_ctx_s ch_machine_s = {0};
struct channel_s ch_s = {
.machine_ctx = &ch_machine_s,
};
int ret = 0;

/* platform_init will set the OS agnostic channel information */
Expand Down
72 changes: 25 additions & 47 deletions examples/libmetal/demos/irq_shmem_demo/remote/irq_shmem_demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,49 +12,19 @@
* Shared-memory partitioning details are documented in machine/remote/amd_rpu/
* README.md.
*/
#include "common.h"

#include <stdbool.h>

#include "common.h"

#define BUF_SIZE_MAX 512
#define SHUTDOWN "shutdown"

/* Shared memory offsets */
#define SHM0_DESC_OFFSET 0x0
#define SHM1_DESC_OFFSET SHM0_DESC_SIZE
#define SHM_PAYLOAD_OFFSET (SHM0_DESC_SIZE + SHM1_DESC_SIZE)

/* Shared memory descriptors offset */
#define SHM_DESC_AVAIL_OFFSET 0x00
#define SHM_DESC_USED_OFFSET 0x04
#define SHM_DESC_ADDR_ARRAY_OFFSET 0x08

/* Descriptor 0 (Host to Remote) resides at SHM0_DESC_OFFSET.
* Descriptor 1 (Remote to Host) resides at SHM1_DESC_OFFSET.
* The payload carveout begins at SHM_PAYLOAD_OFFSET and is split evenly
* between RX (lower half) and TX (upper half).
*
* Note that H_TO_R_ is host to remote and R_TO_H_ is vice versa.
*/
#define SHM_DESC_OFFSET_H_TO_R SHM0_DESC_OFFSET
#define SHM_DESC_OFFSET_R_TO_H SHM1_DESC_OFFSET
#define SHM_PAYLOAD_H_TO_R SHM_PAYLOAD_RX_OFFSET
#define SHM_PAYLOAD_R_TO_H SHM_PAYLOAD_TX_OFFSET

#define H_TO_R_DESC_ADDR_START \
(SHM_DESC_OFFSET_H_TO_R + SHM_DESC_ADDR_ARRAY_OFFSET)
#define H_TO_R_DESC_ADDR_END \
(SHM_DESC_OFFSET_H_TO_R + SHM0_DESC_SIZE)
#define R_TO_H_DESC_ADDR_START \
(SHM_DESC_OFFSET_R_TO_H + SHM_DESC_ADDR_ARRAY_OFFSET)
#define R_TO_H_DESC_ADDR_END \
(SHM_DESC_OFFSET_R_TO_H + SHM1_DESC_SIZE)

#define H_TO_R_PAYLOAD_START SHM_PAYLOAD_H_TO_R
#define H_TO_R_PAYLOAD_END (SHM_PAYLOAD_H_TO_R + SHM_PAYLOAD_HALF_SIZE)
#define R_TO_H_PAYLOAD_START SHM_PAYLOAD_R_TO_H
#define R_TO_H_PAYLOAD_END (SHM_PAYLOAD_R_TO_H + SHM_PAYLOAD_HALF_SIZE)
#define SHM_DESC_ADDR_START SHM_DESC_ADDR_ARRAY_OFFSET
#define PKGS_TOTAL 1024

/**
Expand All @@ -70,10 +40,12 @@
*/
int demo(void *arg)
{
unsigned long tx_data_offset, rx_data_offset, rx_used_offset;
unsigned long tx_avail_offset, rx_avail_offset;
struct channel_machine_ctx_s ch_machine_s = {0};
unsigned long tx_data_offset, rx_data_offset;
unsigned long tx_addr_offset, rx_addr_offset;
struct channel_s ch_s = {0x0};
struct channel_s ch_s = {
.machine_ctx = &ch_machine_s,
};
struct channel_s *ch = &ch_s;
bool platform_ready = false;
uint32_t rx_count, rx_avail;
Expand Down Expand Up @@ -108,32 +80,35 @@ int demo(void *arg)
}

/* Set tx/rx buffer address offset */
tx_addr_offset = R_TO_H_DESC_ADDR_START;
rx_addr_offset = H_TO_R_DESC_ADDR_START;
tx_data_offset = R_TO_H_PAYLOAD_START;
tx_addr_offset = SHM_DESC_ADDR_START;
rx_addr_offset = SHM_DESC_ADDR_START;
tx_data_offset = SHM_PAYLOAD_TX_OFFSET;

metal_info("REMOTE: Wait for echo test to start.\n");
rx_count = 0;
while (1) {
system_suspend(ch);

rx_avail = metal_io_read32(ch->shm_io,
SHM_DESC_OFFSET_H_TO_R +
rx_avail = metal_io_read32(ch->host_to_remote_desc_io,
SHM_DESC_AVAIL_OFFSET);
while (rx_count != rx_avail) {
uint32_t buf_phy_addr;
/* Get the buffer location from the rx addr array. */
buf_phy_addr = metal_io_read32(ch->shm_io, rx_addr_offset);
buf_phy_addr = metal_io_read32(ch->host_to_remote_desc_io,
rx_addr_offset);
rx_data_offset = metal_io_phys_to_offset(ch->shm_io,
(metal_phys_addr_t)buf_phy_addr);
if (rx_data_offset == METAL_BAD_OFFSET) {
metal_err("REMOTE: [%u]failed to get rx offset: 0x%x, 0x%lx.\n",
rx_count, buf_phy_addr,
metal_io_phys(ch->shm_io, rx_addr_offset));
metal_io_phys(ch->host_to_remote_desc_io,
rx_addr_offset));
ret = -EINVAL;
goto out;
}
rx_addr_offset += sizeof(buf_phy_addr);
if (rx_addr_offset >= SHM0_DESC_SIZE)
rx_addr_offset = SHM_DESC_ADDR_START;

/* Read message header from shared memory */
ret = metal_io_block_read(ch->shm_io, rx_data_offset, lbuf,
Expand Down Expand Up @@ -168,8 +143,8 @@ int demo(void *arg)
payload = (char *)lbuf + sizeof(*msg_hdr);
rx_count++;
/* Increase rx used count to indicate received data was used. */
metal_io_write32(ch->shm_io,
SHM_DESC_OFFSET_H_TO_R + SHM_DESC_USED_OFFSET,
metal_io_write32(ch->host_to_remote_desc_io,
SHM_DESC_USED_OFFSET,
rx_count);

/* Check if it is the shutdown message. */
Expand Down Expand Up @@ -199,13 +174,16 @@ int demo(void *arg)
goto out;
}

metal_io_write32(ch->shm_io, tx_addr_offset, buf_phy_addr);
metal_io_write32(ch->remote_to_host_desc_io,
tx_addr_offset, buf_phy_addr);
tx_data_offset += sizeof(struct msg_hdr_s) + msg_hdr->len;
tx_addr_offset += sizeof(uint32_t);
if (tx_addr_offset >= SHM1_DESC_SIZE)
tx_addr_offset = SHM_DESC_ADDR_START;

/* Increase number of available buffers. */
metal_io_write32(ch->shm_io,
SHM_DESC_OFFSET_R_TO_H + SHM_DESC_AVAIL_OFFSET,
metal_io_write32(ch->remote_to_host_desc_io,
SHM_DESC_AVAIL_OFFSET,
rx_count);

/* Kick IRQ to notify data is in shared buffer. */
Expand Down
18 changes: 10 additions & 8 deletions examples/libmetal/machine/host/amd_linux_userspace/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <stdio.h>

#include "irq_shmem_demo.h"
#include "config.h"

/*
Expand Down Expand Up @@ -113,17 +114,18 @@ static inline void update_stat(struct metal_stat *pst, uint64_t val)
pst->st_max = val;
}

struct channel_s {
struct metal_io_region *host_to_remote_desc_io; /* host to remote descriptors */
struct metal_io_region *remote_to_host_desc_io; /* remote to host descriptors */
struct metal_io_region *ipi_io; /* IPI metal i/o region */
struct metal_io_region *shm_io; /* Shared memory metal i/o region */
struct metal_io_region *ttc_io; /* TTC metal i/o region */
struct channel_machine_ctx_s {
atomic_flag remote_nkicked; /* IRQ kick flag */
uint32_t ipi_mask; /* RPU IPI mask */
int irq_vector_id; /* IRQ number. */
};

static inline struct channel_machine_ctx_s *channel_machine_ctx(struct channel_s *ch)
{
metal_assert(ch);
metal_assert(ch->machine_ctx);

return (struct channel_machine_ctx_s *)ch->machine_ctx;
}

/**
* @ AMD RPU port for IRQ notification
* @param[in] irq_io - IO region used for IRQ kick
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ int open_metal_devices(void)
static int irq_isr(int vect_id, void *priv)
{
struct channel_s *ch = (struct channel_s *)priv;
struct channel_machine_ctx_s *machine = channel_machine_ctx(ch);
struct metal_io_region *ipi_io = ch->ipi_io;
uint32_t ipi_mask = IPI_MASK;
uint64_t val = 1;
Expand All @@ -105,7 +106,7 @@ static int irq_isr(int vect_id, void *priv)
val = metal_io_read32(ipi_io, IPI_ISR_OFFSET);
if (val & ipi_mask) {
metal_io_write32(ipi_io, IPI_ISR_OFFSET, ipi_mask);
atomic_flag_clear(&ch->remote_nkicked);
atomic_flag_clear(&machine->remote_nkicked);
return METAL_IRQ_HANDLED;
}
return METAL_IRQ_NOT_HANDLED;
Expand All @@ -117,6 +118,7 @@ int platform_init(struct channel_s *ch)
int ret;

metal_assert(ch);
metal_assert(ch->machine_ctx);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could use local variable here:

struct channel_machine_ctx_s *machine = channel_machine_ctx(ch);


ret = metal_init(&init_param);
if (ret) {
Expand All @@ -125,8 +127,8 @@ int platform_init(struct channel_s *ch)
}

/* initialize remote_nkicked */
ch->remote_nkicked = (atomic_flag)ATOMIC_FLAG_INIT;
atomic_flag_test_and_set(&ch->remote_nkicked);
channel_machine_ctx(ch)->remote_nkicked = (atomic_flag)ATOMIC_FLAG_INIT;
atomic_flag_test_and_set(&channel_machine_ctx(ch)->remote_nkicked);

ret = open_metal_devices();
if (ret) {
Expand Down
4 changes: 3 additions & 1 deletion examples/libmetal/machine/remote/amd_rpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ add_subdirectory (system)
set (_elf_name ${DEMO})

set (source_dirs ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/system/${PROJECT_SYSTEM})
collector_list (_inc_dirs PROJECT_INC_DIRS)
link_directories(${source_dirs})
include_directories(${source_dirs})
include_directories(${source_dirs} ${_inc_dirs})

collector_list (_deps PROJECT_LIB_DEPS)

Expand Down Expand Up @@ -60,5 +61,6 @@ target_link_libraries(${_elf_name}.elf PRIVATE
-Wl,--start-group ${_deps} -Wl,--end-group)

target_compile_definitions(${_elf_name}.elf PUBLIC ${USER_COMPILE_DEFINITIONS})
target_include_directories(${_elf_name}.elf PUBLIC ${_inc_dirs})
target_include_directories(${_elf_name}.elf PUBLIC ${USER_INCLUDE_DIRECTORIES})
install (TARGETS ${_elf_name}.elf RUNTIME DESTINATION bin)
Loading