diff --git a/examples/libmetal/demos/irq_shmem_demo/common/irq_shmem_demo.h b/examples/libmetal/demos/irq_shmem_demo/common/irq_shmem_demo.h index b8524cf2..381da74d 100644 --- a/examples/libmetal/demos/irq_shmem_demo/common/irq_shmem_demo.h +++ b/examples/libmetal/demos/irq_shmem_demo/common/irq_shmem_demo.h @@ -25,6 +25,9 @@ struct channel_s { void *machine_ctx; /* Platform- or OS-private channel state */ uint32_t ipi_mask; /* RPU IPI mask */ int irq_vector_id; /* IRQ number. */ + uint32_t desc0_size; /* host to remote descriptor region size */ + uint32_t desc1_size; /* remote to host descriptor region size */ + uint32_t shm_payload_size; /* shared payload buffer size */ }; #endif /* __IRQ_SHMEM_DEMO_H__ */ diff --git a/examples/libmetal/demos/irq_shmem_demo/host/irq_shmem_demo.c b/examples/libmetal/demos/irq_shmem_demo/host/irq_shmem_demo.c index 589f8196..0d45d180 100644 --- a/examples/libmetal/demos/irq_shmem_demo/host/irq_shmem_demo.c +++ b/examples/libmetal/demos/irq_shmem_demo/host/irq_shmem_demo.c @@ -24,8 +24,9 @@ * amd_linux_userspace/README.md. */ -#include +#include #include +#include #include #include #include @@ -37,30 +38,11 @@ #include "common.h" #include "platform_init.h" -/* Shared memory offsets */ -#define SHM_DESC_OFFSET_TX 0x0 -#define SHM_BUFF_OFFSET_TX 0x04000 -#define SHM_DESC_OFFSET_RX 0x02000 -#define SHM_BUFF_OFFSET_RX 0x104000 - /* Shared memory descriptors offset */ #define SHM_DESC_AVAIL_OFFSET 0x00 #define SHM_DESC_USED_OFFSET 0x04 #define SHM_DESC_ADDR_ARRAY_OFFSET 0x08 -/* Descriptor regions for each direction. */ -/* Note that H_TO_R_ is host to remote and R_TO_H_ is vice versa. */ -#define H_TO_R_DESC_ADDR_START SHM_DESC_ADDR_ARRAY_OFFSET -#define H_TO_R_DESC_ADDR_END SHM0_DESC_SIZE -#define R_TO_H_DESC_ADDR_START SHM_DESC_ADDR_ARRAY_OFFSET -#define R_TO_H_DESC_ADDR_END SHM1_DESC_SIZE - -/* Split of the data / payload area for each direction */ -#define H_TO_R_PAYLOAD_START SHM_PAYLOAD_RX_OFFSET -#define H_TO_R_PAYLOAD_END (SHM_PAYLOAD_RX_OFFSET + SHM_PAYLOAD_HALF_SIZE) -#define R_TO_H_PAYLOAD_START SHM_PAYLOAD_TX_OFFSET -#define R_TO_H_PAYLOAD_END (SHM_PAYLOAD_TX_OFFSET + SHM_PAYLOAD_HALF_SIZE) - #define PKGS_TOTAL 1024 #define BUF_SIZE_MAX 512 @@ -73,6 +55,83 @@ struct msg_hdr_s { uint32_t len; }; +enum { + OPT_SHM_DEV = 1000, + OPT_DESC0_DEV, + OPT_DESC1_DEV, + OPT_IPI_DEV, + OPT_TTC_DEV, + OPT_IPI_MASK_PROP, +}; + +static void usage(const char *prog, const struct app_platform_options *options) +{ + fprintf(stderr, + "Usage: %s [options]\n" + " --shm-dev Shared-memory UIO name (default: %s)\n" + " --desc0-dev Host-to-remote descriptor UIO name (default: %s)\n" + " --desc1-dev Remote-to-host descriptor UIO name (default: %s)\n" + " --ipi-dev IPI UIO name (default: %s)\n" + " --ttc-dev Timer UIO name (default: %s)\n" + " --ipi-mask-prop IPI remote-mask DT property (default: %s)\n" + " -h, --help Show this help text\n", + prog, options->shm_dev_name, options->desc0_dev_name, + options->desc1_dev_name, options->ipi_dev_name, + options->ttc_dev_name, options->ipi_remote_mask_property); +} + +static int parse_args(int argc, char **argv, + struct app_platform_options *options) +{ + static const struct option long_options[] = { + { "shm-dev", required_argument, NULL, OPT_SHM_DEV }, + { "desc0-dev", required_argument, NULL, OPT_DESC0_DEV }, + { "desc1-dev", required_argument, NULL, OPT_DESC1_DEV }, + { "ipi-dev", required_argument, NULL, OPT_IPI_DEV }, + { "ttc-dev", required_argument, NULL, OPT_TTC_DEV }, + { "ipi-mask-prop", required_argument, NULL, OPT_IPI_MASK_PROP }, + { "help", no_argument, NULL, 'h' }, + { 0, 0, 0, 0 } + }; + int c; + + while ((c = getopt_long(argc, argv, "h", long_options, NULL)) != -1) { + switch (c) { + case OPT_SHM_DEV: + options->shm_dev_name = optarg; + break; + case OPT_DESC0_DEV: + options->desc0_dev_name = optarg; + break; + case OPT_DESC1_DEV: + options->desc1_dev_name = optarg; + break; + case OPT_IPI_DEV: + options->ipi_dev_name = optarg; + break; + case OPT_TTC_DEV: + options->ttc_dev_name = optarg; + break; + case OPT_IPI_MASK_PROP: + options->ipi_remote_mask_property = optarg; + break; + case 'h': + usage(argv[0], options); + return 1; + default: + usage(argv[0], options); + return -EINVAL; + } + } + + if (optind != argc) { + usage(argv[0], options); + return -EINVAL; + } + + return 0; +} + /** * @brief wait_for_notified() - Loop until notified bit in channel is set. * @@ -137,6 +196,8 @@ static int irq_shmem_echo(struct channel_s *ch) unsigned long tx_avail_offset, rx_avail_offset; unsigned long tx_addr_offset, rx_addr_offset; unsigned long tx_data_offset, rx_data_offset; + uint32_t h_to_r_desc_addr_end, h_to_r_payload_start; + uint32_t h_to_r_payload_end, r_to_h_payload_start; void *txbuf = NULL, *rxbuf = NULL, *tmpptr; long long tdiff_avg_s = 0, tdiff_avg_ns = 0; unsigned long long tstart, tend; @@ -163,23 +224,31 @@ static int irq_shmem_echo(struct channel_s *ch) if (!ch || !ch->shm_io || !ch->host_to_remote_desc_io || !ch->remote_to_host_desc_io || !ch->ipi_io) { - return -EINVAL; + ret = -EINVAL; + goto out; } + h_to_r_desc_addr_end = ch->desc0_size; + h_to_r_payload_start = 0; + h_to_r_payload_end = ch->shm_payload_size / 2; + r_to_h_payload_start = ch->shm_payload_size / 2; + /* Clear shared memory and descriptors */ - ret = metal_io_block_set(ch->shm_io, 0, 0, SHM_PAYLOAD_SIZE); + ret = metal_io_block_set(ch->shm_io, 0, 0, ch->shm_payload_size); if (ret < 0) { metal_err("HOST: Failed to clear payload area.\n"); goto out; } - ret = metal_io_block_set(ch->host_to_remote_desc_io, 0, 0, SHM0_DESC_SIZE); + ret = metal_io_block_set(ch->host_to_remote_desc_io, 0, 0, + ch->desc0_size); if (ret < 0) { metal_err("HOST: Failed to clear host to remote descriptor area.\n"); goto out; } - ret = metal_io_block_set(ch->remote_to_host_desc_io, 0, 0, SHM1_DESC_SIZE); + ret = metal_io_block_set(ch->remote_to_host_desc_io, 0, 0, + ch->desc1_size); if (ret < 0) { metal_err("HOST: Failed to clear remote to host descriptor area.\n"); goto out; @@ -189,10 +258,10 @@ static int irq_shmem_echo(struct channel_s *ch) tx_avail_offset = SHM_DESC_AVAIL_OFFSET; rx_avail_offset = SHM_DESC_AVAIL_OFFSET; rx_used_offset = SHM_DESC_USED_OFFSET; - tx_addr_offset = H_TO_R_DESC_ADDR_START; - rx_addr_offset = R_TO_H_DESC_ADDR_START; - tx_data_offset = H_TO_R_PAYLOAD_START; - rx_data_offset = R_TO_H_PAYLOAD_START; + tx_addr_offset = SHM_DESC_ADDR_ARRAY_OFFSET; + rx_addr_offset = SHM_DESC_ADDR_ARRAY_OFFSET; + tx_data_offset = h_to_r_payload_start; + rx_data_offset = r_to_h_payload_start; metal_info("HOST: Start echo flood testing....\n"); metal_info("HOST: Sending msgs to the remote.\n"); @@ -225,11 +294,12 @@ static int irq_shmem_echo(struct channel_s *ch) goto out; } - metal_io_write32(desc_host_to_remote, tx_addr_offset, tx_phy_addr_32); + metal_io_write32(desc_host_to_remote, tx_addr_offset, + tx_phy_addr_32); tx_data_offset += sizeof(struct msg_hdr_s) + msg_hdr->len; tx_addr_offset += sizeof(uint32_t); - if (tx_addr_offset >= H_TO_R_DESC_ADDR_END) - tx_addr_offset = H_TO_R_DESC_ADDR_START; + if (tx_addr_offset >= h_to_r_desc_addr_end) + tx_addr_offset = SHM_DESC_ADDR_ARRAY_OFFSET; /* Increase number of available buffers */ metal_io_write32(desc_host_to_remote, tx_avail_offset, (i + 1)); @@ -238,7 +308,7 @@ static int irq_shmem_echo(struct channel_s *ch) } metal_info("HOST: Waiting for messages to echo back and verify.\n"); i = 0; - tx_data_offset = H_TO_R_PAYLOAD_START; + tx_data_offset = h_to_r_payload_start; while (i != PKGS_TOTAL) { @@ -314,8 +384,11 @@ static int irq_shmem_echo(struct channel_s *ch) } tx_data_offset += sizeof(*msg_hdr) + sizeof(tstart); + if (tx_data_offset >= h_to_r_payload_end) + tx_data_offset = h_to_r_payload_start; /* Compare the received message and the sent message */ - ret = memcmp(rxbuf, txbuf, sizeof(*msg_hdr) + sizeof(tstart)); + ret = memcmp(rxbuf, txbuf, + sizeof(*msg_hdr) + sizeof(tstart)); if (ret) { metal_err("HOST: data[%u] verification failed.\n", i); metal_info("HOST: Expected:"); @@ -375,16 +448,25 @@ static int irq_shmem_echo(struct channel_s *ch) return ret; } -int main(void) +int main(int argc, char **argv) { struct channel_machine_ctx_s ch_machine_s = {0}; + struct app_platform_options platform_options; struct channel_s ch_s = { .machine_ctx = &ch_machine_s, }; int ret = 0; + platform_get_default_options(&platform_options); + ret = parse_args(argc, argv, &platform_options); + if (ret) { + if (ret > 0) + return 0; + return ret; + } + /* platform_init will set the OS agnostic channel information */ - ret = platform_init(&ch_s); + ret = platform_init(&ch_s, &platform_options); if (ret) { metal_err("HOST: Failed to initialize system.\n"); return ret; diff --git a/examples/libmetal/machine/host/amd_linux_userspace/CMakeLists.txt b/examples/libmetal/machine/host/amd_linux_userspace/CMakeLists.txt index 42cf77fe..17b2b0bd 100644 --- a/examples/libmetal/machine/host/amd_linux_userspace/CMakeLists.txt +++ b/examples/libmetal/machine/host/amd_linux_userspace/CMakeLists.txt @@ -1,17 +1,6 @@ # Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved. # SPDX-License-Identifier: BSD-3-Clause -include (CheckIncludeFiles) -include (CheckCSourceCompiles) include (${APPS_ROOT_DIR}/../legacy_apps/cmake/options.cmake) -include (${APPS_ROOT_DIR}/../legacy_apps/cmake/collect.cmake) - -get_property (DEMO_CFG_FILE GLOBAL PROPERTY DEMO_CFG_FILE) -if (EXISTS ${DEMO_CFG_FILE}) - include(${DEMO_CFG_FILE}) - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" - "${CMAKE_CURRENT_SOURCE_DIR}/config.h") - message("WARNING: DEMO_CFG_FILE ${DEMO_CFG_FILE} passed in at configure time. Using this to configure demo.") -endif() collect (APP_COMMON_SOURCES platform_init.c) collect (APP_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/examples/libmetal/machine/host/amd_linux_userspace/README.md b/examples/libmetal/machine/host/amd_linux_userspace/README.md index d11f672d..14ebe466 100644 --- a/examples/libmetal/machine/host/amd_linux_userspace/README.md +++ b/examples/libmetal/machine/host/amd_linux_userspace/README.md @@ -19,14 +19,15 @@ messages. - Signals completion via IPI and then disables the interrupt and releases the mapped devices. ## Prerequisites -- Linux kernel exposes the shared memory carveouts and descriptor UIOs - (`9868000.shm`, `9860000.shm_desc`, `9864000.shm_desc` by default; adjust to - the platform-specific devices/offsets), along with IPI and TTC peripherals, - to userspace with permissions suitable for the demo binary. +- Linux kernel exposes the shared memory carveouts and descriptor UIOs to + userspace with stable logical names: + `libmetal-data`, `libmetal-desc0`, `libmetal-desc1`, `libmetal-ipi`, and + `libmetal-timer`. +- The host IPI UIO node carries a `libmetal,ipi-remote-mask` device-tree + property so the demo can discover the platform-specific interrupt bit at + runtime. - libmetal (and dependent libraries) installed on the host system, as well as the `metal_xlnx_extension` library when required by the platform glue. -- The project toolchain file defines the correct platform macro (for example, - `-DPLATFORM_ZYNQMP`) so `common.h` selects the matching peripheral map. - Remote firmware is already loaded and waiting for interrupts before the host demo starts. @@ -51,22 +52,31 @@ The static executable is emitted at ## Run 1. Start the remote firmware so it sits in the notification loop. -2. Launch the host binary (root/sudo may be required for IPI device access): +2. Confirm the expected logical UIO names are visible: + ```bash + cat /sys/class/uio/uio*/name + ``` +3. Launch the host binary (root/sudo may be required for IPI device access): ```bash ./irq_shmem_demo-static ``` -3. Observe the console output for packet progress and the final average + Override individual logical names when the platform uses different UIO + aliases: + ```bash + ./irq_shmem_demo-static --shm-dev my-data --desc0-dev my-desc0 \ + --desc1-dev my-desc1 --ipi-dev my-ipi --ttc-dev my-timer + ``` +4. Observe the console output for packet progress and the final average round-trip latency. ## [Shared Memory Layout](../../../demos/irq_shmem_demo/README.md#shared-memory-layout) Shared buffer map used by both sides of the demo. ## Troubleshooting -- **Hangs waiting for notification**: ensure the IPI mask configured in - `common.h` (or overridden via the optional demo config file) matches the - remote firmware and that the host process can write to the IPI device. +- **Hangs waiting for notification**: ensure the host IPI UIO node exposes + `libmetal,ipi-remote-mask`, that the host process can write to the IPI device, + and that the remote firmware uses the matching interrupt bit. - **Shared-memory access errors**: confirm the UIO entries expose the expected - descriptor/payload ranges (`0x09860000` base) with read/write permissions for - the demo user. + descriptor and payload regions with read/write permissions for the demo user. - **Mismatched payloads**: verify both sides agree on descriptor offsets and the `PKGS_TOTAL` value compiled into each binary. diff --git a/examples/libmetal/machine/host/amd_linux_userspace/common.h b/examples/libmetal/machine/host/amd_linux_userspace/common.h index a73f5ae8..7c440c44 100644 --- a/examples/libmetal/machine/host/amd_linux_userspace/common.h +++ b/examples/libmetal/machine/host/amd_linux_userspace/common.h @@ -7,6 +7,7 @@ #ifndef __COMMON_H__ #define __COMMON_H__ +#include #include #include @@ -17,7 +18,6 @@ #include #include "irq_shmem_demo.h" -#include "config.h" /* * Apply this snippet to the device tree in an overlay so that Linux userspace can diff --git a/examples/libmetal/machine/host/amd_linux_userspace/config.h.in b/examples/libmetal/machine/host/amd_linux_userspace/config.h.in deleted file mode 100644 index 12de8f05..00000000 --- a/examples/libmetal/machine/host/amd_linux_userspace/config.h.in +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -/* UIO device names */ -#cmakedefine SHM_DEV_NAME "@SHM_DEV_NAME@" -#cmakedefine SHM0_DESC_DEV_NAME "@SHM0_DESC_DEV_NAME@" -#cmakedefine SHM1_DESC_DEV_NAME "@SHM1_DESC_DEV_NAME@" - -/* Carveout layout */ -#cmakedefine SHM_IMAGE_BASE @SHM_IMAGE_BASE@ -#cmakedefine SHM_IMAGE_SIZE @SHM_IMAGE_SIZE@ -#cmakedefine SHM0_DESC_BASE @SHM0_DESC_BASE@ -#cmakedefine SHM0_DESC_SIZE @SHM0_DESC_SIZE@ -#cmakedefine SHM1_DESC_BASE @SHM1_DESC_BASE@ -#cmakedefine SHM1_DESC_SIZE @SHM1_DESC_SIZE@ -#cmakedefine SHM_PAYLOAD_BASE @SHM_PAYLOAD_BASE@ -#cmakedefine SHM_PAYLOAD_SIZE @SHM_PAYLOAD_SIZE@ -#cmakedefine SHM_PAYLOAD_TX_OFFSET @SHM_PAYLOAD_TX_OFFSET@ -#cmakedefine SHM_PAYLOAD_RX_OFFSET @SHM_PAYLOAD_RX_OFFSET@ - -/* Peripheral names/masks */ -#cmakedefine IPI_DEV_NAME "@IPI_DEV_NAME@" -#cmakedefine IPI_MASK @IPI_MASK@ -#cmakedefine TTC_DEV_NAME "@TTC_DEV_NAME@" - -#cmakedefine BUS_NAME "@BUS_NAME@" -#endif /* CONFIG_H */ diff --git a/examples/libmetal/machine/host/amd_linux_userspace/platform_init.c b/examples/libmetal/machine/host/amd_linux_userspace/platform_init.c index 80950587..db1185d9 100644 --- a/examples/libmetal/machine/host/amd_linux_userspace/platform_init.c +++ b/examples/libmetal/machine/host/amd_linux_userspace/platform_init.c @@ -4,15 +4,165 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include +#include +#include +#include #include +#include #include #include +#include #include #include #include "common.h" +#include "platform_init.h" static struct metal_device *rpu_to_apu_desc_dev, *apu_to_rpu_desc_dev; static struct metal_device *shm_dev, *ipi_dev, *ttc_dev; +#define APP_UIO_BUS_NAME "uio" +#define APP_UIO_CLASS_PATH "/sys/class/uio" + +static const struct app_platform_options app_default_platform_options = { + .shm_dev_name = "libmetal-data", + .desc0_dev_name = "libmetal-desc0", + .desc1_dev_name = "libmetal-desc1", + .ipi_dev_name = "libmetal-ipi", + .ttc_dev_name = "libmetal-timer", + .ipi_remote_mask_property = "libmetal,uio-ipi-bitmask", +}; + +static int app_read_first_line(const char *path, char *output, size_t output_len) +{ + FILE *fp; + char *newline; + + if (!path || !output || output_len < 2) + return -EINVAL; + + fp = fopen(path, "r"); + if (!fp) + return -errno; + + if (!fgets(output, output_len, fp)) { + int err = ferror(fp) ? -errno : -ENODATA; + + fclose(fp); + return err; + } + + fclose(fp); + + newline = strchr(output, '\n'); + if (newline) + *newline = '\0'; + + return 0; +} + +static int app_uio_find_path(const char *uio_name, char *uio_path, + size_t uio_path_len) +{ + DIR *dir; + struct dirent *entry; + char path[PATH_MAX]; + char value[PATH_MAX]; + bool found = false; + int ret = -ENODEV; + + if (!uio_name || !strlen(uio_name) || !uio_path || !uio_path_len) + return -EINVAL; + + dir = opendir(APP_UIO_CLASS_PATH); + if (!dir) + return -errno; + + while ((entry = readdir(dir)) != NULL) { + if (strncmp(entry->d_name, "uio", 3) != 0) + continue; + + ret = snprintf(path, sizeof(path), "%s/%s/name", + APP_UIO_CLASS_PATH, entry->d_name); + if (ret < 0 || ret >= (int)sizeof(path)) { + ret = -EOVERFLOW; + goto out; + } + + ret = app_read_first_line(path, value, sizeof(value)); + if (ret) + continue; + + if (strcmp(value, uio_name) != 0) + continue; + + if (found) { + ret = -EEXIST; + goto out; + } + found = true; + + ret = snprintf(uio_path, uio_path_len, "%s/%s", + APP_UIO_CLASS_PATH, entry->d_name); + if (ret < 0 || ret >= (int)uio_path_len) { + ret = -EOVERFLOW; + goto out; + } + } + + ret = found ? 0 : -ENODEV; + +out: + closedir(dir); + return ret; +} + +static int app_uio_read_dt_u32(const char *uio_name, const char *property, + uint32_t *value) +{ + unsigned char raw[4]; + char uio_path[PATH_MAX]; + char path[PATH_MAX]; + FILE *fp; + size_t len; + int ret; + + if (!uio_name || !property || !value) + return -EINVAL; + + ret = app_uio_find_path(uio_name, uio_path, sizeof(uio_path)); + if (ret) + return ret; + + ret = snprintf(path, sizeof(path), "%s/device/of_node/%s", + uio_path, property); + if (ret < 0 || ret >= (int)sizeof(path)) + return -EOVERFLOW; + + fp = fopen(path, "rb"); + if (!fp) + return -errno; + + len = fread(raw, 1, sizeof(raw), fp); + fclose(fp); + if (len != sizeof(raw)) + return -ENODATA; + + *value = ((uint32_t)raw[0] << 24) | + ((uint32_t)raw[1] << 16) | + ((uint32_t)raw[2] << 8) | + (uint32_t)raw[3]; + + return 0; +} + +void platform_get_default_options(struct app_platform_options *options) +{ + if (!options) + return; + + *options = app_default_platform_options; +} /** * @brief close_metal_devices() - close libmetal devices * This function closes all the libmetal devices which have @@ -22,23 +172,33 @@ static struct metal_device *shm_dev, *ipi_dev, *ttc_dev; static void close_metal_devices(void) { /* Close shared memory device */ - if (shm_dev) + if (shm_dev) { metal_device_close(shm_dev); + shm_dev = NULL; + } /* Close IPI device */ - if (ipi_dev) + if (ipi_dev) { metal_device_close(ipi_dev); + ipi_dev = NULL; + } /* Close TTC device */ - if (ttc_dev) + if (ttc_dev) { metal_device_close(ttc_dev); + ttc_dev = NULL; + } /* Close descriptor devices */ - if (rpu_to_apu_desc_dev) + if (rpu_to_apu_desc_dev) { metal_device_close(rpu_to_apu_desc_dev); + rpu_to_apu_desc_dev = NULL; + } - if (apu_to_rpu_desc_dev) + if (apu_to_rpu_desc_dev) { metal_device_close(apu_to_rpu_desc_dev); + apu_to_rpu_desc_dev = NULL; + } } /** @@ -47,43 +207,46 @@ static void close_metal_devices(void) * * @return 0 - succeeded, non-zero for failures. */ -int open_metal_devices(void) +static int open_metal_devices(const struct app_platform_options *options) { int ret; /* Open shared memory device */ - ret = metal_device_open(BUS_NAME, SHM_DEV_NAME, &shm_dev); + ret = metal_device_open(APP_UIO_BUS_NAME, options->shm_dev_name, &shm_dev); if (ret) { - metal_err("HOST: Failed to open device %s.\n", SHM_DEV_NAME); + metal_err("HOST: Failed to open device %s.\n", + options->shm_dev_name); goto out; } /* Open descriptor devices */ - ret = metal_device_open(BUS_NAME, SHM0_DESC_DEV_NAME, + ret = metal_device_open(APP_UIO_BUS_NAME, options->desc0_dev_name, &apu_to_rpu_desc_dev); if (ret) { - metal_err("Failed to open device %s.\n", SHM0_DESC_DEV_NAME); + metal_err("Failed to open device %s.\n", options->desc0_dev_name); goto out; } - ret = metal_device_open(BUS_NAME, SHM1_DESC_DEV_NAME, + ret = metal_device_open(APP_UIO_BUS_NAME, options->desc1_dev_name, &rpu_to_apu_desc_dev); if (ret) { - metal_err("Failed to open device %s.\n", SHM1_DESC_DEV_NAME); + metal_err("Failed to open device %s.\n", options->desc1_dev_name); goto out; } /* Open IPI device */ - ret = metal_device_open(BUS_NAME, IPI_DEV_NAME, &ipi_dev); + ret = metal_device_open(APP_UIO_BUS_NAME, options->ipi_dev_name, &ipi_dev); if (ret) { - metal_err("HOST: Failed to open device %s.\n", IPI_DEV_NAME); + metal_err("HOST: Failed to open device %s.\n", + options->ipi_dev_name); goto out; } /* Open TTC device */ - ret = metal_device_open(BUS_NAME, TTC_DEV_NAME, &ttc_dev); + ret = metal_device_open(APP_UIO_BUS_NAME, options->ttc_dev_name, &ttc_dev); if (ret) { - metal_err("HOST: Failed to open device %s.\n", TTC_DEV_NAME); + metal_err("HOST: Failed to open device %s.\n", + options->ttc_dev_name); goto out; } @@ -96,7 +259,7 @@ 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; + uint32_t ipi_mask = ch->ipi_mask; uint64_t val = 1; (void)vect_id; @@ -112,12 +275,17 @@ static int irq_isr(int vect_id, void *priv) return METAL_IRQ_NOT_HANDLED; } -int platform_init(struct channel_s *ch) +int platform_init(struct channel_s *ch, + const struct app_platform_options *options) { struct metal_init_params init_param = METAL_INIT_DEFAULTS; struct channel_machine_ctx_s *machine = channel_machine_ctx(ch); + uint32_t ipi_mask; int ret; + if (!options) + options = &app_default_platform_options; + ret = metal_init(&init_param); if (ret) { metal_err("HOST: Failed to initialize libmetal\n"); @@ -128,17 +296,18 @@ int platform_init(struct channel_s *ch) machine->remote_nkicked = (atomic_flag)ATOMIC_FLAG_INIT; atomic_flag_test_and_set(&machine->remote_nkicked); - ret = open_metal_devices(); + ret = open_metal_devices(options); if (ret) { metal_err("HOST: Failed to open devices\n"); - return ret; + goto out_close; } /* Get shared memory device IO region */ ch->shm_io = metal_device_io_region(shm_dev, 0); if (!ch->shm_io) { metal_err("HOST: Failed to map io region for %s.\n", shm_dev->name); - return -ENODEV; + ret = -ENODEV; + goto out_close; } /* Get descriptor IO Regions */ @@ -146,52 +315,81 @@ int platform_init(struct channel_s *ch) if (!ch->host_to_remote_desc_io) { metal_err("Failed to map io region for %s.\n", apu_to_rpu_desc_dev->name); - return -ENODEV; + ret = -ENODEV; + goto out_close; } ch->remote_to_host_desc_io = metal_device_io_region(rpu_to_apu_desc_dev, 0); if (!ch->remote_to_host_desc_io) { metal_err("Failed to map io region for %s.\n", rpu_to_apu_desc_dev->name); - return -ENODEV; + ret = -ENODEV; + goto out_close; } /* Get IPI device IO region */ ch->ipi_io = metal_device_io_region(ipi_dev, 0); if (!ch->ipi_io) { metal_err("HOST: Failed to map io region for %s.\n", ipi_dev->name); - return -ENODEV; + ret = -ENODEV; + goto out_close; } - /* Get the IPI IRQ from the opened IPI device */ - ch->ipi_mask = IPI_MASK; + ch->desc0_size = (uint32_t)metal_io_region_size(ch->host_to_remote_desc_io); + ch->desc1_size = (uint32_t)metal_io_region_size(ch->remote_to_host_desc_io); + ch->shm_payload_size = (uint32_t)metal_io_region_size(ch->shm_io); + if (!ch->desc0_size || !ch->desc1_size || !ch->shm_payload_size) { + metal_err("HOST: Invalid descriptor or payload region size.\n"); + ret = -EINVAL; + goto out_close; + } + + ret = app_uio_read_dt_u32(options->ipi_dev_name, + options->ipi_remote_mask_property, &ipi_mask); + if (ret) { + metal_err("HOST: Failed to read %s for %s.\n", + options->ipi_remote_mask_property, + options->ipi_dev_name); + goto out_close; + } + ch->ipi_mask = ipi_mask; /* Get TTC IO region */ ch->ttc_io = metal_device_io_region(ttc_dev, 0); if (!ch->ttc_io) { metal_err("HOST: Failed to map io region for %s.\n", ttc_dev->name); - return -ENODEV; + ret = -ENODEV; + goto out_close; } /* Get the IPI IRQ from the opened IPI device */ ch->irq_vector_id = (intptr_t)ipi_dev->irq_info; /* disable IPI interrupt */ - metal_io_write32(ch->ipi_io, IPI_IDR_OFFSET, IPI_MASK); + metal_io_write32(ch->ipi_io, IPI_IDR_OFFSET, ch->ipi_mask); /* clear old IPI interrupt */ - metal_io_write32(ch->ipi_io, IPI_ISR_OFFSET, IPI_MASK); + metal_io_write32(ch->ipi_io, IPI_ISR_OFFSET, ch->ipi_mask); /* Register IPI irq handler */ - metal_irq_register(ch->irq_vector_id, irq_isr, ch); + ret = metal_irq_register(ch->irq_vector_id, irq_isr, ch); + if (ret) { + metal_err("HOST: Failed to register IRQ handler.\n"); + goto out_close; + } metal_irq_enable(ch->irq_vector_id); /* Enable IPI interrupt */ - metal_io_write32(ch->ipi_io, IPI_IER_OFFSET, IPI_MASK); + metal_io_write32(ch->ipi_io, IPI_IER_OFFSET, ch->ipi_mask); return 0; + +out_close: + close_metal_devices(); + metal_finish(); + return ret; } void platform_cleanup(struct channel_s *ch) { /* disable IPI interrupt */ - metal_io_write32(ch->ipi_io, IPI_IDR_OFFSET, IPI_MASK); + metal_io_write32(ch->ipi_io, IPI_IDR_OFFSET, ch->ipi_mask); /* unregister IPI irq handler by setting the handler to 0 */ metal_irq_disable(ch->irq_vector_id); metal_irq_unregister(ch->irq_vector_id); diff --git a/examples/libmetal/machine/host/amd_linux_userspace/platform_init.h b/examples/libmetal/machine/host/amd_linux_userspace/platform_init.h index 3633f8ea..24a2e81e 100644 --- a/examples/libmetal/machine/host/amd_linux_userspace/platform_init.h +++ b/examples/libmetal/machine/host/amd_linux_userspace/platform_init.h @@ -7,9 +7,19 @@ #ifndef __PLATFORM_INIT_H__ #define __PLATFORM_INIT_H__ -#include "platform_init.h" +struct channel_s; +struct app_platform_options { + const char *shm_dev_name; + const char *desc0_dev_name; + const char *desc1_dev_name; + const char *ipi_dev_name; + const char *ttc_dev_name; + const char *ipi_remote_mask_property; +}; -int platform_init(struct channel_s *ch); +void platform_get_default_options(struct app_platform_options *options); +int platform_init(struct channel_s *ch, + const struct app_platform_options *options); void platform_cleanup(struct channel_s *ch); #endif /* __PLATFORM_INIT_H__ */