[EMBEDDEDSW PATCH 0/3] libmetal sync with upstream

217 views
Skip to first unread message

Sam Sortais

unread,
Jul 29, 2017, 10:52:47 AM7/29/17
to open...@googlegroups.com
Fix library memory barrier for io.
Update demo with more API details and for clarity.

BRANCH: master,2017.3
PLATFORM: Zynq,ZynqMP

Sam Sortais (3):
libmetal: io - correct memory barrier in block op
libmetal: demo generic sync with upstream
libmetal: demo freertos sync with upstream

.../sw_services/libmetal/src/libmetal/lib/io.c | 4 +-
.../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/freertos/libmetal_amp_demo.c | 533 ---------------------
.../src/system/freertos/libmetal_amp_demod.c | 177 +++++++
.../src/system/freertos/machine/zynqmp_r5/common.h | 187 ++++++++
.../system/freertos/machine/zynqmp_r5/lscript.ld | 2 +-
.../system/freertos/machine/zynqmp_r5/sys_init.c | 183 ++++---
.../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 +++---
18 files changed, 2519 insertions(+), 1154 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/freertos/libmetal_amp_demo.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/common.h
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

--
2.7.4

Sam Sortais

unread,
Jul 29, 2017, 10:52:48 AM7/29/17
to open...@googlegroups.com
Signed-off-by: Sam Sortais <sam.s...@xilinx.com>
---
.../src/system/freertos/libmetal_amp_demo.c | 533 ---------------------
.../src/system/freertos/libmetal_amp_demod.c | 177 +++++++
.../src/system/freertos/machine/zynqmp_r5/common.h | 187 ++++++++
.../system/freertos/machine/zynqmp_r5/lscript.ld | 2 +-
.../system/freertos/machine/zynqmp_r5/sys_init.c | 183 ++++---
5 files changed, 493 insertions(+), 589 deletions(-)
delete mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demo.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demod.c
create mode 100644 lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/common.h

diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demo.c b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demo.c
deleted file mode 100644
index 3b7c325..0000000
--- a/lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demo.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of Xilinx nor the names of its contributors may be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
- /***************************************************************************
- * libmetal_amp_demo.c
- *
- * This application shows how to use IPI to trigger interrupt and how to
- * setup shared memory with libmetal API for communication between processors.
- *
- * This application 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 initialization.
- * 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 calculation.
- * * 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>
-#include <errno.h>
-
-#include <FreeRTOS.h>
-#include <task.h>
-
-#include <metal/sys.h>
-#include <metal/device.h>
-#include <metal/irq.h>
-#include <metal/atomic.h>
-#include <metal/cpu.h>
-
-#include "sys_init.h"
-
-#define IPI_TRIG_OFFSET 0x0
-#define IPI_OBS_OFFSET 0x4
-#define IPI_ISR_OFFSET 0x10
-#define IPI_IMR_OFFSET 0x14
-#define IPI_IER_OFFSET 0x18
-#define IPI_IDR_OFFSET 0x1C
-
-#define IPI_MASK 0x1000000
-
-#define IPI_DEV_NAME "ff310000.ipi"
-#define SHM0_DESC_DEV_NAME "3ed00000.shm_desc"
-#define SHM1_DESC_DEV_NAME "3ed10000.shm_desc"
-#define SHM_DEV_NAME "3ed20000.shm"
-#define BUS_NAME "generic"
-#define D0_SHM_OFFSET 0x00000
-#define D1_SHM_OFFSET 0x20000
-
-#define BUF_SIZE_MAX 512
-#define SHUTDOWN "shutdown"
-
-#define LPRINTF(format, ...) \
- printf("SERVER> " format, ##__VA_ARGS__)
-#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
-
-
-struct shm_mg_s {
- uint32_t avails;
- uint32_t used;
-};
-
-typedef uint64_t shm_addr_t;
-
-struct msg_hdr_s {
- uint32_t index;
- int32_t len;
-};
-
-struct channel_s {
- struct metal_device *ipi_dev;
- struct metal_io_region *ipi_io;
- unsigned int ipi_mask;
- struct metal_device *shm0_desc_dev;
- struct metal_io_region *shm0_desc_io;
- struct metal_device *shm1_desc_dev;
- struct metal_io_region *shm1_desc_io;
- struct metal_device *shm_dev;
- struct metal_io_region *shm_io;
- atomic_int notified;
- unsigned long d0_start_offset;
- unsigned long d1_start_offset;
-};
-
-static struct channel_s ch0;
-
-extern int system_init();
-extern int run_comm_task(void *task, void *arg);
-extern void wait_for_interrupt(void);
-
-static TaskHandle_t comm_task;
-
-/**
- * @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 interrupt it expected.
- */
-static int ipi_irq_isr (int vect_id, void *priv)
-{
- (void)vect_id;
- struct channel_s *ch = (struct channel_s *)priv;
- uint64_t val = 1;
-
- if (!ch)
- return METAL_IRQ_NOT_HANDLED;
- 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->notified);
- return METAL_IRQ_HANDLED;
- }
- return METAL_IRQ_NOT_HANDLED;
-}
-
-/**
- * @brief ipi_task_shm_atomicd() - Shared memory atomic operation demo
- * This task will:
- * * Wait for the remote to trigger IPI.
- * * Once it receives the IPI interrupt, it start atomic add by 1 for
- * 1000 times to the first 32bit of the shared memory descriptor
- * location.
- * * Trigger IPI to notify the remote once it finishes calculation.
- *
- * @param[in] arg - channel information
- */
-static void *ipi_task_shm_atomicd(void *arg)
-{
- struct channel_s *ch = (struct channel_s *)arg;
- atomic_int *shm_int;
- int i;
-
- shm_int = (atomic_int *)metal_io_virt(ch->shm0_desc_io, 0);
-
- LPRINTF("Wait for atomic test to start.\n");
- while (1) {
- while (atomic_flag_test_and_set(&ch->notified)) {
- taskYIELD();
- }
- 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 notify 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;
- 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) {
- LPERROR("Failed to allocate local buffer for msg.\n");
- return NULL;
- }
-
- LPRINTF("Wait for echo test to start.\n");
- while (1) {
- while (atomic_flag_test_and_set(&ch->notified)) {
- taskYIELD();
- }
- 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) {
- LPERROR("failed to get rx address: 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)) {
- LPERROR("Failed to get msg header.\n");
- goto out;
- }
- msg_hdr = lbuf;
- if (msg_hdr->len < 0) {
- LPERROR("wrong msg length: %d.\n",
- (int)msg_hdr->len);
- goto out;
- } else {
- /* Copy msg data from shared buf to local mem */
- d0 += sizeof(struct msg_hdr_s);
- len = metal_io_block_read(ch->shm_io,
- metal_io_virt_to_offset(ch->shm_io, d0),
- lbuf + sizeof(struct msg_hdr_s),
- msg_hdr->len);
-#if DEBUG
- LPRINTF("received: %d, %d\n",
- (int)msg_hdr->index, (int)msg_hdr->len);
-#endif
- /* Check if the it is the shutdown message */
- if (!strncmp((lbuf + sizeof(struct msg_hdr_s)),
- SHUTDOWN, sizeof(SHUTDOWN))) {
- LPRINTF("Received shutdown message\n");
- goto out;
- }
- }
- /* Copy the message back to the other end */
- metal_io_block_write(ch->shm_io,
- metal_io_virt_to_offset(ch->shm_io, d1),
- lbuf,
- sizeof(struct msg_hdr_s) + msg_hdr->len);
-
- /* Update the d1 address */
- shm1_addr_array[shm1_mg->avails] =
- (uint64_t)metal_io_virt_to_phys(
- ch->shm_io, d1);
- d1 += (sizeof(struct msg_hdr_s) + msg_hdr->len);
- shm0_mg->used++;
- shm1_mg->avails++;
- /* memory barrier */
- atomic_thread_fence(memory_order_acq_rel);
-
- /* Send the message */
- metal_io_write32(ch->ipi_io, IPI_TRIG_OFFSET,
- ch->ipi_mask);
- }
- }
-
-out:
- free(lbuf);
- return NULL;
-}
-
-/**
- * @brief cleanup - cleanup the application
- * The cleanup function 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 demo application main processing task
- * Here are the steps for the task:
- * * 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 self killing task.
- */
-static void processing(void *unused_arg)
-{
- struct metal_device *device;
- struct metal_io_region *io;
- int irq;
- uint32_t val;
- int ret = 0;
-
- (void)unused_arg;
-
- if (sys_init()) {
- LPERROR("Failed to initialize system\n");
- vTaskDelete(NULL);
- return;
- }
- 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) {
- LPERROR("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) {
- LPERROR("Failed to map io region 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) {
- LPERROR("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) {
- LPERROR("Failed to map io region 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) {
- LPERROR("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) {
- LPERROR("Failed to map io region 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) {
- LPERROR("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) {
- LPERROR("Failed to map io region 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) {
- LPERROR("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) {
- LPERROR("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) {
- LPERROR("Failed to run shared memory atomic task.\n");
- goto out;
- }
- ret = run_comm_task(ipi_task_echod, &ch0);
- if (ret) {
- LPERROR("Failed to run IPI communication task.\n");
- }
-
-out:
- cleanup();
-
- /* Terminate this task */
- vTaskDelete(NULL);
-}
-
-/**
- * @brief main function of the demo application.
- * It starts the processing task and go wait forever.
- * @return 0 - succeeded, but in reality will never return.
- */
-
-int main(void)
-{
- BaseType_t stat;
-
- Xil_ExceptionDisable();
-
- /* Create the tasks */
- stat = xTaskCreate(processing, ( const char * ) "HW2",
- 1024, NULL, 2, &comm_task);
- if (stat != pdPASS) {
- LPERROR("cannot create task\n");
- } else {
- /* Start running FreeRTOS tasks */
- vTaskStartScheduler();
- }
-
- /* Will normally not get here */
- while (1) {
- __asm__("wfi\n\t");
- }
-
- /* suppress compilation warnings*/
- return 0;
-}
diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demod.c b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demod.c
new file mode 100644
index 0000000..39e12c9
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/libmetal_amp_demod.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Xilinx nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /***************************************************************************
+ * libmetal_amp_demo.c
+ *
+ * This application shows how to use IPI to trigger interrupt and how to
+ * setup shared memory with libmetal API for communication between processors.
+ *
+ * This application 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 initialization.
+ * 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 calculation.
+ * * 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 <FreeRTOS.h>
+#include <task.h>
+
+#include <unistd.h>
+#include <metal/atomic.h>
+#include <metal/io.h>
+#include <metal/device.h>
+#include <metal/irq.h>
+#include "common.h"
+
+static TaskHandle_t comm_task;
+
+/**
+ * @brief demo application main processing task
+ * 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 before self killing task.
+ * Report if any of the above demos failed.
+ * @return 0 - succeeded, non-zero for failures.
+ */
+static void processing(void *unused_arg)
+{
+ int ret;
+
+ (void)unused_arg;
+
+ ret = sys_init();
+
+ if (ret) {
+ LPERROR("Failed to initialize system.\n");
+ goto out;
+ }
+
+ ret = shmem_demod();
+ if (ret){
+ LPERROR("shared memory demo failed.\n");
+ goto out;
+ }
+
+ ret = atomic_shmem_demod();
+ if (ret){
+ LPERROR("shared memory atomic demo failed.\n");
+ goto out;
+ }
+
+ ret = ipi_shmem_demod();
+ if (ret){
+ LPERROR("shared memory atomic demo failed.\n");
+ goto out;
+ }
+
+ ret = ipi_latency_demod();
+ if (ret){
+ LPERROR("IPI latency demo failed.\n");
+ goto out;
+ }
+
+ ret = shmem_latency_demod();
+ if (ret){
+ LPERROR("shared memory latency demo failed.\n");
+ goto out;
+ }
+
+ ret = shmem_throughput_demod();
+ if (ret){
+ LPERROR("shared memory thoughput demo failed.\n");
+ goto out;
+ }
+
+ sys_cleanup();
+
+out:
+ /* Terminate this task */
+ vTaskDelete(NULL);
+}
+
+/**
+ * @brief main function of the demo application.
+ * It starts the processing task and go wait forever.
+ * @return 0 - succeeded, but in reality will never return.
+ */
+
+int main(void)
+{
+ BaseType_t stat;
+
+ Xil_ExceptionDisable();
+
+ /* Create the tasks */
+ stat = xTaskCreate(processing, ( const char * ) "HW",
+ 1024, NULL, 2, &comm_task);
+ if (stat != pdPASS) {
+ LPERROR("Cannot create task\n");
+ } else {
+ /* Start running FreeRTOS tasks */
+ vTaskStartScheduler();
+ }
+
+ /* Will normally not get here */
+ while (1) {
+ wait_for_interrupt();
+ }
+
+ /* suppress compilation warnings*/
+ return 0;
+}
diff --git a/lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/common.h b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/common.h
new file mode 100644
index 0000000..04d719c
--- /dev/null
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/common.h
@@ -0,0 +1,187 @@
+ /*
+ * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Xilinx nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <metal/atomic.h>
+#include <metal/alloc.h>
+#include <metal/irq.h>
+#include <errno.h>
+#include <metal/sys.h>
+#include <metal/cpu.h>
+#include <metal/io.h>
+#include <metal/device.h>
+#include <sys/types.h>
+#include "sys_init.h"
+
+/* Devices names */
+#define BUS_NAME "generic"
+#define IPI_DEV_NAME "ff310000.ipi"
+#define SHM_DEV_NAME "3ed80000.shm"
+#define TTC_DEV_NAME "ff110000.ttc"
+
+/* IPI registers offset */
+#define IPI_TRIG_OFFSET 0x0 /* IPI trigger reg offset */
+#define IPI_OBS_OFFSET 0x4 /* IPI observation reg offset */
+#define IPI_ISR_OFFSET 0x10 /* IPI interrupt status reg offset */
+#define IPI_IMR_OFFSET 0x14 /* IPI interrupt mask reg offset */
+#define IPI_IER_OFFSET 0x18 /* IPI interrupt enable reg offset */
+#define IPI_IDR_OFFSET 0x1C /* IPI interrup disable reg offset */
+
+#define IPI_MASK 0x1000000 /* IPI mask for kick from APU.
+ We use PL0 IPI in this demo. */
+
+/* TTC counter offsets */
+#define XTTCPS_CLK_CNTRL_OFFSET 0x0 /* TTC counter clock control reg offset */
+#define XTTCPS_CNT_CNTRL_OFFSET 0xC /* TTC counter control reg offset */
+#define XTTCPS_CNT_VAL_OFFSET 0x18 /* TTC counter val reg offset */
+#define XTTCPS_CNT_OFFSET(ID) (2 << (ID - 1)) /* TTC counter offset
+ ID is from 1 to 3 */
+
+/* TTC counter control masks */
+#define XTTCPS_CNT_CNTRL_RST_MASK 0x10U /* TTC counter constrol reset mask */
+#define XTTCPS_CNT_CNTRL_DIS_MASK 0x01U /* TTC counter control disable mask */
+
+#define LPRINTF(format, ...) \
+ xil_printf("\r\nSERVER> " format, ##__VA_ARGS__)
+
+#define LPERROR(format, ...) LPRINTF("ERROR: " format, ##__VA_ARGS__)
+
+extern struct metal_device *ipi_dev; /* IPI metal device */
+extern struct metal_device *shm_dev; /* IPI metal device */
+extern struct metal_device *ttc_dev; /* IPI metal device */
+
+/**
+ * @brief atomic_shmem_demod() - 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 1000 times to first 32 bits of memory in the
+ * shared memory location at 3ed00000 which is pointed to by shm_io.
+ * * Write to shared mem to notify the remote once it finishes
+ * calculation.
+ *
+ * @return - If setup failed, return the corresponding error number. Otherwise
+ * return 0 on success.
+ */
+int atomic_shmem_demod();
+
+/**
+ * @brief ipi_latency_demod() - Show performance of IPI with Libmetal.
+ * Loop until APU tells RPU to stop via shared memory.
+ * In loop, wait for interrupt (interrupt handler stops APU to
+ * RPU timer). Then reset count on RPU to APU timer to 0, start
+ * counting and send interrupt to notify APU.
+ *
+ * @return - 0 on success, error code if failure.
+ */
+int ipi_latency_demod();
+
+/**
+ * @brief ipi_shmem_demod() - 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.
+ *
+ * @return - 0 on success, error code if failure.
+ */
+int ipi_shmem_demod();
+
+/**
+ * @brief shmem_demod() - Show use of shared memory with Libmetal.
+ * Until KEEP_GOING signal is stopped, keep looping.
+ * In the loop, read message from remote, add one to message and
+ * then respond. After the loop, cleanup resources.
+ *
+ * @return - return 0 on success, otherwise return error number indicating
+ * type of error
+ */
+int shmem_demod();
+
+/**
+ * @brief shmem_latency_demod() - Show performance of shared mem.
+ * Loop until APU tells RPU to stop via shared memory.
+ * In loop, wait for interrupt (interrupt handler stops APU to
+ * RPU timer). Then reset count on RPU to APU timer to 0, start
+ * counting and send interrupt to notify APU.
+ *
+ * @return - 0 on success, error code if failure.
+ */
+int shmem_latency_demod();
+
+/**
+ * @brief shmem_throughput_demod() - Show throughput of shared mem.
+ * At signal of remote, record total time to do block read and write
+ * operation Loop until APU tells RPU to stop via shared memory.
+ * In loop, wait for interrupt (interrupt handler stops APU to
+ * RPU timer). Then reset count on RPU to APU timer to 0, start
+ * counting and send interrupt to notify APU.
+ *
+ * @return - 0 on success, error code if failure.
+ */
+int shmem_throughput_demod();
+
+static inline void wait_for_interrupt()
+{
+ asm volatile("wfi");
+}
+
+/**
+ * @breif wait_for_notified() - Loop until notified bit
+ * in channel is set.
+ *
+ * @param[in] notified - pointer to the notified variable
+ */
+static inline void wait_for_notified(atomic_int *notified)
+{
+ while (atomic_flag_test_and_set(notified));
+}
+
+/**
+ * @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/freertos/machine/zynqmp_r5/lscript.ld b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/lscript.ld
index 2c9ca42..e23da7e 100644
--- a/lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/lscript.ld
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/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/freertos/machine/zynqmp_r5/sys_init.c b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/sys_init.c
index 41282b8..9fef999 100644
--- a/lib/sw_apps/libmetal_echo_demo/src/system/freertos/machine/zynqmp_r5/sys_init.c
+++ b/lib/sw_apps/libmetal_echo_demo/src/system/freertos/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
+
extern XScuGic xInterruptController;

const metal_phys_addr_t metal_phys[] = {
- 0xFF310000, /**< base IPI address */
- 0x3ED00000, /**< shared memory0 description base address */
- 0x3ED10000, /**< shared memory0 description base address */
- 0x3ED20000, /**< shared memory base address */
+ IPI_BASE_ADDR, /**< base IPI address */
+ SHM_BASE_ADDR, /**< shared memory base address */
+ TTC0_BASE_ADDR, /**< base TTC0 address */
};

-struct metal_device metal_dev_table[] = {
+static struct metal_device metal_dev_table[] = {
{
/* IPI device */
- "ff310000.ipi",
+ IPI_DEV_NAME,
NULL,
1,
{
{
- (void *)0xFF310000,
+ (void *)IPI_BASE_ADDR,
&metal_phys[0],
0x1000,
(sizeof(metal_phys_addr_t) << 3),
@@ -86,15 +90,15 @@ struct metal_device metal_dev_table[] = {

},
{
- /* Shared memory0 management device */
- "3ed00000.shm_desc",
+ /* Shared memory management device */
+ SHM_DEV_NAME,
NULL,
1,
{
{
- (void *)0x3ED00000,
+ (void *)SHM_BASE_ADDR,
&metal_phys[1],
- 0x1000,
+ 0x800000,
(sizeof(metal_phys_addr_t) << 3),
(unsigned long)(-1),
NORM_SHARED_NCACHE | PRIV_RW_USER_RW,
@@ -107,39 +111,18 @@ struct metal_device metal_dev_table[] = {

},
{
- /* Shared memory1 management device */
- "3ed10000.shm_desc",
+ /* ttc0 */
+ TTC_DEV_NAME,
NULL,
1,
{
{
- (void *)0x3ED10000,
+ (void *)TTC0_BASE_ADDR ,
&metal_phys[2],
0x1000,
(sizeof(metal_phys_addr_t) << 3),
(unsigned long)(-1),
- NORM_SHARED_NCACHE | PRIV_RW_USER_RW,
- {NULL},
- }
- },
- {NULL},
- 0,
- NULL,
-
- },
- {
- /* Shared memory management device */
- "3ed20000.shm",
- NULL,
- 1,
- {
- {
- (void *)0x3ED20000,
- &metal_phys[3],
- 0x40000,
- (sizeof(metal_phys_addr_t) << 3),
- (unsigned long)(-1),
- NORM_SHARED_NCACHE | PRIV_RW_USER_RW,
+ DEVICE_NONSHARED | PRIV_RW_USER_RW,
{NULL},
}
},
@@ -151,6 +134,13 @@ struct metal_device metal_dev_table[] = {
};

/**
+ * Extern global variables
+ */
+struct metal_device *ipi_dev = NULL;
+struct metal_device *shm_dev = NULL;
+struct metal_device *ttc_dev = NULL;
+
+/**
* @brief enable_caches() - Enable caches
*/
void enable_caches()
@@ -196,6 +186,34 @@ void init_uart()
*/
int init_irq()
{
+ int ret = 0;
+ XScuGic_Config *IntcConfig; /* The configuration parameters of
+ * the interrupt controller */
+
+ Xil_ExceptionDisable();
+ /*
+ * Initialize the interrupt controller driver
+ */
+ IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
+ if (NULL == IntcConfig) {
+ return (int)XST_FAILURE;
+ }
+
+ ret = XScuGic_CfgInitialize(&xInterruptController, IntcConfig,
+ IntcConfig->CpuBaseAddress);
+ if (ret != XST_SUCCESS) {
+ return (int)XST_FAILURE;
+ }
+
+ /*
+ * Register the interrupt handler to the hardware interrupt handling
+ * logic in the ARM processor.
+ */
+ Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
+ (Xil_ExceptionHandler)XScuGic_InterruptHandler,
+ &xInterruptController);
+
+ Xil_ExceptionEnable();
/* Connect IPI Interrupt ID with libmetal ISR */
XScuGic_Connect(&xInterruptController, IPI_IRQ_VECT_ID,
(Xil_ExceptionHandler)metal_irq_isr,
@@ -214,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++) {
@@ -232,6 +251,62 @@ int platform_register_metal_device (void)
}

/**
+ * @brief open_metal_devices() - Open registered libmetal devices.
+ * This function opens all the registered libmetal devices.
+ *
+ * @return 0 - succeeded, non-zero for failures.
+ */
+int open_metal_devices(void)
+{
+ int ret;
+
+ /* Open shared memory device */
+ ret = metal_device_open(BUS_NAME, SHM_DEV_NAME, &shm_dev);
+ if (ret) {
+ LPERROR("Failed to open device %s.\n", SHM_DEV_NAME);
+ goto out;
+ }
+
+ /* Open IPI device */
+ ret = metal_device_open(BUS_NAME, IPI_DEV_NAME, &ipi_dev);
+ if (ret) {
+ LPERROR("Failed to open device %s.\n", IPI_DEV_NAME);
+ goto out;
+ }
+
+ /* Open TTC device */
+ ret = metal_device_open(BUS_NAME, TTC_DEV_NAME, &ttc_dev);
+ if (ret) {
+ LPERROR("Failed to open device %s.\n", TTC_DEV_NAME);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * @brief close_metal_devices() - close libmetal devices
+ * This function closes all the libmetal devices which have
+ * been opened.
+ *
+ */
+void close_metal_devices(void)
+{
+ /* Close shared memory device */
+ if (shm_dev)
+ metal_device_close(shm_dev);
+
+ /* Close IPI device */
+ if (ipi_dev)
+ metal_device_close(ipi_dev);
+
+ /* Close TTC device */
+ if (ttc_dev)
+ metal_device_close(ttc_dev);
+}
+
+/**
* @brief sys_init() - Register libmetal devices.
* This function register the libmetal generic bus, and then
* register the IPI, shared memory descriptor and shared memory
@@ -243,20 +318,28 @@ int sys_init()
{
struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
int ret;
+
enable_caches();
init_uart();
if (init_irq()) {
- xil_printf("Failed to initialize interrupt\n");
+ LPERROR("Failed to initialize interrupt\n");
}
- /** Register the device */
+
+ /* Initialize libmetal environment */
metal_init(&metal_param);
+ /* Register libmetal devices */
ret = platform_register_metal_device();
if (ret) {
- xil_printf(
- "%s: failed to register device: %d\n", __func__, ret);
+ LPERROR("%s: failed to register devices: %d\n", __func__, ret);
return ret;
}

+ /* Open libmetal devices which have been registered */
+ ret = open_metal_devices();
+ if (ret) {
+ LPERROR("%s: failed to open devices: %d\n", __func__, ret);
+ return ret;
+ }
return 0;
}

@@ -269,20 +352,10 @@ int sys_init()
*/
void sys_cleanup()
{
+ /* Close libmetal devices which have been opened */
+ close_metal_devices();
+ /* Finish libmetal environment */
metal_finish();
disable_caches();
}

-typedef void *(*task_to_run)(void *arg);
-/**
- * @brief run_comm_task() - run the communication task
- */
-int run_comm_task(task_to_run task, void *arg)
-{
- task(arg);
- return 0;
-}
-
-void wait_for_interrupt(void) {
- asm volatile("wfi");
-}
--
2.7.4

Sam Sortais

unread,
Jul 29, 2017, 10:52:48 AM7/29/17
to open...@googlegroups.com, Wendy Liang
Add memory barrier after io block.
move memory barrier from the end of block read to the beginning
of block read.

Signed-off-by: Wendy Liang <jli...@xilinx.com>
Signed-off-by: Sam Sortais <sam.s...@xilinx.com>
---
ThirdParty/sw_services/libmetal/src/libmetal/lib/io.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/ThirdParty/sw_services/libmetal/src/libmetal/lib/io.c b/ThirdParty/sw_services/libmetal/src/libmetal/lib/io.c
index e33cf54..b435f66 100644
--- a/ThirdParty/sw_services/libmetal/src/libmetal/lib/io.c
+++ b/ThirdParty/sw_services/libmetal/src/libmetal/lib/io.c
@@ -46,6 +46,7 @@ int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
retlen = (*io->ops.block_read)(
io, offset, dst, memory_order_seq_cst, len);
} else {
+ atomic_thread_fence(memory_order_seq_cst);
while ( len && (
((uintptr_t)dst % sizeof(int)) ||
((uintptr_t)ptr % sizeof(int)))) {
@@ -62,7 +63,6 @@ int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
for (; len != 0; dst++, ptr++, len--)
*(unsigned char *)dst =
*(const unsigned char *)ptr;
- atomic_thread_fence(memory_order_seq_cst);
}
return retlen;
}
@@ -131,6 +131,8 @@ int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
*(unsigned int *)ptr = cint;
for (; len != 0; ptr++, len--)
*(unsigned char *)ptr = (unsigned char) value;
+ atomic_thread_fence(memory_order_seq_cst);
}
return retlen;
}
+
--
2.7.4

Sam Sortais

unread,
Jul 29, 2017, 10:52:48 AM7/29/17
to open...@googlegroups.com
Signed-off-by: Sam Sortais <sam.s...@xilinx.com>
---
.../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()

Sam Sortais

unread,
Jul 29, 2017, 11:00:54 AM7/29/17
to open-amp
Sorry this was sent to wrong repo/list, please ignore.
Reply all
Reply to author
Forward
0 new messages