建立工程,成功创建两个虚拟串口

This commit is contained in:
ranchuan
2023-06-21 18:00:56 +08:00
commit 3604192d8f
872 changed files with 428764 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE})
add_subdirectory(${PROJECT_MACHINE})
endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_MACHINE})

View File

@@ -0,0 +1,18 @@
collect(PROJECT_LIB_DEPS freertos)
collect(PROJECT_LIB_DEPS metal)
collect(PROJECT_LIB_DEPS xil)
collect(PROJECT_LIB_DEPS c)
collect(PROJECT_LIB_DEPS m)
set (_lib "xil")
find_library (_lib_path ${_lib})
if (NOT _lib_path)
message ( "external library ${_lib_path} not found" )
message ( "hint: you may need to pass -DCMAKE_LIBRARY_PATH=<path>" )
message ( FATAL_ERROR "library ${_lib} is required to build the examples" )
endif (NOT _lib_path)
get_filename_component (_lib_path ${_lib_path} DIRECTORY)
collect (PROJECT_LIB_DIRS ${_lib_path})
add_subdirectory(zynqmp_amp_demo)

View File

@@ -0,0 +1,31 @@
collector_list (_list PROJECT_INC_DIRS)
include_directories (${_list} ${CMAKE_CURRENT_SOURCE_DIR})
collector_list (_list PROJECT_LIB_DIRS)
link_directories (${_list})
collector_list (_deps PROJECT_LIB_DEPS)
set (_linker_script ${CMAKE_CURRENT_SOURCE_DIR}/lscript.ld)
set (_src_common ${CMAKE_CURRENT_SOURCE_DIR}/init_${PROJECT_SYSTEM}.c)
set (_app0 libmetal_amp_demod)
set (_src0 ${CMAKE_CURRENT_SOURCE_DIR}/${_app0}.c)
list(APPEND _src0 ${CMAKE_CURRENT_SOURCE_DIR}/sys_init.c)
list(APPEND _src0 ${CMAKE_CURRENT_SOURCE_DIR}/shmem_demod.c)
list(APPEND _src0 ${CMAKE_CURRENT_SOURCE_DIR}/shmem_atomic_demod.c)
list(APPEND _src0 ${CMAKE_CURRENT_SOURCE_DIR}/ipi_shmem_demod.c)
list(APPEND _src0 ${CMAKE_CURRENT_SOURCE_DIR}/ipi_latency_demod.c)
list(APPEND _src0 ${CMAKE_CURRENT_SOURCE_DIR}/shmem_latency_demod.c)
list(APPEND _src0 ${CMAKE_CURRENT_SOURCE_DIR}/shmem_throughput_demod.c)
get_property (_linker_options GLOBAL PROPERTY TEST_LINKER_OPTIONS)
add_executable (${_app0}.elf ${_src0})
if (PROJECT_EC_FLAGS)
string(REPLACE " " ";" _ec_flgs ${PROJECT_EC_FLAGS})
target_compile_options (${_app0}.elf PUBLIC ${_ec_flgs})
endif (PROJECT_EC_FLAGS)
target_link_libraries(${_app0}.elf -Wl,-Map=${_app0}.map -Wl,--gc-sections -T\"${_linker_script}\" -Wl,--start-group ${_deps} -Wl,--end-group)
install (TARGETS ${_app0}.elf RUNTIME DESTINATION bin)
# vim: expandtab:ts=2:sw=2:smartindent

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#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 <metal/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) ((ID) == 1 ? 0 : 1 << (ID)) /* TTC counter offset
ID is from 1 to 3 */
/* TTC counter control masks */
#define XTTCPS_CNT_CNTRL_RST_MASK 0x10U /* TTC counter control 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; /* SHM metal device */
extern struct metal_device *ttc_dev; /* TTC 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__ */

View File

@@ -0,0 +1,218 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*****************************************************************************
* 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 */
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);
/* unregister IPI irq handler */
metal_irq_unregister(ipi_irq, 0, ipi_dev, &ch);
out:
return ret;
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*****************************************************************************
* 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 <metal/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);
/* unregister IPI irq handler */
metal_irq_unregister(ipi_irq, 0, ipi_dev, ipi_io);
out:
return ret;
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/***************************************************************************
* 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;
}

View File

@@ -0,0 +1,317 @@
/******************************************************************************
*
* Copyright (C) 2017 Xilinx, Inc. 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.
*
******************************************************************************/
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x1000;
_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x6000;
_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024;
_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048;
_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024;
_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024;
_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024;
/* Define Memories in the system */
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 = 0x3ed00000, LENGTH = 0x80000
}
/* Specify the default entry point to the program */
ENTRY(_boot)
/* Define the sections, and where they are mapped in memory */
SECTIONS
{
.vectors : {
KEEP (*(.vectors))
*(.boot)
} > psu_r5_atcm_MEM_0
.text : {
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.glue_7)
*(.glue_7t)
*(.vfp11_veneer)
*(.ARM.extab)
*(.gnu.linkonce.armextab.*)
} > psu_r5_ddr_0_MEM_0
.init : {
KEEP (*(.init))
} > psu_r5_ddr_0_MEM_0
.fini : {
KEEP (*(.fini))
} > psu_r5_ddr_0_MEM_0
.interp : {
KEEP (*(.interp))
} > psu_r5_ddr_0_MEM_0
.note-ABI-tag : {
KEEP (*(.note-ABI-tag))
} > psu_r5_ddr_0_MEM_0
.rodata : {
__rodata_start = .;
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
__rodata_end = .;
} > psu_r5_ddr_0_MEM_0
.rodata1 : {
__rodata1_start = .;
*(.rodata1)
*(.rodata1.*)
__rodata1_end = .;
} > psu_r5_ddr_0_MEM_0
.sdata2 : {
__sdata2_start = .;
*(.sdata2)
*(.sdata2.*)
*(.gnu.linkonce.s2.*)
__sdata2_end = .;
} > psu_r5_ddr_0_MEM_0
.sbss2 : {
__sbss2_start = .;
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
__sbss2_end = .;
} > psu_r5_ddr_0_MEM_0
.data : {
__data_start = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
*(.jcr)
*(.got)
*(.got.plt)
__data_end = .;
} > psu_r5_ddr_0_MEM_0
.data1 : {
__data1_start = .;
*(.data1)
*(.data1.*)
__data1_end = .;
} > psu_r5_ddr_0_MEM_0
.got : {
*(.got)
} > psu_r5_ddr_0_MEM_0
.ctors : {
__CTOR_LIST__ = .;
___CTORS_LIST___ = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
___CTORS_END___ = .;
} > psu_r5_ddr_0_MEM_0
.dtors : {
__DTOR_LIST__ = .;
___DTORS_LIST___ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
___DTORS_END___ = .;
} > psu_r5_ddr_0_MEM_0
.fixup : {
__fixup_start = .;
*(.fixup)
__fixup_end = .;
} > psu_r5_ddr_0_MEM_0
.eh_frame : {
*(.eh_frame)
} > psu_r5_ddr_0_MEM_0
.eh_framehdr : {
__eh_framehdr_start = .;
*(.eh_framehdr)
__eh_framehdr_end = .;
} > psu_r5_ddr_0_MEM_0
.gcc_except_table : {
*(.gcc_except_table)
} > psu_r5_ddr_0_MEM_0
.mmu_tbl (ALIGN(16384)) : {
__mmu_tbl_start = .;
*(.mmu_tbl)
__mmu_tbl_end = .;
} > psu_r5_ddr_0_MEM_0
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
__exidx_end = .;
} > psu_r5_ddr_0_MEM_0
.preinit_array : {
__preinit_array_start = .;
KEEP (*(SORT(.preinit_array.*)))
KEEP (*(.preinit_array))
__preinit_array_end = .;
} > psu_r5_ddr_0_MEM_0
.init_array : {
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} > psu_r5_ddr_0_MEM_0
.fini_array : {
__fini_array_start = .;
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array))
__fini_array_end = .;
} > psu_r5_ddr_0_MEM_0
.ARM.attributes : {
__ARM.attributes_start = .;
*(.ARM.attributes)
__ARM.attributes_end = .;
} > psu_r5_ddr_0_MEM_0
.sdata : {
__sdata_start = .;
*(.sdata)
*(.sdata.*)
*(.gnu.linkonce.s.*)
__sdata_end = .;
} > psu_r5_ddr_0_MEM_0
.sbss (NOLOAD) : {
__sbss_start = .;
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
__sbss_end = .;
} > psu_r5_ddr_0_MEM_0
.tdata : {
__tdata_start = .;
*(.tdata)
*(.tdata.*)
*(.gnu.linkonce.td.*)
__tdata_end = .;
} > psu_r5_ddr_0_MEM_0
.tbss : {
__tbss_start = .;
*(.tbss)
*(.tbss.*)
*(.gnu.linkonce.tb.*)
__tbss_end = .;
} > psu_r5_ddr_0_MEM_0
.bss (NOLOAD) : {
. = ALIGN(4);
__bss_start__ = .;
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > psu_r5_ddr_0_MEM_0
_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );
_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );
/* Generate Stack and Heap definitions */
.heap (NOLOAD) : {
. = ALIGN(16);
_heap = .;
HeapBase = .;
_heap_start = .;
. += _HEAP_SIZE;
_heap_end = .;
HeapLimit = .;
} > psu_r5_atcm_MEM_0
.stack (NOLOAD) : {
. = ALIGN(16);
_stack_end = .;
. += _STACK_SIZE;
_stack = .;
__stack = _stack;
. = ALIGN(16);
_irq_stack_end = .;
. += _IRQ_STACK_SIZE;
__irq_stack = .;
_supervisor_stack_end = .;
. += _SUPERVISOR_STACK_SIZE;
. = ALIGN(16);
__supervisor_stack = .;
_abort_stack_end = .;
. += _ABORT_STACK_SIZE;
. = ALIGN(16);
__abort_stack = .;
_fiq_stack_end = .;
. += _FIQ_STACK_SIZE;
. = ALIGN(16);
__fiq_stack = .;
_undef_stack_end = .;
. += _UNDEF_STACK_SIZE;
. = ALIGN(16);
__undef_stack = .;
} > psu_r5_atcm_MEM_0
_end = .;
}

