.../libmetal_echo_demo/src/ipi_latency_demod.c | 244 ++++++++++
.../libmetal_echo_demo/src/ipi_shmem_demod.c | 306 +++++++++++++
.../libmetal_echo_demo/src/shmem_atomic_demod.c | 174 +++++++
lib/sw_apps/libmetal_echo_demo/src/shmem_demod.c | 192 ++++++++
.../libmetal_echo_demo/src/shmem_latency_demod.c | 291 ++++++++++++
.../src/shmem_throughput_demod.c | 377 +++++++++++++++
lib/sw_apps/libmetal_echo_demo/src/sys_init.h | 6 +-
.../src/system/generic/libmetal_amp_demo.c | 503 ---------------------
.../src/system/generic/libmetal_amp_demod.c | 137 ++++++
.../src/system/generic/machine/zynqmp_r5/common.h | 197 ++++++++
.../system/generic/machine/zynqmp_r5/lscript.ld | 2 +-
.../system/generic/machine/zynqmp_r5/sys_init.c | 158 ++++---
12 files changed, 2023 insertions(+), 564 deletions(-)
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/ipi_latency_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/ipi_shmem_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/shmem_atomic_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/shmem_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/shmem_latency_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/shmem_throughput_demod.c
delete mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demo.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/common.h
diff --git a/lib/sw_apps/libmetal_echo_demo/src/ipi_latency_demod.c b/lib/sw_apps/libmetal_echo_demo/src/ipi_latency_demod.c
new file mode 100644
index 0000000..60663b0
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/ipi_latency_demod.c
@@ -0,0 +1,244 @@
+/*****************************************************************************
+ * ipi_latency_demod.c
+ * This is the remote side of the IPI latency measurement demo.
+ * This demo does the follwing steps:
+ *
+ * 1. Open the shared memory device.
+ * 1. Open the TTC timer device.
+ * 2. Open the IPI device.
+ * 3. Register IPI interrupt handler.
+ * 6. When it receives IPI interrupt, the IPI interrupt handler to stop
+ * the RPU to APU TTC counter.
+ * 7. Check the shared memory to see if demo is on. If the demo is on,
+ * reest the RPU to APU TTC counter and kick IPI to notify the remote.
+ * 8. If the shared memory indicates the demo is off, cleanup resource:
+ * disable IPI interrupt and deregister the IPI interrupt handler.
+ */
+
+#include <unistd.h>
+#include <metal/atomic.h>
+#include <metal/io.h>
+#include <metal/device.h>
+#include <metal/irq.h>
+#include "common.h"
+
+#define TTC_CNT_APU_TO_RPU 2 /* APU to RPU TTC counter ID */
+#define TTC_CNT_RPU_TO_APU 3 /* RPU to APU TTC counter ID */
+
+#define TTC_CLK_FREQ_HZ 100000000
+
+/* Shared memory offset */
+#define SHM_DEMO_CNTRL_OFFSET 0x0
+
+#define DEMO_STATUS_IDLE 0x0
+#define DEMO_STATUS_START 0x1 /* Status value to indicate demo start */
+
+#define ITERATIONS 1000
+
+struct channel_s {
+ 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 */
+ uint32_t ipi_mask; /* RPU IPI mask */
+ atomic_int remote_nkicked; /* 0 - kicked from remote */
+};
+
+/**
+ * @brief reset_timer() - function to reset TTC counter
+ * Set the RST bit in the Count Control Reg.
+ *
+ * @param[in] ttc_io - TTC timer i/o region
+ * @param[in] cnt_id - counter id
+ */
+static inline void reset_timer(struct metal_io_region *ttc_io,
+ unsigned long cnt_id)
+{
+ uint32_t val;
+ unsigned long offset = XTTCPS_CNT_CNTRL_OFFSET +
+ XTTCPS_CNT_OFFSET(cnt_id);
+
+ val = XTTCPS_CNT_CNTRL_RST_MASK;
+ metal_io_write32(ttc_io, offset, val);
+}
+
+/**
+ * @brief stop_timer() - function to stop TTC counter
+ * Set the disable bit in the Count Control Reg.
+ *
+ * @param[in] ttc_io - TTC timer i/o region
+ * @param[in] cnt_id - counter id
+ */
+static inline void stop_timer(struct metal_io_region *ttc_io,
+ unsigned long cnt_id)
+{
+ uint32_t val;
+ unsigned long offset = XTTCPS_CNT_CNTRL_OFFSET +
+ XTTCPS_CNT_OFFSET(cnt_id);
+
+ val = XTTCPS_CNT_CNTRL_DIS_MASK;
+ metal_io_write32(ttc_io, offset, val);
+}
+
+/**
+ * @brief ipi_irq_handler() - IPI interrupt handler
+ * It will clear the notified flag to mark it's got an IPI interrupt.
+ * It will stop the RPU->APU timer and will clear the notified
+ * flag to mark it's got an IPI interrupt
+ *
+ * @param[in] vect_id - IPI interrupt vector ID
+ * @param[in/out] priv - communication channel data for this application.
+ *
+ * @return - If the IPI interrupt is triggered by its remote, it returns
+ * METAL_IRQ_HANDLED. It returns METAL_IRQ_NOT_HANDLED, if it is
+ * not the interrupt it expected.
+ *
+ */
+static int ipi_irq_handler (int vect_id, void *priv)
+{
+ struct channel_s *ch = (struct channel_s *)priv;
+ uint32_t val;
+
+ (void)vect_id;
+
+ if (ch) {
+ val = metal_io_read32(ch->ipi_io, IPI_ISR_OFFSET);
+ if (val & ch->ipi_mask) {
+ /* stop RPU -> APU timer */
+ stop_timer(ch->ttc_io, TTC_CNT_APU_TO_RPU);
+ metal_io_write32(ch->ipi_io, IPI_ISR_OFFSET,
+ ch->ipi_mask);
+ atomic_flag_clear(&ch->remote_nkicked);
+ return METAL_IRQ_HANDLED;
+ }
+ }
+ return METAL_IRQ_NOT_HANDLED;
+}
+
+
+/**
+ * @brief measure_ipi_latencyd() - measure IPI latency with libmetal
+ * Loop until APU tells RPU to stop via shared memory.
+ * In loop, wait for interrupt (interrupt handler stops APU to
+ * RPU TTC counter). Then reset count on RPU to APU TTC counter
+ * and kick IPI to notify APU.
+ *
+ * @param[in] ch - channel information
+ * @return - 0 on success, error code if failure.
+ */
+static int measure_ipi_latencyd(struct channel_s *ch)
+{
+ LPRINTF("Starting IPI latency demo\r\n");
+ while(1) {
+ wait_for_notified(&ch->remote_nkicked);
+ if (metal_io_read32(ch->shm_io, SHM_DEMO_CNTRL_OFFSET) ==
+ DEMO_STATUS_START) {
+ /* Reset RPU to APU TTC counter */
+ reset_timer(ch->ttc_io, TTC_CNT_RPU_TO_APU);
+ /* Kick IPI to notify the remote */
+ metal_io_write32(ch->ipi_io, IPI_TRIG_OFFSET,
+ ch->ipi_mask);
+ } else {
+ break;
+ }
+ }
+ return 0;
+}
+
+int ipi_latency_demod()
+{
+ struct channel_s ch;
+ int ipi_irq;
+ int ret = 0;
+
+ print_demo("IPI latency");
+ memset(&ch, 0, sizeof(ch));
+
+
+ /* Get shared memory device IO region */
+ if (!shm_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ch.shm_io = metal_device_io_region(shm_dev, 0);
+ if (!ch.shm_io) {
+ LPERROR("Failed to map io region for %s.\n", shm_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get TTC IO region */
+ ch.ttc_io = metal_device_io_region(ttc_dev, 0);
+ if (!ch.ttc_io) {
+ LPERROR("Failed to map io region for %s.\n", ttc_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get IPI device IO region */
+ ch.ipi_io = metal_device_io_region(ipi_dev, 0);
+ if (!ch.ipi_io) {
+ LPERROR("Failed to map io region for %s.\n", ipi_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* disable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* clear old IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_ISR_OFFSET, IPI_MASK);
+
+ ch.ipi_mask = IPI_MASK;
+
+ /* Get the IPI IRQ from the opened IPI device */
+ ipi_irq = (intptr_t)ipi_dev->irq_info;
+
+ /* Register IPI irq handler */
+ metal_irq_register(ipi_irq, ipi_irq_handler, ipi_dev, &ch);
+ /* initialize remote_nkicked */
+ atomic_init(&ch.remote_nkicked, 1);
+ /* Enable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IER_OFFSET, IPI_MASK);
+
+ /* Run atomic operation demo */
+ ret = measure_ipi_latencyd(&ch);
+
+ /* disable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* deregister IPI irq handler by setting the handler to 0 */
+ metal_irq_register(ipi_irq, 0, ipi_dev, &ch);
+
+out:
+ return ret;
+
+}
+
diff --git a/lib/sw_apps/libmetal_echo_demo/src/ipi_shmem_demod.c b/lib/sw_apps/libmetal_echo_demo/src/ipi_shmem_demod.c
new file mode 100644
index 0000000..19dc0d6
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/ipi_shmem_demod.c
@@ -0,0 +1,306 @@
+/*****************************************************************************
+ * ipi_shmem_demo.c - shared memory with IPI demo
+ * This demo will:
+ *
+ * 1. Get the shared memory device I/O region.
+ * 2. Get the IPI device I/O region.
+ * 3. Register IPI interrupt handler.
+ * 4. Wait for remote IPI notification to receive message.
+ * 5. When message is received, check if it is shutdown message.
+ * 6. If it is shutdown message, do cleanup, otherwise, echo it back to the
+ * shared buffer.
+ * 7. Kick IPI to notify there is a message written to the shared memory
+ * if it echos back the message.
+ * 8. Repeat 4.
+ * 9. Clean up: disable IPI interrupt, deregister the IPI interrupt handler.
+ *
+ * Here is the Shared memory structure of this demo:
+ * |0x0 - 0x03 | number of APU to RPU buffers available to RPU |
+ * |0x04 - 0x07 | number of APU to RPU buffers consumed by RPU |
+ * |0x08 - 0x1FFC | address array for shared buffers from APU to RPU |
+ * |0x2000 - 0x2003 | number of RPU to APU buffers available to APU |
+ * |0x2004 - 0x2007 | number of RPU to APU buffers consumed by APU |
+ * |0x2008 - 0x3FFC | address array for shared buffers from RPU to APU |
+ * |0x04000 - 0x103FFC | APU to RPU buffers |
+ * |0x104000 - 0x203FFC | RPU to APU buffers |
+ */
+
+#include <sys/types.h>
+#include <metal/sys.h>
+#include <metal/io.h>
+#include <metal/alloc.h>
+#include <metal/device.h>
+#include <metal/irq.h>
+#include <errno.h>
+#include "common.h"
+
+#define BUF_SIZE_MAX 512
+#define SHUTDOWN "shutdown"
+
+/* Shared memory offsets */
+#define SHM_DESC_OFFSET_RX 0x0
+#define SHM_BUFF_OFFSET_RX 0x04000
+#define SHM_DESC_OFFSET_TX 0x02000
+#define SHM_BUFF_OFFSET_TX 0x104000
+
+/* Shared memory descriptors offset */
+#define SHM_DESC_AVAIL_OFFSET 0x00
+#define SHM_DESC_USED_OFFSET 0x04
+#define SHM_DESC_ADDR_ARRAY_OFFSET 0x08
+
+#define PKGS_TOTAL 1024
+
+#define BUF_SIZE_MAX 512
+#define SHUTDOWN "shutdown"
+
+struct msg_hdr_s {
+ uint32_t index;
+ uint32_t len;
+};
+
+static atomic_int remote_nkicked; /* is remote kicked, 0 - kicked,
+ 1 - not-kicked */
+
+static int ipi_irq_handler (int vect_id, void *priv)
+{
+ (void)vect_id;
+ struct metal_io_region *ipi_io = (struct metal_io_region *)priv;
+ uint32_t ipi_mask = IPI_MASK;
+ uint64_t val = 1;
+
+ if (!ipi_io)
+ return METAL_IRQ_NOT_HANDLED;
+ 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(&remote_nkicked);
+ return METAL_IRQ_HANDLED;
+ }
+ return METAL_IRQ_NOT_HANDLED;
+}
+
+/**
+ * @brief ipi_shmem_echod() - shared memory IPI demo
+ * This task will:
+ * * Wait for IPI interrupt from the remote
+ * * Once it received the interrupt, copy the content from
+ * the ping buffer to the pong buffer.
+ * * Update the shared memory descriptor for the new available
+ * pong buffer.
+ * * Trigger IPI to notifty the remote.
+ * @param[in] ipi_io - IPI metal i/o region
+ * @param[in] shm_io - shared memory metal i/o region
+ * @return - return 0 on success, otherwise return error number indicating
+ * type of error.
+ */
+static int ipi_shmem_echod(struct metal_io_region *ipi_io,
+ struct metal_io_region *shm_io)
+{
+ int ret = 0;
+ uint32_t rx_count, rx_avail;
+ unsigned long tx_avail_offset, rx_avail_offset;
+ unsigned long rx_used_offset;
+ unsigned long tx_addr_offset, rx_addr_offset;
+ unsigned long tx_data_offset, rx_data_offset;
+ void *lbuf = NULL;
+ struct msg_hdr_s *msg_hdr;
+ uint32_t ipi_mask = IPI_MASK;
+
+ lbuf = metal_allocate_memory(BUF_SIZE_MAX);
+ if (!lbuf) {
+ LPERROR("Failed to allocate local buffer for msg.\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ /* Clear shared memory */
+ metal_io_block_set(shm_io, 0, 0, metal_io_region_size(shm_io));
+
+ /* Set tx/rx buffer address offset */
+ tx_avail_offset = SHM_DESC_OFFSET_TX + SHM_DESC_AVAIL_OFFSET;
+ rx_avail_offset = SHM_DESC_OFFSET_RX + SHM_DESC_AVAIL_OFFSET;
+ rx_used_offset = SHM_DESC_OFFSET_RX + SHM_DESC_USED_OFFSET;
+ tx_addr_offset = SHM_DESC_OFFSET_TX + SHM_DESC_ADDR_ARRAY_OFFSET;
+ rx_addr_offset = SHM_DESC_OFFSET_RX + SHM_DESC_ADDR_ARRAY_OFFSET;
+ tx_data_offset = SHM_DESC_OFFSET_TX + SHM_BUFF_OFFSET_TX;
+ rx_data_offset = SHM_DESC_OFFSET_RX + SHM_BUFF_OFFSET_RX;
+
+ LPRINTF("Wait for echo test to start.\n");
+ rx_count = 0;
+ while (1) {
+ wait_for_notified(&remote_nkicked);
+ rx_avail = metal_io_read32(shm_io, rx_avail_offset);
+ while(rx_count != rx_avail) {
+ uint32_t buf_phy_addr_32;
+
+ /* Received ping from the other side */
+
+ /* Get the buffer location from the shared memory
+ * rx address array.
+ */
+ buf_phy_addr_32 = metal_io_read32(shm_io,
+ rx_addr_offset);
+ rx_data_offset = metal_io_phys_to_offset(shm_io,
+ (metal_phys_addr_t)buf_phy_addr_32);
+ if (rx_data_offset == METAL_BAD_OFFSET) {
+ LPERROR("[%u]failed to get rx offset: 0x%x, 0x%lx.\n",
+ rx_count, buf_phy_addr_32,
+ metal_io_phys(shm_io, rx_addr_offset));
+ ret = -EINVAL;
+ goto out;
+ }
+ rx_addr_offset += sizeof(buf_phy_addr_32);
+
+ /* Read message header from shared memory */
+ metal_io_block_read(shm_io, rx_data_offset, lbuf,
+ sizeof(struct msg_hdr_s));
+ msg_hdr = (struct msg_hdr_s *)lbuf;
+
+ /* Check if the message header is valid */
+ if (msg_hdr->len > (BUF_SIZE_MAX - sizeof(*msg_hdr))) {
+ LPERROR("wrong msg: length invalid: %u, %u.\n",
+ BUF_SIZE_MAX - sizeof(*msg_hdr),
+ msg_hdr->len);
+ ret = -EINVAL;
+ goto out;
+ }
+ rx_data_offset += sizeof(*msg_hdr);
+ /* Read message */
+ metal_io_block_read(shm_io,
+ rx_data_offset,
+ lbuf + sizeof(*msg_hdr), msg_hdr->len);
+ rx_data_offset += msg_hdr->len;
+ rx_count++;
+ /* increase rx used count to indicate it has consumed
+ * the received data */
+ metal_io_write32(shm_io, rx_used_offset, rx_count);
+
+ /* Check if the it is the shutdown message */
+ if (msg_hdr->len == strlen(SHUTDOWN) &&
+ !strncmp(SHUTDOWN,
+ (lbuf + sizeof(struct msg_hdr_s)),
+ strlen(SHUTDOWN))) {
+ LPRINTF("Received shutdown message\n");
+ goto out;
+ }
+ /* Copy the message back to the other end */
+ metal_io_block_write(shm_io, tx_data_offset, msg_hdr,
+ sizeof(struct msg_hdr_s) + msg_hdr->len);
+
+ /* Write to the address array to tell the other end
+ * the buffer address.
+ */
+ buf_phy_addr_32 = (uint32_t)metal_io_phys(shm_io,
+ tx_data_offset);
+ metal_io_write32(shm_io, tx_addr_offset,
+ buf_phy_addr_32);
+ tx_data_offset += sizeof(struct msg_hdr_s) +
+ msg_hdr->len;
+ tx_addr_offset += sizeof(uint32_t);
+
+ /* Increase number of available buffers */
+ metal_io_write32(shm_io, tx_avail_offset, rx_count);
+ /* Kick IPI to notify data is in shared buffer */
+ metal_io_write32(ipi_io, IPI_TRIG_OFFSET,
+ ipi_mask);
+ }
+
+ }
+
+out:
+ LPRINTF("IPI with shared memory demo finished with exit code: %i.\n",
+ ret);
+
+ if (lbuf)
+ metal_free_memory(lbuf);
+ return ret;
+}
+
+int ipi_shmem_demod()
+{
+ struct metal_io_region *ipi_io = NULL, *shm_io = NULL;
+ int ipi_irq;
+ int ret = 0;
+
+ print_demo("IPI and shared memory");
+
+ /* Get shared memory device IO region */
+ if (!shm_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ shm_io = metal_device_io_region(shm_dev, 0);
+ if (!shm_io) {
+ LPERROR("Failed to map io region for %s.\n", shm_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get IPI device IO region */
+ if (!ipi_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ipi_io = metal_device_io_region(ipi_dev, 0);
+ if (!ipi_io) {
+ LPERROR("Failed to map io region for %s.\n", ipi_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get the IPI IRQ from the opened IPI device */
+ ipi_irq = (intptr_t)ipi_dev->irq_info;
+
+ /* disable IPI interrupt */
+ metal_io_write32(ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* clear old IPI interrupt */
+ metal_io_write32(ipi_io, IPI_ISR_OFFSET, IPI_MASK);
+ /* Register IPI irq handler */
+ metal_irq_register(ipi_irq, ipi_irq_handler, ipi_dev, ipi_io);
+ /* initialize remote_nkicked */
+ atomic_init(&remote_nkicked, 1);
+ /* Enable IPI interrupt */
+ metal_io_write32(ipi_io, IPI_IER_OFFSET, IPI_MASK);
+
+ /* Run atomic operation demo */
+ ret = ipi_shmem_echod(ipi_io, shm_io);
+
+ /* disable IPI interrupt */
+ metal_io_write32(ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* deregister IPI irq handler by setting the handler to 0 */
+ metal_irq_register(ipi_irq, 0, ipi_dev, ipi_io);
+
+out:
+ return ret;
+
+}
+
diff --git a/lib/sw_apps/libmetal_echo_demo/src/shmem_atomic_demod.c b/lib/sw_apps/libmetal_echo_demo/src/shmem_atomic_demod.c
new file mode 100644
index 0000000..649c986
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/shmem_atomic_demod.c
@@ -0,0 +1,174 @@
+ /*****************************************************************************
+ * atomic_shmem_demod.c - Shared memory atomic operation demo
+ * This task will:
+ * 1. Get the shared memory device I/O region.
+ * 2. Get the IPI device I/O region.
+ * 3. Register IPI interrupt handler.
+ * 4. Wait for the APU to kick IPI to start the demo
+ * 5. Once notification is received, start atomic add by
+ * 1 for 5000 times over the shared memory
+ * 6. Trigger IPI to notify the remote it has finished calculation.
+ * 7. Clean up: Disable IPI interrupt, deregister the IPI interrupt handler.
+ */
+#include <metal/shmem.h>
+#include <metal/atomic.h>
+#include <metal/device.h>
+#include <metal/io.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include "common.h"
+#include "sys_init.h"
+
+#define ATOMIC_INT_OFFSET 0x0 /* shared memory offset for atomic operation */
+#define ITERATIONS 5000
+
+static atomic_int remote_nkicked; /* is remote kicked, 0 - kicked,
+ 1 - not-kicked */
+
+static int ipi_irq_handler (int vect_id, void *priv)
+{
+ (void)vect_id;
+ struct metal_io_region *ipi_io = (struct metal_io_region *)priv;
+ uint32_t ipi_mask = IPI_MASK;
+ uint64_t val = 1;
+
+ if (!ipi_io)
+ return METAL_IRQ_NOT_HANDLED;
+ 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(&remote_nkicked);
+ return METAL_IRQ_HANDLED;
+ }
+ return METAL_IRQ_NOT_HANDLED;
+}
+
+/**
+ * @brief atomic_add_shmemd() - Shared memory atomic operation demo
+ * This task will:
+ * * Wait for the remote to write to shared memory.
+ * * Once it receives the notification via polling, start atomic add by
+ * 1 for 5000 times to first 32 bits of memory in the shared memory
+ * which is pointed to by shm_io.
+ * * Write to shared mem to notify the remote once it finishes
+ * calculation.
+ *
+ * @param[in] ipi_io - IPI metal i/o region
+ * @param[in] shm_io - shared memory metal i/o region
+ * @return - If setup failed, return the corresponding error number. Otherwise
+ * return 0 on success.
+ */
+int atomic_add_shmemd(struct metal_io_region *ipi_io,
+ struct metal_io_region *shm_io)
+{
+ atomic_int *shm_int;
+ uint32_t ipi_mask = IPI_MASK;
+ int i;
+
+ LPRINTF("Starting atomic add on shared memory demo.\n");
+ shm_int = (atomic_int *)metal_io_virt(shm_io,
+ ATOMIC_INT_OFFSET);
+
+ /* Wait for notification from the remote to start the demo */
+ wait_for_notified(&remote_nkicked);
+
+ /* Do atomic add over the shared memory */
+ for (i = 0; i < ITERATIONS; i++)
+ atomic_fetch_add(shm_int, 1);
+
+ /* Write to IPI trigger register to notify the remote it has finished
+ * the atomic operation. */
+ metal_io_write32(ipi_io, IPI_TRIG_OFFSET, ipi_mask);
+
+ LPRINTF("Shared memory with atomics test finished\n");
+ return 0;
+}
+
+int atomic_shmem_demod()
+{
+ struct metal_io_region *ipi_io = NULL, *shm_io = NULL;
+ int ipi_irq;
+ int ret = 0;
+
+ print_demo("atomic operation over shared memory");
+
+ /* Get shared memory device IO region */
+ if (!shm_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ shm_io = metal_device_io_region(shm_dev, 0);
+ if (!shm_io) {
+ LPERROR("Failed to map io region for %s.\n", shm_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get IPI device IO region */
+ if (!ipi_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ipi_io = metal_device_io_region(ipi_dev, 0);
+ if (!ipi_io) {
+ LPERROR("Failed to map io region for %s.\n", ipi_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get the IPI IRQ from the opened IPI device */
+ ipi_irq = (intptr_t)ipi_dev->irq_info;
+
+ /* disable IPI interrupt */
+ metal_io_write32(ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* clear old IPI interrupt */
+ metal_io_write32(ipi_io, IPI_ISR_OFFSET, IPI_MASK);
+ /* Register IPI irq handler */
+ metal_irq_register(ipi_irq, ipi_irq_handler, ipi_dev, ipi_io);
+ /* initialize remote_nkicked */
+ atomic_init(&remote_nkicked, 1);
+ /* Enable IPI interrupt */
+ metal_io_write32(ipi_io, IPI_IER_OFFSET, IPI_MASK);
+
+ /* Run atomic operation demo */
+ ret = atomic_add_shmemd(ipi_io, shm_io);
+
+ /* disable IPI interrupt */
+ metal_io_write32(ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* deregister IPI irq handler by setting the handler to 0 */
+ metal_irq_register(ipi_irq, 0, ipi_dev, ipi_io);
+
+out:
+ return ret;
+
+}
+
diff --git a/lib/sw_apps/libmetal_echo_demo/src/shmem_demod.c b/lib/sw_apps/libmetal_echo_demo/src/shmem_demod.c
new file mode 100644
index 0000000..85c7578
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/shmem_demod.c
@@ -0,0 +1,192 @@
+ /*****************************************************************************
+ * shmem_demod.c
+ * This demo demonstrates the use of shared mem. between the APU and RPU.
+ * This demo does so via the following steps:
+ *
+ * 1. Get the shared memory device I/O region.
+ * 2. Clear the demo control value in shared memory.
+ * 3. Check the demo control value in the shared memory to wait for APU
+ * to start the demo.
+ * 4. Once the demo control value indicates the demo starts, it polls on
+ * RX available value to see if there is new RX message available.
+ * 5. If there is a new RX message available, it reads the message from
+ * the shared memory
+ * 6. It echos back the message to the shared memory
+ * 7. It increases the TX available value in the shared memory to notify
+ * the other end there is a message available to read.
+ * 8. Check if the demo control value and the RX available values to see
+ * if demo finishes and if there is new RX data available.
+ *
+ * Here is the Shared memory structure of this demo:
+ * |0 | 4Bytes | DEMO control status shows if demo starts or not |
+ * |0x04 | 4Bytes | number of APU to RPU buffers available to RPU |
+ * |0x08 | 4Bytes | number of APU to RPU buffers consumed by RPU |
+ * |0x0c | 4Bytes | number of RPU to APU buffers available to APU |
+ * |0x10 | 4Bytes | number of RPU to APU buffers consumed by APU |
+ * |0x14 | 1KBytes | APU to RPU buffer |
+ * ... ...
+ * |0x800 | 1KBytes | RPU to APU buffer |
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <metal/sys.h>
+#include <metal/device.h>
+#include <metal/io.h>
+#include <metal/alloc.h>
+#include "common.h"
+
+/* Shared memory offsets */
+#define SHM_DEMO_CNTRL_OFFSET 0x0
+#define SHM_RX_AVAIL_OFFSET 0x04
+#define SHM_RX_USED_OFFSET 0x08
+#define SHM_TX_AVAIL_OFFSET 0x0C
+#define SHM_TX_USED_OFFSET 0x10
+#define SHM_RX_BUFFER_OFFSET 0x14
+#define SHM_TX_BUFFER_OFFSET 0x800
+
+#define SHM_BUFFER_SIZE 0x400
+
+#define DEMO_STATUS_IDLE 0x0
+#define DEMO_STATUS_START 0x1 /* Status value to indicate demo start */
+
+struct msg_hdr_s {
+ uint32_t index;
+ uint32_t len;
+};
+
+/**
+ * @brief shmem_echod() - Show use of shared memory with libmetal.
+ * Wait for message from APU. Once received, read and echo it back.
+ *
+ * @param[in] shm_io - metal i/o region of the shared memory
+ * @return - return 0 on success, otherwise return error number indicating
+ * type of error
+ */
+static int shmem_echod(struct metal_io_region *shm_io)
+{
+ void *data = NULL;
+ struct msg_hdr_s *msg_hdr;
+ unsigned int rx_count = 0;
+ unsigned int len;
+ int ret = 0;
+
+ /* clear demo status value */
+ metal_io_write32(shm_io, SHM_DEMO_CNTRL_OFFSET, 0);
+
+ /* allocate memory for receiving data */
+ data = metal_allocate_memory(SHM_BUFFER_SIZE);
+ if (!data) {
+ LPERROR("Failed to allocate memory.\r\n");
+ return -1;
+ }
+
+ LPRINTF("Wait for shared memory demo to start.\r\n");
+ while (metal_io_read32(shm_io, SHM_DEMO_CNTRL_OFFSET) !=
+ DEMO_STATUS_START);
+
+ LPRINTF("Demo has started.\r\n");
+ /* wait for message is available */
+ while(metal_io_read32(shm_io, SHM_DEMO_CNTRL_OFFSET) ==
+ DEMO_STATUS_START) {
+ if (metal_io_read32(shm_io, SHM_RX_AVAIL_OFFSET)
+ == rx_count)
+ continue;
+ /* Message is available, read the message header */
+ ret = metal_io_block_read(shm_io, SHM_RX_BUFFER_OFFSET,
+ data, sizeof(struct msg_hdr_s));
+ if (ret < 0){
+ LPERROR("Unable to metal_io_block_read()\n");
+ return ret;
+ }
+ msg_hdr = (struct msg_hdr_s *)data;
+ /* Get the length of the data, if the data length is
+ * too large, truncate it. */
+ len = msg_hdr->len;
+ if (msg_hdr->len >
+ (SHM_BUFFER_SIZE - sizeof(*msg_hdr))) {
+ LPERROR("Input message is too long %u.\n",
+ msg_hdr->len);
+ len = SHM_BUFFER_SIZE - sizeof(*msg_hdr);
+ }
+ /* Read the message data */
+ ret = metal_io_block_read(shm_io,
+ SHM_RX_BUFFER_OFFSET + sizeof(*msg_hdr),
+ data + sizeof(*msg_hdr), len);
+
+ rx_count++;
+ ret = metal_io_block_write(shm_io,
+ SHM_TX_BUFFER_OFFSET,
+ (void*)data, sizeof(*msg_hdr) + len);
+ if (ret < 0){
+ LPERROR("Unable to metal_io_block_write()\n");
+ return ret;
+ }
+
+ /* increase TX available value to notify the other end
+ * there is data ready to read. */
+ metal_io_write32(shm_io, SHM_TX_AVAIL_OFFSET, rx_count);
+ }
+
+ metal_free_memory(data);
+ LPRINTF("Shared memory test finished\r\n");
+ return 0;
+}
+
+int shmem_demod()
+{
+ struct metal_io_region *io = NULL;
+ int ret = 0;
+
+ print_demo("shared memory");
+
+ /* Get shared memory device IO region */
+ if (!shm_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ io = metal_device_io_region(shm_dev, 0);
+ if (!io) {
+ LPERROR("Failed to map io region for %s.\n", shm_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = shmem_echod(io);
+
+out:
+ return ret;
+
+}
diff --git a/lib/sw_apps/libmetal_echo_demo/src/shmem_latency_demod.c b/lib/sw_apps/libmetal_echo_demo/src/shmem_latency_demod.c
new file mode 100644
index 0000000..acfce4c
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/shmem_latency_demod.c
@@ -0,0 +1,291 @@
+/*****************************************************************************
+ * shmem_latency_demod.c
+ * This is the remote side of the IPI latency measurement demo.
+ * This demo does the follwing steps:
+ *
+ * 1. Get the shared memory device libmetal I/O region.
+ * 1. Get the TTC timer device libemtal I/O region.
+ * 2. Get IPI device libmetal I/O region and the IPI interrupt vector.
+ * 3. Register IPI interrupt handler.
+ * 6. When it receives IPI interrupt, the IPI interrupt handler marked the
+ * remote has kicked.
+ * 7. Check the shared memory to see if demo is on. If the demo is on,
+ * copy data from the shared memory to local memory, stop the APU to RPU
+ * timer. Reset the RPU to APU TTC counter, copy data from local memory
+ * to shared memory, kick IPI to notify the remote.
+ * 8. If the shared memory indicates the demo is off, cleanup resource:
+ * disable IPI interrupt and deregister the IPI interrupt handler.
+ */
+
+#include <unistd.h>
+#include <metal/atomic.h>
+#include <metal/io.h>
+#include <metal/device.h>
+#include <metal/irq.h>
+#include "common.h"
+
+#define TTC_CNT_APU_TO_RPU 2 /* APU to RPU TTC counter ID */
+#define TTC_CNT_RPU_TO_APU 3 /* RPU to APU TTC counter ID */
+
+#define TTC_CLK_FREQ_HZ 100000000
+
+/* Shared memory offset */
+#define SHM_DEMO_CNTRL_OFFSET 0x0 /* Shared memory for the demo status */
+#define SHM_BUFF_OFFSET_RX 0x1000 /* Shared memory RX buffer start offset */
+#define SHM_BUFF_OFFSET_TX 0x2000 /* Shared memory TX buffer start offset */
+
+#define DEMO_STATUS_IDLE 0x0
+#define DEMO_STATUS_START 0x1 /* Status value to indicate demo start */
+
+#define ITERATIONS 1000
+
+#define BUF_SIZE_MAX 4096
+
+struct channel_s {
+ 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 */
+ uint32_t ipi_mask; /* RPU IPI mask */
+ atomic_int remote_nkicked; /* 0 - kicked from remote */
+};
+
+struct msg_hdr_s {
+ uint32_t index;
+ uint32_t len;
+};
+
+/**
+ * @brief reset_timer() - function to reset TTC counter
+ * Set the RST bit in the Count Control Reg.
+ *
+ * @param[in] ttc_io - TTC timer i/o region
+ * @param[in] cnt_id - counter id
+ */
+static inline void reset_timer(struct metal_io_region *ttc_io,
+ unsigned long cnt_id)
+{
+ uint32_t val;
+ unsigned long offset = XTTCPS_CNT_CNTRL_OFFSET +
+ XTTCPS_CNT_OFFSET(cnt_id);
+
+ val = XTTCPS_CNT_CNTRL_RST_MASK;
+ metal_io_write32(ttc_io, offset, val);
+}
+
+/**
+ * @brief stop_timer() - function to stop TTC counter
+ * Set the disable bit in the Count Control Reg.
+ *
+ * @param[in] ttc_io - TTC timer i/o region
+ * @param[in] cnt_id - counter id
+ */
+static inline void stop_timer(struct metal_io_region *ttc_io,
+ unsigned long cnt_id)
+{
+ uint32_t val;
+ unsigned long offset = XTTCPS_CNT_CNTRL_OFFSET +
+ XTTCPS_CNT_OFFSET(cnt_id);
+
+ val = XTTCPS_CNT_CNTRL_DIS_MASK;
+ metal_io_write32(ttc_io, offset, val);
+}
+
+/**
+ * @brief ipi_irq_handler() - IPI interrupt handler
+ * It will clear the notified flag to mark it's got an IPI interrupt.
+ * It will stop the RPU->APU timer and will clear the notified
+ * flag to mark it's got an IPI interrupt
+ *
+ * @param[in] vect_id - IPI interrupt vector ID
+ * @param[in/out] priv - communication channel data for this application.
+ *
+ * @return - If the IPI interrupt is triggered by its remote, it returns
+ * METAL_IRQ_HANDLED. It returns METAL_IRQ_NOT_HANDLED, if it is
+ * not the interrupt it expected.
+ *
+ */
+static int ipi_irq_handler (int vect_id, void *priv)
+{
+ struct channel_s *ch = (struct channel_s *)priv;
+ uint32_t val;
+
+ (void)vect_id;
+
+ if (ch) {
+ val = metal_io_read32(ch->ipi_io, IPI_ISR_OFFSET);
+ if (val & ch->ipi_mask) {
+ metal_io_write32(ch->ipi_io, IPI_ISR_OFFSET,
+ ch->ipi_mask);
+ atomic_flag_clear(&ch->remote_nkicked);
+ return METAL_IRQ_HANDLED;
+ }
+ }
+ return METAL_IRQ_NOT_HANDLED;
+}
+
+
+/**
+ * @brief measure_shmem_latencyd() - measure shmem latency with libmetal
+ * Loop until APU tells RPU to stop via shared memory.
+ * In loop, wait for interrupt (interrupt handler stops APU to
+ * RPU TTC counter). Then reset count on RPU to APU TTC counter
+ * and kick IPI to notify APU.
+ *
+ * @param[in] ch - channel information
+ * @return - 0 on success, error code if failure.
+ */
+static int measure_shmem_latencyd(struct channel_s *ch)
+{
+ void *lbuf = NULL;
+ struct msg_hdr_s *msg_hdr;
+ int ret = 0;
+
+ /* allocate memory for receiving data */
+ lbuf = metal_allocate_memory(BUF_SIZE_MAX);
+ if (!lbuf) {
+ LPERROR("Failed to allocate memory.\r\n");
+ return -1;
+ }
+
+ LPRINTF("Starting IPI latency demo\r\n");
+ while(1) {
+ wait_for_notified(&ch->remote_nkicked);
+ if (metal_io_read32(ch->shm_io, SHM_DEMO_CNTRL_OFFSET) ==
+ DEMO_STATUS_START) {
+ /* Read message header from shared memory */
+ metal_io_block_read(ch->shm_io, SHM_BUFF_OFFSET_RX,
+ lbuf, sizeof(struct msg_hdr_s));
+ msg_hdr = (struct msg_hdr_s *)lbuf;
+
+ /* Check if the message header is valid */
+ if (msg_hdr->len > (BUF_SIZE_MAX - sizeof(*msg_hdr))) {
+ LPERROR("wrong msg: length invalid: %u, %u.\n",
+ BUF_SIZE_MAX - sizeof(*msg_hdr),
+ msg_hdr->len);
+ ret = -EINVAL;
+ goto out;
+ }
+ /* Read message */
+ metal_io_block_read(ch->shm_io,
+ SHM_BUFF_OFFSET_RX + sizeof(*msg_hdr),
+ lbuf + sizeof(*msg_hdr), msg_hdr->len);
+ /* Stop APU to RPU TTC counter */
+ stop_timer(ch->ttc_io, TTC_CNT_APU_TO_RPU);
+
+ /* Reset RPU to APU TTC counter */
+ reset_timer(ch->ttc_io, TTC_CNT_RPU_TO_APU);
+ /* Copy the message back to the other end */
+ metal_io_block_write(ch->shm_io, SHM_BUFF_OFFSET_TX,
+ msg_hdr,
+ sizeof(*msg_hdr) + msg_hdr->len);
+
+ /* Kick IPI to notify the remote */
+ metal_io_write32(ch->ipi_io, IPI_TRIG_OFFSET,
+ ch->ipi_mask);
+ } else {
+ break;
+ }
+ }
+
+out:
+ metal_free_memory(lbuf);
+ return ret;
+}
+
+int shmem_latency_demod()
+{
+ struct channel_s ch;
+ int ipi_irq;
+ int ret = 0;
+
+ print_demo("shared memory latency");
+ memset(&ch, 0, sizeof(ch));
+
+ /* Get shared memory device IO region */
+ if (!shm_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ch.shm_io = metal_device_io_region(shm_dev, 0);
+ if (!ch.shm_io) {
+ LPERROR("Failed to map io region for %s.\n", shm_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get TTC IO region */
+ ch.ttc_io = metal_device_io_region(ttc_dev, 0);
+ if (!ch.ttc_io) {
+ LPERROR("Failed to map io region for %s.\n", ttc_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get IPI device IO region */
+ ch.ipi_io = metal_device_io_region(ipi_dev, 0);
+ if (!ch.ipi_io) {
+ LPERROR("Failed to map io region for %s.\n", ipi_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* disable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* clear old IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_ISR_OFFSET, IPI_MASK);
+
+ ch.ipi_mask = IPI_MASK;
+
+ /* Get the IPI IRQ from the opened IPI device */
+ ipi_irq = (intptr_t)ipi_dev->irq_info;
+
+ /* Register IPI irq handler */
+ metal_irq_register(ipi_irq, ipi_irq_handler, ipi_dev, &ch);
+ /* initialize remote_nkicked */
+ atomic_init(&ch.remote_nkicked, 1);
+ /* Enable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IER_OFFSET, IPI_MASK);
+
+ /* Run atomic operation demo */
+ ret = measure_shmem_latencyd(&ch);
+
+ /* disable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* deregister IPI irq handler by setting the handler to 0 */
+ metal_irq_register(ipi_irq, 0, ipi_dev, &ch);
+
+out:
+ return ret;
+
+}
+
diff --git a/lib/sw_apps/libmetal_echo_demo/src/shmem_throughput_demod.c b/lib/sw_apps/libmetal_echo_demo/src/shmem_throughput_demod.c
new file mode 100644
index 0000000..afe0fbd
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/shmem_throughput_demod.c
@@ -0,0 +1,377 @@
+/*****************************************************************************
+ * shmem_throughput_demo_task.c
+ * This is the remote side of the shared memory throughput demo.
+ * This demo does the following steps:
+ *
+ * 1. Get the shared memory device libmetal I/O region.
+ * 1. Get the TTC timer device libemtal I/O region.
+ * 2. Get IPI device libmetal I/O region and the IPI interrupt vector.
+ * 3. Register IPI interrupt handler.
+ * 6. Download throughput measurement:
+ * Start TTC RPU counter, wait for IPI kick, check if data is available,
+ * if yes, read as much data as possible from shared memory. It will
+ * iterates untill 1000 packages have been received, stop TTC RPU counter
+ * and kick IPI to notify the remote. Repeat for different package size.
+ * 7. Upload throughput measurement:
+ * Start TTC RPU counter, write data to shared memory and kick IPI to
+ * notify remote. It will iterate for 1000 times, stop TTC RPU counter.
+ * wait for APU IPI kick to know APU has finished receiving packages.
+ * Kick IPI to notify it TTC RPU conter value is ready to read.
+ * Repeat for different package size.
+ * 8. Cleanup resource:
+ * disable IPI interrupt and deregister the IPI interrupt handler.
+ *
+ * Here is the Shared memory structure of this demo:
+ * |0x0 - 0x03 | number of APU to RPU buffers available to RPU |
+ * |0x04 - 0x1FFC | address array for shared buffers from APU to RPU |
+ * |0x2000 - 0x2003 | number of RPU to APU buffers available to APU |
+ * |0x2004 - 0x3FFC | address array for shared buffers from RPU to APU |
+ * |0x04000 - 0x103FFC | APU to RPU buffers |
+ * |0x104000 - 0x203FFC | RPU to APU buffers |
+ */
+
+#include <unistd.h>
+#include <metal/atomic.h>
+#include <metal/io.h>
+#include <metal/device.h>
+#include <metal/irq.h>
+#include <metal/alloc.h>
+#include "common.h"
+
+#define TTC_CNT_APU_TO_RPU 2 /* APU to RPU TTC counter ID */
+#define TTC_CNT_RPU_TO_APU 3 /* RPU to APU TTC counter ID */
+
+/* Shared memory offsets */
+#define SHM_DESC_OFFSET_RX 0x0
+#define SHM_BUFF_OFFSET_RX 0x04000
+#define SHM_DESC_OFFSET_TX 0x02000
+#define SHM_BUFF_OFFSET_TX 0x104000
+
+/* Shared memory descriptors offset */
+#define SHM_DESC_AVAIL_OFFSET 0x00
+#define SHM_DESC_ADDR_ARRAY_OFFSET 0x04
+
+#define ITERATIONS 1000
+
+#define BUF_SIZE_MAX 4096
+#define PKG_SIZE_MAX 1024
+#define PKG_SIZE_MIN 16
+
+struct channel_s {
+ 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 */
+ uint32_t ipi_mask; /* RPU IPI mask */
+ atomic_int remote_nkicked; /* 0 - kicked from remote */
+};
+
+/**
+ * @brief reset_timer() - function to reset TTC counter
+ * Set the RST bit in the Count Control Reg.
+ *
+ * @param[in] ttc_io - TTC timer i/o region
+ * @param[in] cnt_id - counter id
+ */
+static inline void reset_timer(struct metal_io_region *ttc_io,
+ unsigned long cnt_id)
+{
+ uint32_t val;
+ unsigned long offset = XTTCPS_CNT_CNTRL_OFFSET +
+ XTTCPS_CNT_OFFSET(cnt_id);
+
+ val = XTTCPS_CNT_CNTRL_RST_MASK;
+ metal_io_write32(ttc_io, offset, val);
+}
+
+/**
+ * @brief stop_timer() - function to stop TTC counter
+ * Set the disable bit in the Count Control Reg.
+ *
+ * @param[in] ttc_io - TTC timer i/o region
+ * @param[in] cnt_id - counter id
+ */
+static inline void stop_timer(struct metal_io_region *ttc_io,
+ unsigned long cnt_id)
+{
+ uint32_t val;
+ unsigned long offset = XTTCPS_CNT_CNTRL_OFFSET +
+ XTTCPS_CNT_OFFSET(cnt_id);
+
+ val = XTTCPS_CNT_CNTRL_DIS_MASK;
+ metal_io_write32(ttc_io, offset, val);
+}
+
+/**
+ * @brief ipi_irq_handler() - IPI interrupt handler
+ * It will clear the notified flag to mark it's got an IPI interrupt.
+ * It will stop the RPU->APU timer and will clear the notified
+ * flag to mark it's got an IPI interrupt
+ *
+ * @param[in] vect_id - IPI interrupt vector ID
+ * @param[in/out] priv - communication channel data for this application.
+ *
+ * @return - If the IPI interrupt is triggered by its remote, it returns
+ * METAL_IRQ_HANDLED. It returns METAL_IRQ_NOT_HANDLED, if it is
+ * not the interrupt it expected.
+ *
+ */
+static int ipi_irq_handler (int vect_id, void *priv)
+{
+ struct channel_s *ch = (struct channel_s *)priv;
+ uint32_t val;
+
+ (void)vect_id;
+
+ if (ch) {
+ val = metal_io_read32(ch->ipi_io, IPI_ISR_OFFSET);
+ if (val & ch->ipi_mask) {
+ metal_io_write32(ch->ipi_io, IPI_ISR_OFFSET,
+ ch->ipi_mask);
+ atomic_flag_clear(&ch->remote_nkicked);
+ return METAL_IRQ_HANDLED;
+ }
+ }
+ return METAL_IRQ_NOT_HANDLED;
+}
+
+/**
+ * @brief measure_shmem_throughputd() - measure shmem throughpput with libmetal
+ * - Download throughput measurement:
+ * Start TTC RPU counter, wait for IPI kick, check if data is
+ * available, if yes, read as much data as possible from shared
+ * memory. It will iterates untill 1000 packages have been received,
+ * stop TTC RPU counter and kick IPI to notify the remote. Repeat
+ * for different package size.
+ * - Upload throughput measurement:
+ * Start TTC RPU counter, write data to shared memory and kick IPI
+ * to notify remote. It will iterate for 1000 times, stop TTC RPU
+ * counter.Wait for APU IPI kick to know APU has received all the
+ * packages. Kick IPI to notify it TTC RPU conter value is ready to
+ * read. Repeat for different package size.
+ *
+ * @param[in] ch - channel information
+ * @return - 0 on success, error code if failure.
+ */
+static int measure_shmem_throughputd(struct channel_s *ch)
+{
+ void *lbuf = NULL;
+ int ret = 0;
+ size_t s;
+ uint32_t rx_count, rx_avail, tx_count;
+ 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 buf_phy_addr_32;
+
+ /* allocate memory for receiving data */
+ lbuf = metal_allocate_memory(BUF_SIZE_MAX);
+ if (!lbuf) {
+ LPERROR("Failed to allocate memory.\r\n");
+ return -1;
+ }
+ memset(lbuf, 0xA, BUF_SIZE_MAX);
+
+ /* Clear shared memory */
+ metal_io_block_set(ch->shm_io, 0, 0, metal_io_region_size(ch->shm_io));
+
+ LPRINTF("Starting shared mem throughput demo\n");
+
+ /* for each data size, measure block receive throughput */
+ for (s = PKG_SIZE_MIN; s <= PKG_SIZE_MAX; s <<= 1) {
+ rx_count = 0;
+ /* Set rx buffer address offset */
+ rx_avail_offset = SHM_DESC_OFFSET_RX + SHM_DESC_AVAIL_OFFSET;
+ rx_addr_offset = SHM_DESC_OFFSET_RX +
+ SHM_DESC_ADDR_ARRAY_OFFSET;
+ rx_data_offset = SHM_DESC_OFFSET_RX + SHM_BUFF_OFFSET_RX;
+ wait_for_notified(&ch->remote_nkicked);
+ /* Data has arrived, seasure start. Reset RPU TTC counter */
+ reset_timer(ch->ttc_io, TTC_CNT_RPU_TO_APU);
+ while (1) {
+ rx_avail = metal_io_read32(ch->shm_io, rx_avail_offset);
+
+ while(rx_count != rx_avail) {
+ /* Get the buffer location from the shared
+ * memory rx address array.
+ */
+ buf_phy_addr_32 = metal_io_read32(ch->shm_io,
+ rx_addr_offset);
+ rx_data_offset = metal_io_phys_to_offset(
+ ch->shm_io,
+ (metal_phys_addr_t)buf_phy_addr_32);
+ if (rx_data_offset == METAL_BAD_OFFSET) {
+ LPERROR(
+ "[%u]failed to get rx offset: 0x%x, 0x%lx.\n",
+ rx_count, buf_phy_addr_32,
+ metal_io_phys(ch->shm_io,
+ rx_addr_offset));
+ ret = -EINVAL;
+ goto out;
+ }
+ rx_addr_offset += sizeof(buf_phy_addr_32);
+ /* Read data from shared memory */
+ metal_io_block_read(ch->shm_io, rx_data_offset,
+ lbuf, s);
+ rx_count++;
+ }
+ if (rx_count < ITERATIONS)
+ /* Need to wait for more data */
+ wait_for_notified(&ch->remote_nkicked);
+ else
+ break;
+ }
+ /* Stop RPU TTC counter */
+ stop_timer(ch->ttc_io, TTC_CNT_RPU_TO_APU);
+ /* Clear remote kicked flag -- 0 is kicked */
+ atomic_init(&ch->remote_nkicked, 1);
+ /* Kick IPI to notify RPU TTC counter value is ready */
+ metal_io_write32(ch->ipi_io, IPI_TRIG_OFFSET, ch->ipi_mask);
+ }
+
+ /* for each data size, measure send throughput */
+ for (s = PKG_SIZE_MIN; s <= PKG_SIZE_MAX; s <<= 1) {
+ tx_count = 0;
+ /* Set tx buffer address offset */
+ tx_avail_offset = SHM_DESC_OFFSET_TX + SHM_DESC_AVAIL_OFFSET;
+ tx_addr_offset = SHM_DESC_OFFSET_TX +
+ SHM_DESC_ADDR_ARRAY_OFFSET;
+ tx_data_offset = SHM_DESC_OFFSET_TX + SHM_BUFF_OFFSET_TX;
+ /* Wait for APU to signal it is ready for the measurement */
+ wait_for_notified(&ch->remote_nkicked);
+ /* Data has arrived, seasure start. Reset RPU TTC counter */
+ reset_timer(ch->ttc_io, TTC_CNT_RPU_TO_APU);
+ while (tx_count < ITERATIONS) {
+ /* Write data to the shared memory*/
+ metal_io_block_write(ch->shm_io, tx_data_offset,
+ lbuf, s);
+
+ /* Write to the address array to tell the other end
+ * the buffer address.
+ */
+ buf_phy_addr_32 = (uint32_t)metal_io_phys(ch->shm_io,
+ tx_data_offset);
+ metal_io_write32(ch->shm_io, tx_addr_offset,
+ buf_phy_addr_32);
+ tx_data_offset += s;
+ tx_addr_offset += sizeof(buf_phy_addr_32);
+
+ /* Increase number of available buffers */
+ tx_count++;
+ metal_io_write32(ch->shm_io, tx_avail_offset, tx_count);
+ /* Kick IPI to notify remote data is ready in the
+ * shared memory */
+ metal_io_write32(ch->ipi_io, IPI_TRIG_OFFSET,
+ ch->ipi_mask);
+ }
+ /* Stop RPU TTC counter */
+ stop_timer(ch->ttc_io, TTC_CNT_RPU_TO_APU);
+ /* Wait for IPI kick to know when the remote is ready
+ * to read the TTC counter value */
+ wait_for_notified(&ch->remote_nkicked);
+ /* Kick IPI to notify RPU TTC counter value is ready */
+ metal_io_write32(ch->ipi_io, IPI_TRIG_OFFSET, ch->ipi_mask);
+ }
+
+out:
+ if (lbuf)
+ metal_free_memory(lbuf);
+ return ret;
+}
+
+int shmem_throughput_demod()
+{
+ struct channel_s ch;
+ int ipi_irq;
+ int ret = 0;
+
+ print_demo("shared memory throughput");
+ memset(&ch, 0, sizeof(ch));
+
+ /* Get shared memory device IO region */
+ if (!shm_dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+ ch.shm_io = metal_device_io_region(shm_dev, 0);
+ if (!ch.shm_io) {
+ LPERROR("Failed to map io region for %s.\n", shm_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get TTC IO region */
+ ch.ttc_io = metal_device_io_region(ttc_dev, 0);
+ if (!ch.ttc_io) {
+ LPERROR("Failed to map io region for %s.\n", ttc_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Get IPI device IO region */
+ ch.ipi_io = metal_device_io_region(ipi_dev, 0);
+ if (!ch.ipi_io) {
+ LPERROR("Failed to map io region for %s.\n", ipi_dev->name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* disable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* clear old IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_ISR_OFFSET, IPI_MASK);
+
+ ch.ipi_mask = IPI_MASK;
+
+ /* Get the IPI IRQ from the opened IPI device */
+ ipi_irq = (intptr_t)ipi_dev->irq_info;
+
+ /* Register IPI irq handler */
+ metal_irq_register(ipi_irq, ipi_irq_handler, ipi_dev, &ch);
+ /* initialize remote_nkicked */
+ atomic_init(&ch.remote_nkicked, 1);
+ /* Enable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IER_OFFSET, IPI_MASK);
+
+ /* Run atomic operation demo */
+ ret = measure_shmem_throughputd(&ch);
+
+ /* disable IPI interrupt */
+ metal_io_write32(ch.ipi_io, IPI_IDR_OFFSET, IPI_MASK);
+ /* deregister IPI irq handler by setting the handler to 0 */
+ metal_irq_register(ipi_irq, 0, ipi_dev, &ch);
+
+out:
+ return ret;
+
+}
+
diff --git a/lib/sw_apps/libmetal_echo_demo/src/sys_init.h b/lib/sw_apps/libmetal_echo_demo/src/sys_init.h
index e8c6500..93e771e 100644
--- a/lib/sw_apps/libmetal_echo_demo/src/sys_init.h
+++ b/lib/sw_apps/libmetal_echo_demo/src/sys_init.h
@@ -30,12 +30,12 @@
*
******************************************************************************/
-#ifndef __PLATFORM_H_
-#define __PLATFORM_H_
+#ifndef __SYS_INIT_H__
+#define __SYS_INIT_H__
#include "platform_config.h"
int sys_init();
void sys_cleanup();
-#endif
+#endif /* __SYS_INIT_H__ */
diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demo.c b/lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demo.c
deleted file mode 100644
index 465a22e..0000000
--- a/lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demo.c
+++ /dev/null
@@ -1,503 +0,0 @@
- * This app does the following:
- * 1. Initialize the platform hardware such as UART, GIC.
- * 2. Connect the IPI interrupt.
- * 3. Register IPI device, shared memory descriptor device and shared memory
- * device with libmetal in the intialization.
- * 4. In the main application it does the following,
- * * open the registered libmetal devices: IPI device, shared memory
- * descriptor device and shared memory device.
- * * Map the shared memory descriptor as non-cached memory.
- * * Map the shared memory as non-cached memory. If you do not map the
- * shared memory as non-cached memory, make sure you flush the cache,
- * before you notify the remote.
- * 7. Register the IPI interrupt handler with libmetal.
- * 8. Run the atomic demo task ipi_task_shm_atomicd():
- * * Wait for the IPI interrupt from the remote.
- * * Once it receives the interrupt, it does atomic add by 1 to the
- * first 32bit of the shared memory descriptor location by 1000 times.
- * * It will then notify the remote after the calucation.
- * * As the remote side also does 1000 times add after it has notified
- * this end. The remote side will check if the result is 2000, if not,
- * it will error.
- * 9. Run the shared memory echo demo task ipi_task_echod()
- * * Wait for the IPI interrupt from the other end.
- * * If an IPI interrupt is received, copy the message to the current
- * available RPU to APU buffer, increase the available buffer indicator,
- * and trigger IPI to notify the remote.
- * * If "shutdown" message is received, cleanup the libmetal source.
- */
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-/**
- * @brief ipi_irq_isr() - IPI interrupt handler
- * It will clear the notified flag to mark it's got an IPI interrupt.
- *
- * @param[in] vect_id - IPI interrupt vector ID
- * @param[in/out] priv - communication channel data for this application.
- *
- * @return - If the IPI interrupt is triggered by its remote, it returns
- * METAL_IRQ_HANDLED. It returns METAL_IRQ_NOT_HANDLED, if it is
- * not the interupt it expected.
- unsigned int flags;
- int i;
-
- shm_int = (atomic_int *)metal_io_virt(ch->shm0_desc_io, 0);
-
- LPRINTF("Wait for atomic test to start.\n");
- while (1) {
- do {
- flags = metal_irq_save_disable();
- if (!atomic_flag_test_and_set(&ch->notified)) {
- metal_irq_restore_enable(flags);
- break;
- }
- wait_for_interrupt();
- metal_irq_restore_enable(flags);
- } while(1);
- for (i = 0; i < 1000; i++)
- atomic_fetch_add(shm_int, 1);
- /* memory barrier */
- atomic_thread_fence(memory_order_acq_rel);
-
- /* Send the message */
- LPRINTF("SENDING message...\n");
- metal_io_write32(ch->ipi_io, IPI_TRIG_OFFSET, ch->ipi_mask);
- break;
- }
-
- return NULL;
-}
-
-/**
- * @brief ipi_task_echod() - shared memory ping-pong demo
- * This task will:
- * * Wait for IPI interrupt from the remote
- * * Once it received the interrupt, copy the content from
- * the ping buffer to the pong buffer.
- * * Update the shared memory descriptor for the new available
- * pong buffer.
- * * Trigger IPI to notifty the remote.
- *
- * @param[in] arg - channel information
- */
-static void *ipi_task_echod(void *arg)
-{
- struct channel_s *ch = (struct channel_s *)arg;
- struct shm_mg_s *shm0_mg, *shm1_mg;
- shm_addr_t *shm0_addr_array, *shm1_addr_array;
- struct msg_hdr_s *msg_hdr;
- unsigned int flags;
- void *d0, *d1, *lbuf;
- metal_phys_addr_t d0_pa;
- int len;
-
- shm0_mg = (struct shm_mg_s *)metal_io_virt(ch->shm0_desc_io, 0);
- shm1_mg = (struct shm_mg_s *)metal_io_virt(ch->shm1_desc_io, 0);
- shm0_addr_array = (void *)shm0_mg + sizeof(struct shm_mg_s);
- shm1_addr_array = (void *)shm1_mg + sizeof(struct shm_mg_s);
- d1 = metal_io_virt(ch->shm_io, ch->d1_start_offset);
- lbuf = malloc(BUF_SIZE_MAX);
- if (!lbuf) {
- LPRINTF("ERROR: Failed to allocate local buffer for msg.\n");
- return NULL;
- }
-
- LPRINTF("Wait for echo test to start.\n");
- while (1) {
- do {
- flags = metal_irq_save_disable();
- if (!atomic_flag_test_and_set(&ch->notified)) {
- metal_irq_restore_enable(flags);
- break;
- }
- wait_for_interrupt();
- metal_irq_restore_enable(flags);
- } while(1);
- atomic_thread_fence(memory_order_acq_rel);
- while(shm0_mg->used != shm0_mg->avails) {
- d0_pa = (metal_phys_addr_t)
- shm0_addr_array[shm0_mg->used];
- d0 = metal_io_phys_to_virt(ch->shm_io, d0_pa);
- if (!d0) {
- LPRINTF("ERROR: failed to get rx addr:0x%lx.\n",
- d0_pa);
- goto out;
- }
- /* Copy msg header from shared buf to local mem */
- len = metal_io_block_read(ch->shm_io,
- metal_io_virt_to_offset(ch->shm_io, d0),
- lbuf, sizeof(struct msg_hdr_s));
- if (len < (int)sizeof(struct msg_hdr_s)) {
- LPRINTF("ERROR: Failed to get msg header.\n");
- goto out;
- }
- msg_hdr = lbuf;
- if (msg_hdr->len < 0) {
- LPRINTF("ERROR: wrong msg length: %d.\n",
- * The cleanup funciton will disable the IPI interrupt
- * close the metal devices and clean the system.
- */
-void cleanup(void)
-{
- int irq;
- /* Disable IPI interrupt */
- if (ch0.ipi_io) {
- metal_io_write32(ch0.ipi_io, IPI_IDR_OFFSET, ch0.ipi_mask);
- /* Get interrupt ID from IPI metal device */
- irq = (intptr_t)ch0.ipi_dev->irq_info;
- metal_irq_register(irq, 0, ch0.ipi_dev, &ch0);
- }
- if (ch0.ipi_dev)
- metal_device_close(ch0.ipi_dev);
- if (ch0.shm0_desc_dev)
- metal_device_close(ch0.shm0_desc_dev);
- if (ch0.shm1_desc_dev)
- metal_device_close(ch0.shm1_desc_dev);
- if (ch0.shm_dev)
- metal_device_close(ch0.shm_dev);
- sys_cleanup();
-}
-
-/**
- * @brief main function of the demo application.
- * Here are the steps for the main function:
- * * call sys_init() function for system related initialization and
- * metal device registration.
- * * Open the IPI, shared memory descriptors, and shared memory
- * devices, and stored the I/O region.
- * * Register the IPI interrupt handler.
- * * Enable the IPI interrupt.
- * * Run the atomic across shared memory task.
- * * Run the echo demo with shared memory task.
- * * cleanup the libmetal resource before return.
- * @return 0 - succeeded, non-zero for failures.
- */
-int main(void)
-{
- struct metal_device *device;
- struct metal_io_region *io;
- int irq;
- uint32_t val;
- int ret = 0;
-
- if (sys_init()) {
- LPRINTF("ERROR: Failed to initialize system\n");
- return -1;
- }
- memset(&ch0, 0, sizeof(ch0));
-
- atomic_store(&ch0.notified, 1);
-
- /* Open IPI device */
- ret = metal_device_open(BUS_NAME, IPI_DEV_NAME, &device);
- if (ret) {
- LPRINTF("ERROR: Failed to open device %s.\n", IPI_DEV_NAME);
- goto out;
- }
-
- /* Map IPI device IO region */
- io = metal_device_io_region(device, 0);
- if (!io) {
- LPRINTF("ERROR: Failed to map io regio for %s.\n",
- device->name);
- metal_device_close(device);
- ret = -ENODEV;
- goto out;
- }
-
- /* Store the IPI device and I/O region */
- ch0.ipi_dev = device;
- ch0.ipi_io = io;
-
- /* Open shared memory0 descriptor device */
- ret = metal_device_open(BUS_NAME, SHM0_DESC_DEV_NAME, &device);
- if (ret) {
- LPRINTF("ERROR: Failed to open device %s.\n",
- SHM0_DESC_DEV_NAME);
- goto out;
- }
-
- /* Map shared memory0 descriptor device IO region */
- io = metal_device_io_region(device, 0);
- if (!io) {
- LPRINTF("ERROR: Failed to map io regio for %s.\n",
- device->name);
- metal_device_close(device);
- ret = -ENODEV;
- goto out;
- }
-
- /* Store the shared memory0 descriptor device and I/O region */
- ch0.shm0_desc_dev = device;
- ch0.shm0_desc_io = io;
-
- /* Open shared memory1 descriptor device */
- ret = metal_device_open(BUS_NAME, SHM1_DESC_DEV_NAME, &device);
- if (ret) {
- LPRINTF("ERROR: Failed to open device %s.\n",
- SHM1_DESC_DEV_NAME);
- goto out;
- }
-
- /* Map shared memory1 descriptor device IO region */
- io = metal_device_io_region(device, 0);
- if (!io) {
- LPRINTF("ERROR: Failed to map io regio for %s.\n",
- device->name);
- metal_device_close(device);
- ret = -ENODEV;
- goto out;
- }
- /* Store the shared memory1 descriptor device and I/O region */
- ch0.shm1_desc_dev = device;
- ch0.shm1_desc_io = io;
-
- /* Open shared memory device */
- ret = metal_device_open(BUS_NAME, SHM_DEV_NAME, &device);
- if (ret) {
- LPRINTF("ERROR: Failed to open device %s.\n", SHM_DEV_NAME);
- goto out;
- }
-
- /* Map shared memory device IO region */
- io = metal_device_io_region(device, 0);
- if (!io) {
- LPRINTF("ERROR: Failed to map io regio for %s.\n",
- device->name);
- metal_device_close(device);
- ret = -ENODEV;
- goto out;
- }
-
- /* Store the shared memory device and I/O region */
- ch0.shm_dev = device;
- ch0.shm_io = io;
- ch0.d1_start_offset = D1_SHM_OFFSET;
-
- /* Get interrupt ID from IPI metal device */
- irq = (intptr_t)ch0.ipi_dev->irq_info;
- if (irq < 0) {
- LPRINTF("ERROR: Failed to request interrupt for %s.\n",
- device->name);
- ret = -EINVAL;
- goto out;
- }
-
- ch0.ipi_mask = IPI_MASK;
-
- LPRINTF("Try to register IPI interrupt.\n");
- ret = metal_irq_register(irq, ipi_irq_isr, ch0.ipi_dev, &ch0);
- LPRINTF("registered IPI interrupt.\n");
- if (ret)
- goto out;
-
- /* Enable interrupt */
- metal_io_write32(ch0.ipi_io, IPI_IER_OFFSET, ch0.ipi_mask);
- val = metal_io_read32(ch0.ipi_io, IPI_IMR_OFFSET);
- if (val & ch0.ipi_mask) {
- LPRINTF("ERROR: Failed to enable IPI interrupt.\n");
- ret = -1;
- goto out;
- }
- LPRINTF("enabled IPI interrupt.\n");
- ret = run_comm_task(ipi_task_shm_atomicd, &ch0);
- if (ret) {
- LPRINTF("ERROR: Failed to run shared memory atomic task.\n");
- goto out;
- }
- ret = run_comm_task(ipi_task_echod, &ch0);
- if (ret)
- LPRINTF("ERROR: Failed to run IPI communication task.\n");
-
-out:
- cleanup();
-
- return ret;
-}
diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demod.c b/lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demod.c
new file mode 100644
index 0000000..f841ef8
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/generic/libmetal_amp_demod.c
@@ -0,0 +1,137 @@
+ * This app does the following:
+ * 1. Initialize the platform hardware such as UART, GIC.
+ * 2. Connect the IPI interrupt.
+ * 3. Register IPI device, shared memory descriptor device and shared memory
+ * device with libmetal in the intialization.
+ * 4. In the main application it does the following,
+ * * open the registered libmetal devices: IPI device, shared memory
+ * descriptor device and shared memory device.
+ * * Map the shared memory descriptor as non-cached memory.
+ * * Map the shared memory as non-cached memory. If you do not map the
+ * shared memory as non-cached memory, make sure you flush the cache,
+ * before you notify the remote.
+ * 7. Register the IPI interrupt handler with libmetal.
+ * 8. Run the atomic demo task ipi_task_shm_atomicd():
+ * * Wait for the IPI interrupt from the remote.
+ * * Once it receives the interrupt, it does atomic add by 1 to the
+ * first 32bit of the shared memory descriptor location by 1000 times.
+ * * It will then notify the remote after the calucation.
+ * * As the remote side also does 1000 times add after it has notified
+ * this end. The remote side will check if the result is 2000, if not,
+ * it will error.
+ * 9. Run the shared memory echo demo task ipi_task_echod()
+ * * Wait for the IPI interrupt from the other end.
+ * * If an IPI interrupt is received, copy the message to the current
+ * available RPU to APU buffer, increase the available buffer indicator,
+ * and trigger IPI to notify the remote.
+ * * If "shutdown" message is received, cleanup the libmetal source.
+ */
+
+#include <unistd.h>
+#include <metal/atomic.h>
+#include <metal/io.h>
+#include <metal/device.h>
+#include <metal/irq.h>
+#include "common.h"
+
+/**
+ * @brief main function of the demo application.
+ * Here are the steps for the main function:
+ * * Setup libmetal resources
+ * * Run the IPI with shared memory demo.
+ * * Run the shared memory demo.
+ * * Run the atomic across shared memory demo.
+ * * Run the ipi latency demo.
+ * * Run the shared memory latency demo.
+ * * Run the shared memory throughput demo.
+ * * Cleanup libmetal resources
+ * Report if any of the above demos failed.
+ * @return 0 - succeeded, non-zero for failures.
+ */
+int main(void)
+{
+ int ret;
+
+ ret = sys_init();
+
+ if (ret) {
+ LPERROR("Failed to initialize system.\n");
+ return ret;
+ }
+
+ ret = shmem_demod();
+ if (ret){
+ LPERROR("shared memory demo failed.\n");
+ return ret;
+ }
+
+ ret = atomic_shmem_demod();
+ if (ret){
+ LPERROR("shared memory atomic demo failed.\n");
+ return ret;
+ }
+
+ ret = ipi_shmem_demod();
+ if (ret){
+ LPERROR("shared memory atomic demo failed.\n");
+ return ret;
+ }
+
+ ret = ipi_latency_demod();
+ if (ret){
+ LPERROR("IPI latency demo failed.\n");
+ return ret;
+ }
+
+ ret = shmem_latency_demod();
+ if (ret){
+ LPERROR("shared memory latency demo failed.\n");
+ return ret;
+ }
+
+ ret = shmem_throughput_demod();
+ if (ret){
+ LPERROR("shared memory thoughput demo failed.\n");
+ return ret;
+ }
+
+ sys_cleanup();
+ return ret;
+}
+
diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/common.h b/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/common.h
new file mode 100644
index 0000000..8999105
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/common.h
@@ -0,0 +1,197 @@
+ unsigned int flags;
+
+ do {
+ flags = metal_irq_save_disable();
+ if (!atomic_flag_test_and_set(notified)) {
+ metal_irq_restore_enable(flags);
+ break;
+ }
+ wait_for_interrupt();
+ metal_irq_restore_enable(flags);
+ } while(1);
+}
+
+/**
+ * @brief print_demo() - print demo string
+ *
+ * @param[in] name - demo name
+ */
+static inline void print_demo(char *name)
+{
+ LPRINTF("====== libmetal demo: %s ======\n", name);
+}
+
+#endif /* __COMMON_H__ */
+
diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/lscript.ld b/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/lscript.ld
index 009f6d5..9d973f3 100644
--- a/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/lscript.ld
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/lscript.ld
@@ -45,7 +45,7 @@ MEMORY
{
psu_r5_atcm_MEM_0 : ORIGIN = 0x0, LENGTH = 0x10000
psu_r5_btcm_MEM_0 : ORIGIN = 0x20000, LENGTH = 0x10000
- psu_r5_ddr_0_MEM_0 : ORIGIN = 0x3ed60000, LENGTH = 0x80000
+ psu_r5_ddr_0_MEM_0 : ORIGIN = 0x3ed00000, LENGTH = 0x80000
}
/* Specify the default entry point to the program */
diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/sys_init.c b/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/sys_init.c
index 9fbb778..8142f45 100644
--- a/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/sys_init.c
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/generic/machine/zynqmp_r5/sys_init.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
-* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved.
+* Copyright (C) 2010 - 2017 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -43,6 +43,7 @@
#include <metal/irq.h>
#include "platform_config.h"
+#include "common.h"
#ifdef STDOUT_IS_16550
#include <xuartns550_l.h>
@@ -54,24 +55,27 @@
#define IPI_IRQ_VECT_ID 65
+#define SHM_BASE_ADDR 0x3ED80000
+#define TTC0_BASE_ADDR 0xFF110000
+#define IPI_BASE_ADDR 0xFF310000
+
static XScuGic xInterruptController;
@@ -197,11 +187,10 @@ void init_uart()
int init_irq()
{
int ret = 0;
- Xil_ExceptionDisable();
-
XScuGic_Config *IntcConfig; /* The configuration parameters of
* the interrupt controller */
+ Xil_ExceptionDisable();
/*
* Initialize the interrupt controller driver
*/
@@ -243,11 +232,12 @@ int init_irq()
*
* @return 0 - succeeded, non-zero for failures.
*/
-int platform_register_metal_device (void)
+int platform_register_metal_device(void)
{
unsigned int i;
int ret;
struct metal_device *dev;
+
metal_bus_register(&metal_generic_bus);
for (i = 0; i < sizeof(metal_dev_table)/sizeof(struct metal_device);
i++) {
@@ -261,6 +251,62 @@ int platform_register_metal_device (void)
@@ -272,20 +318,28 @@ int sys_init()
@@ -298,20 +352,10 @@ int sys_init()