View File

@@ -0,0 +1,6 @@
#ifndef __PLATFORM_CONFIG_H_
#define __PLATFORM_CONFIG_H_
#define STDOUT_IS_PSU_UART
#define UART_DEVICE_ID 0
#endif

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*****************************************************************************
* 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);
/* unregister IPI irq handler */
metal_irq_unregister(ipi_irq, 0, ipi_dev, ipi_io);
out:
return ret;
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*****************************************************************************
* 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;
}

View File

@@ -0,0 +1,265 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*****************************************************************************
* 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 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);
/* unregister IPI irq handler */
metal_irq_unregister(ipi_irq, 0, ipi_dev, &ch);
out:
return ret;
}

View File

@@ -0,0 +1,355 @@
/*
* Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*****************************************************************************
* 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 - 0x1FFFFF | address array for shared buffers from APU to RPU |
* |0x200000 - 0x200004 | number of RPU to APU buffers available to APU |
* |0x200004 - 0x3FFFFF | address array for shared buffers from RPU to APU |
* |0x400000 - 0x7FFFFF | APU to RPU buffers |
* |0x800000 - 0xAFFFFF | 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 0x400000
#define SHM_DESC_OFFSET_TX 0x200000
#define SHM_BUFF_OFFSET_TX 0x800000
/* Shared memory descriptors offset */
#define SHM_DESC_AVAIL_OFFSET 0x00
#define SHM_DESC_ADDR_ARRAY_OFFSET 0x04
#define BUF_SIZE_MAX 4096
#define PKG_SIZE_MAX 1024
#define PKG_SIZE_MIN 16
#define TOTAL_DATA_SIZE (1024 * 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 */
};
/**
* @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, iterations;
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;
iterations = TOTAL_DATA_SIZE / s;
/* 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;
iterations = TOTAL_DATA_SIZE / s;
/* 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);
/* unregister IPI irq handler */
metal_irq_unregister(ipi_irq, 0, ipi_dev, &ch);
out:
return ret;
}

View File

@@ -0,0 +1,360 @@
/******************************************************************************
*
* Copyright (C) 2010 - 2017 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
******************************************************************************/
#include <xparameters.h>
#include <xil_cache.h>
#include <xil_exception.h>
#include <xstatus.h>
#include <xscugic.h>
#include <xreg_cortexr5.h>
#include <metal/io.h>
#include <metal/device.h>
#include <metal/sys.h>
#include <metal/irq.h>
#include "platform_config.h"
#include "common.h"
#ifdef STDOUT_IS_16550
#include <xuartns550_l.h>
#define UART_BAUD 9600
#endif
#define INTC_DEVICE_ID XPAR_SCUGIC_0_DEVICE_ID
#define IPI_IRQ_VECT_ID 65
#define SHM_BASE_ADDR 0x3ED80000
#define TTC0_BASE_ADDR 0xFF110000
#define IPI_BASE_ADDR 0xFF310000
/* Default generic I/O region page shift */
/* Each I/O region can contain multiple pages.
* In FreeRTOS system, the memory mapping is flat, there is no
* virtual memory.
* We can assume there is only one page in the FreeRTOS system.
*/
#define DEFAULT_PAGE_SHIFT (-1UL)
#define DEFAULT_PAGE_MASK (-1UL)
extern XScuGic xInterruptController;
const metal_phys_addr_t metal_phys[] = {
IPI_BASE_ADDR, /**< base IPI address */
SHM_BASE_ADDR, /**< shared memory base address */
TTC0_BASE_ADDR, /**< base TTC0 address */
};
/* Define metal devices table for IPI, shared memory and TTC devices.
* Linux system uses device tree to describe devices. Unlike Linux,
* there is no standard device abstraction for FreeRTOS system, we
* uses libmetal devices structure to describe the devices we used in
* the example.
* The IPI, shared memory and TTC devices are memory mapped
* devices. For this type of devices, it is required to provide
* accessible memory mapped regions, and interrupt information.
* In FreeRTOS system, the memory mapping is flat. As you can see
* in the table before, we set the virtual address "virt" the same
* as the physical address.
*/
static struct metal_device metal_dev_table[] = {
{
/* IPI device */
.name = IPI_DEV_NAME,
.bus = NULL,
.num_regions = 1,
.regions = {
{
.virt = (void *)IPI_BASE_ADDR,
.physmap = &metal_phys[0],
.size = 0x1000,
.page_shift = DEFAULT_PAGE_SHIFT,
.page_mask = DEFAULT_PAGE_MASK,
.mem_flags = DEVICE_NONSHARED | PRIV_RW_USER_RW,
.ops = {NULL},
}
},
.node = {NULL},
.irq_num = 1,
.irq_info = (void *)IPI_IRQ_VECT_ID,
},
{
/* Shared memory management device */
.name = SHM_DEV_NAME,
.bus = NULL,
.num_regions = 1,
.regions = {
{
.virt = (void *)SHM_BASE_ADDR,
.physmap = &metal_phys[1],
.size = 0x1000000,
.page_shift = DEFAULT_PAGE_SHIFT,
.page_mask = DEFAULT_PAGE_MASK,
.mem_flags = NORM_SHARED_NCACHE |
PRIV_RW_USER_RW,
.ops = {NULL},
}
},
.node = {NULL},
.irq_num = 0,
.irq_info = NULL,
},
{
/* ttc0 */
.name = TTC_DEV_NAME,
.bus = NULL,
.num_regions = 1,
.regions = {
{
.virt = (void *)TTC0_BASE_ADDR ,
.physmap = &metal_phys[2],
.size = 0x1000,
.page_shift = DEFAULT_PAGE_SHIFT,
.page_mask = DEFAULT_PAGE_MASK,
.mem_flags = DEVICE_NONSHARED | PRIV_RW_USER_RW,
.ops = {NULL},
}
},
.node = {NULL},
.irq_num = 0,
.irq_info = NULL,
},
};
/**
* 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()
{
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
Xil_ICacheEnable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
Xil_DCacheEnable();
#endif
#endif
}
/**
* @brief disable_caches() - Disable caches
*/
void disable_caches()
{
Xil_DCacheDisable();
Xil_ICacheDisable();
}
/**
* @brief init_uart() - Initialize UARTs
*/
void init_uart()
{
#ifdef STDOUT_IS_16550
XUartNs550_SetBaud(STDOUT_BASEADDR, XPAR_XUARTNS550_CLOCK_HZ,
UART_BAUD);
XUartNs550_SetLineControlReg(STDOUT_BASEADDR, XUN_LCR_8_DATA_BITS);
#endif
/* Bootrom/BSP configures PS7/PSU UART to 115200 bps */
}
/**
* @brief init_irq() - Initialize GIC and connect IPI interrupt
* This function will initialize the GIC and connect the IPI
* interrupt.
*
* @return 0 - succeeded, non-0 for failures
*/
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,
(void *)IPI_IRQ_VECT_ID);
XScuGic_Enable(&xInterruptController, IPI_IRQ_VECT_ID);
return 0;
}
/**
* @brief platform_register_metal_device() - Statically Register libmetal
* devices.
* This function registers the IPI, shared memory and
* TTC devices to the libmetal generic bus.
* Libmetal uses bus structure to group the devices. Before you can
* access the device with libmetal device operation, you will need to
* register the device to a libmetal supported bus.
* For non-Linux system, libmetal only supports "generic" bus, which is
* used to manage the memory mapped devices.
*
* @return 0 - succeeded, non-zero for failures.
*/
int platform_register_metal_device(void)
{
unsigned int i;
int ret;
struct metal_device *dev;
for (i = 0; i < sizeof(metal_dev_table)/sizeof(struct metal_device);
i++) {
dev = &metal_dev_table[i];
xil_printf("registering: %d, name=%s\n", i, dev->name);
ret = metal_register_generic_device(dev);
if (ret)
return ret;
}
return 0;
}
/**
* @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
* devices to the libmetal generic bus.
*
* @return 0 - succeeded, non-zero for failures.
*/
int sys_init()
{
struct metal_init_params metal_param = METAL_INIT_DEFAULTS;
int ret;
enable_caches();
init_uart();
if (init_irq()) {
LPERROR("Failed to initialize interrupt\n");
}
/* Initialize libmetal environment */
metal_init(&metal_param);
/* Register libmetal devices */
ret = platform_register_metal_device();
if (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;
}
/**
* @brief sys_cleanup() - system cleanup
* This function finish the libmetal environment
* and disable caches.
*
* @return 0 - succeeded, non-zero for failures.
*/
void sys_cleanup()
{
/* Close libmetal devices which have been opened */
close_metal_devices();
/* Finish libmetal environment */
metal_finish();
disable_caches();
}

View File

@@ -0,0 +1,17 @@
/******************************************************************************
*
* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
******************************************************************************/
#ifndef __SYS_INIT_H__
#define __SYS_INIT_H__
#include "platform_config.h"
int sys_init();
void sys_cleanup();
#endif /* __SYS_INIT_H__ */