diff --git a/boards/arm/lpcxpresso54114/lpcxpresso54114_m0_defconfig b/boards/arm/lpcxpresso54114/lpcxpresso54114_m0_defconfig index 9ea97e0c83cda0..dee5c12561b8a0 100644 --- a/boards/arm/lpcxpresso54114/lpcxpresso54114_m0_defconfig +++ b/boards/arm/lpcxpresso54114/lpcxpresso54114_m0_defconfig @@ -9,6 +9,7 @@ CONFIG_SOC_LPC54114_M0=y CONFIG_SOC_SERIES_LPC54XXX=y CONFIG_BOARD_LPCXPRESSO54114_M0=y CONFIG_CONSOLE=y +CONFIG_USE_SEGGER_RTT=y CONFIG_RTT_CONSOLE=y CONFIG_SERIAL=n CONFIG_CORTEX_M_SYSTICK=y diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.c b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.c index 994ad9ab10d4e0..403f2659648ae6 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.c +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.c @@ -39,7 +39,7 @@ unsigned int sys_irq_save_disable(void) void metal_machine_cache_flush(void *addr, unsigned int len) { - if (!addr & !len) + if (!addr && !len) Xil_DCacheFlush(); else Xil_DCacheFlushRange((intptr_t)addr, len); @@ -47,7 +47,7 @@ void metal_machine_cache_flush(void *addr, unsigned int len) void metal_machine_cache_invalidate(void *addr, unsigned int len) { - if (!addr & !len) + if (!addr && !len) Xil_DCacheInvalidate(); else Xil_DCacheInvalidateRange((intptr_t)addr, len); diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.c b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.c index 46f13cff741be3..a63628491d048d 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.c +++ b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.c @@ -39,7 +39,7 @@ unsigned int sys_irq_save_disable(void) void metal_machine_cache_flush(void *addr, unsigned int len) { - if (!addr & !len) + if (!addr && !len) Xil_DCacheFlush(); else Xil_DCacheFlushRange((intptr_t)addr, len); @@ -47,7 +47,7 @@ void metal_machine_cache_flush(void *addr, unsigned int len) void metal_machine_cache_invalidate(void *addr, unsigned int len) { - if (!addr & !len) + if (!addr && !len) Xil_DCacheInvalidate(); else Xil_DCacheInvalidateRange((intptr_t)addr, len); diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/device.c b/ext/hal/libmetal/libmetal/lib/system/linux/device.c index 96f4380ae891a7..85af0d77f50753 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/device.c +++ b/ext/hal/libmetal/libmetal/lib/system/linux/device.c @@ -102,7 +102,7 @@ static int metal_uio_dev_bind(struct linux_device *ldev, return 0; if (strcmp(ldev->sdev->driver_name, SYSFS_UNKNOWN) != 0) { - metal_log(METAL_LOG_ERROR, "device %s in use by driver %s\n", + metal_log(METAL_LOG_INFO, "device %s in use by driver %s\n", ldev->dev_name, ldev->sdev->driver_name); return -EBUSY; } @@ -368,6 +368,16 @@ static struct linux_bus linux_bus[] = { .dev_dma_map = metal_uio_dev_dma_map, .dev_dma_unmap = metal_uio_dev_dma_unmap, }, + { + .drv_name = "uio_dmem_genirq", + .mod_name = "uio_dmem_genirq", + .cls_name = "uio", + .dev_open = metal_uio_dev_open, + .dev_close = metal_uio_dev_close, + .dev_irq_ack = metal_uio_dev_irq_ack, + .dev_dma_map = metal_uio_dev_dma_map, + .dev_dma_unmap = metal_uio_dev_dma_unmap, + }, { 0 /* sentinel */ } } }, @@ -636,3 +646,24 @@ int metal_generic_dev_sys_open(struct metal_device *dev) return 0; } +int metal_linux_get_device_property(struct metal_device *device, + const char *property_name, + void *output, int len) +{ + int fd = 0; + int status = 0; + const int flags = O_RDONLY; + const int mode = S_IRUSR | S_IRGRP | S_IROTH; + struct linux_device *ldev = to_linux_device(device); + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "%s/of_node/%s", + ldev->sdev->path, property_name); + fd = open(path, flags, mode); + if (fd < 0) + return -errno; + status = read(fd, output, len); + + return status < 0 ? -errno : 0; +} + diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/init.c b/ext/hal/libmetal/libmetal/lib/system/linux/init.c index 28ce249151f417..0dbfa769bc8519 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/init.c +++ b/ext/hal/libmetal/libmetal/lib/system/linux/init.c @@ -135,7 +135,7 @@ int metal_sys_init(const struct metal_init_params *params) strerror(errno)); return -errno; } - if (sizeof(int) != fread(&seed, sizeof(int), 1, urandom)) { + if (fread(&seed, 1, sizeof(seed), urandom) <= 0) { metal_log(METAL_LOG_DEBUG, "Failed fread /dev/urandom\n"); } fclose(urandom); diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/sys.h b/ext/hal/libmetal/libmetal/lib/system/linux/sys.h index cbc4e57818f546..11834289071669 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/linux/sys.h @@ -46,6 +46,8 @@ extern "C" { #define METAL_INVALID_VADDR NULL #define MAX_PAGE_SIZES 32 +struct metal_device; + /** Structure of shared page or hugepage sized data. */ struct metal_page_size { /** Page size. */ @@ -111,6 +113,19 @@ extern void metal_mktemp_template(char template[PATH_MAX], const char *name); extern int metal_virt2phys(void *addr, unsigned long *phys); +/** + * @brief Read a device tree property of a device + * + * @param[in] device metal_device of the intended DT node + * @param[in] property_name name of the property to be read + * @param[out] output output buffer to store read data + * @param[in] len number of bytes to be read + * @return 0 on success, or -errno on error. + */ +extern int metal_linux_get_device_property(struct metal_device *device, + const char *property_name, + void *output, int len); + #define metal_for_each_page_size_up(ps) \ for ((ps) = &_metal.page_sizes[0]; \ (ps) <= &_metal.page_sizes[_metal.num_page_sizes - 1]; \ diff --git a/ext/lib/ipc/open-amp/open-amp/LICENSE b/ext/lib/ipc/open-amp/open-amp/LICENSE deleted file mode 100644 index 749696564d535a..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/LICENSE +++ /dev/null @@ -1,33 +0,0 @@ -Software License Agreement (BSD License) -======================================== - -Copyright (c) 2014, Mentor Graphics Corporation. All rights reserved. -Copyright (c) 2015 - 2016 Xilinx, Inc. All rights reserved. -Copyright (c) 2016 Freescale Semiconductor, 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. The names of its contributors may not 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. - diff --git a/ext/lib/ipc/open-amp/open-amp/LICENSE.md b/ext/lib/ipc/open-amp/open-amp/LICENSE.md new file mode 100644 index 00000000000000..41a8b8ad449a13 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/LICENSE.md @@ -0,0 +1,69 @@ +Software License Agreement (BSD 3-Clause License) +======================================== + +Copyright (c) 2014, Mentor Graphics Corporation. All rights reserved. +Copyright (c) 2015 - 2016 Xilinx, Inc. All rights reserved. +Copyright (c) 2016 Freescale Semiconductor, 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 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. + +BSD 2-Clause License +------------------------- + +Copyright (c) . 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. + +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. + +Notes +========================================= +Use the following tag instead of the full license text in the individual files: + + SPDX-License-Identifier: BSD-3-Clause + SPDX-License-Identifier: BSD-2-Clause + +This enables machine processing of license information based on the SPDX +License Identifiers that are here available: http://spdx.org/licenses/ + diff --git a/ext/lib/ipc/open-amp/open-amp/README.md b/ext/lib/ipc/open-amp/open-amp/README.md index 9f6a2f7c4c02ce..a2c15836592b9b 100644 --- a/ext/lib/ipc/open-amp/open-amp/README.md +++ b/ext/lib/ipc/open-amp/open-amp/README.md @@ -82,14 +82,16 @@ In future, we will try to make libmetal as a submodule to OpenAMP to make this flow easier. ### Example to compile OpenAMP for Zephyr - -As OpenAMP uses libmetal, you will need to build libmetal for Zephyr before -building OpenAMP. You'll build OpenAMP as a CMake target to integrate with -Zephyr's CMake build system. Here is how to build libmetal for Zephyr. It -assumes you have the :ref:`ZEPHYR_SDK ` installed and configured. -Please refer to libmetal's README for additional details. - +You can compile OpenAMP library for Zephyr. +As OpenAMP uses libmetal, please refer to libmetal README to build libmetal +for Zephyr before building OpenAMP library for Zephyr. +As Zephyr uses CMake, we build OpenAMP library as a target of Zephyr CMake +project. Here is how to build libmetal for Zephyr: ``` + $ export ZEPHRY_GCC_VARIANT=zephyr + $ export ZEPHRY_SDK_INSTALL_DIR= + $ source /zephyr-env.sh + $ cmake \ -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 \ -DCMAKE_INCLUDE_PATH="/lib/include" \ @@ -128,10 +130,10 @@ directory. ``` # Start echo test server to wait for message to echo $ sudo LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib \ - build/usr/local/bin/echo_testd-shared + build/usr/local/bin/rpmsg-echo-shared # Run echo test to send message to echo test server $ sudo LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib \ - build/usr/local/bin/echo_test-shared 1 + build/usr/local/bin/rpmsg-echo-ping-shared 1 ``` ### Example to compile Zynq UltraScale+ MPSoC R5 generic(baremetal) remote: @@ -231,15 +233,9 @@ For now, it supports: * Linux userspace OpenAMP RPMsg slave ## Known Limitations: -1. OpenAMP framework supports OpenAMP firmware running as master, however, - the example to show this ability is not ready yet. -2. In case of OpenAMP on Linux userspace for inter processors communication, - life cycle management with remoteproc is not supported yet, that is for now, - it is not able to load the remote firmware with OpenAMP running on Linux - userspace. -3. In case of OpenAMP on Linux userspace for inter processors communication, +1. In case of OpenAMP on Linux userspace for inter processors communication, it only supports static vrings and shared buffers. -4. `sudo` is required to run the OpenAMP demos between Linux processes, as +2. `sudo` is required to run the OpenAMP demos between Linux processes, as it doesn't work on some systems if you are normal users. For using the framework please refer to the wiki of the OpenAMP repo. diff --git a/ext/lib/ipc/open-amp/open-amp/cmake/options.cmake b/ext/lib/ipc/open-amp/open-amp/cmake/options.cmake index a8dca246191ddc..42762b1243f756 100644 --- a/ext/lib/ipc/open-amp/open-amp/cmake/options.cmake +++ b/ext/lib/ipc/open-amp/open-amp/cmake/options.cmake @@ -33,12 +33,6 @@ string (TOUPPER ${CMAKE_SYSTEM_PROCESSOR} PROJECT_PROCESSOR_UPPER) string (TOLOWER ${MACHINE} PROJECT_MACHINE) string (TOUPPER ${MACHINE} PROJECT_MACHINE_UPPER) -# Select to build Remote proc master -option (WITH_REMOTEPROC_MASTER "Build as remoteproc master" OFF) -if (WITH_REMOTEPROC_MASTER) - option (WITH_LINUXREMOTE "The remote is Linux" ON) -endif (WITH_REMOTEPROC_MASTER) - # Select which components are in the openamp lib option (WITH_PROXY "Build with proxy(access device controlled by other processor)" ON) option (WITH_APPS "Build with sample applicaitons" OFF) @@ -46,23 +40,22 @@ option (WITH_PROXY_APPS "Build with proxy sample applicaitons" OFF) if (WITH_APPS) if (WITH_PROXY) set (WITH_PROXY_APPS ON) - elseif ("${PROJECT_SYSTEM}" STREQUAL "linux") - set (WITH_PROXY_APPS ON) endif (WITH_PROXY) - option (WITH_BENCHMARK "Build benchmark app" OFF) endif (WITH_APPS) -option (WITH_OBSOLETE "Build obsolete system libs" OFF) -# Set the complication flags -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") +option (WITH_VIRTIO_MASTER "Build with virtio master enabled" ON) +option (WITH_VIRTIO_SLAVE "Build with virtio slave enabled" ON) -if (WITH_LINUXREMOTE) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DOPENAMP_REMOTE_LINUX_ENABLE") -endif (WITH_LINUXREMOTE) +if (NOT WITH_VIRTIO_MASTER) + add_definitions(-DVIRTIO_SLAVE_ONLY) +endif (NOT WITH_VIRTIO_MASTER) -if (WITH_BENCHMARK) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DOPENAMP_BENCHMARK_ENABLE") -endif (WITH_BENCHMARK) +if (NOT WITH_VIRTIO_SLAVE) + add_definitions(-DVIRTIO_MASTER_ONLY) +endif (NOT WITH_VIRTIO_SLAVE) + +# Set the complication flags +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") option (WITH_STATIC_LIB "Build with a static library" ON) @@ -75,7 +68,6 @@ if (WITH_ZEPHYR) endif (WITH_ZEPHYR) option (WITH_LIBMETAL_FIND "Check Libmetal library can be found" ON) -option (WITH_EXT_INCLUDES_FIND "Check other external includes are found" ON) message ("-- C_FLAGS : ${CMAKE_C_FLAGS}") # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/lib/ipc/open-amp/open-amp/docs/data-structure.md b/ext/lib/ipc/open-amp/open-amp/docs/data-structure.md new file mode 100644 index 00000000000000..4ea6197d7c60d6 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/data-structure.md @@ -0,0 +1,168 @@ +Libmetal helper data struct +=========================== +``` +struct metal_io_region { + char name[64]; /**< I/O region name */ + void *virt; /**< base virtual address */ + const metal_phys_addr_t *physmap; /**< table of base physical address + of each of the pages in the I/O + region */ + size_t size; /**< size of the I/O region */ + unsigned long page_shift; /**< page shift of I/O region */ + metal_phys_addr_t page_mask; /**< page mask of I/O region */ + unsigned int mem_flags; /**< memory attribute of the + I/O region */ + struct metal_io_ops ops; /**< I/O region operations */ +}; + + +/** Libmetal device structure. */ +struct metal_device { + const char *name; /**< Device name */ + struct metal_bus *bus; /**< Bus that contains device */ + unsigned num_regions; /**< Number of I/O regions in + device */ + struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of + I/O regions in device*/ + struct metal_list node; /**< Node on bus' list of devices */ + int irq_num; /**< Number of IRQs per device */ + void *irq_info; /**< IRQ ID */ +}; +``` + +Remoteproc data struct +=========================== +``` +struct remoteproc { + struct metal_device dev; /**< Each remoteproc has a device, each device knows its memories regions */ + metal_mutex_t lock; /**< mutex lock */ + void *rsc_table; /**< pointer to resource table */ + size_t rsc_len; /**< length of the resoruce table */ + struct remoteproc_ops *ops; /**< pointer to remoteproc operation */ + metal_phys_addr_t bootaddr; /**< boot address */ + struct loader_ops *loader_ops; /**< image loader operation */ + unsigned int state; /**< remoteproc state */ + struct metal_list vdevs; /**< list of vdevs (can we limited to one for code size but linux and resource table supports multiple */ + void *priv; /**< remoteproc private data */ +}; + +struct remoteproc_vdev { + struct metal_list node; /**< node */ + struct remoteproc *rproc; /**< pointer to the remoteproc instance */ + struct virtio_dev; /**< virtio device */ + uint32_t notify_id; /**< virtio device notification ID */ + void *vdev_rsc; /**< pointer to the vdev space in resource table */ + struct metal_io_region *vdev_io; /**< pointer to the vdev space I/O region */ + int vrings_num; /**< number of vrings */ + struct rproc_vrings[1]; /**< vrings array */ +}; + +struct remoteproc_vring { + struct remoteproc_vdev *rpvdev; /**< pointer to the remoteproc vdev */ + uint32_t notify_id; /**< vring notify id */ + size_t len; /**< vring length */ + uint32_t alignment; /**< vring alignment */ + void *va; /**< vring start virtual address */ + struct metal_io_region *io; /**< pointer to the vring I/O region */ +}; +``` + +Virtio Data struct +=========================== +``` +struct virtio_dev { + int index; /**< unique position on the virtio bus */ + struct virtio_device_id id; /**< the device type identification (used to match it with a driver). */ + struct metal_device *dev; /**< do we need this in virtio device ? */ + metal_spinlock lock; /**< spin lock */ + uint64_t features; /**< the features supported by both ends. */ + unsigned int role; /**< if it is virtio backend or front end. */ + void (*rst_cb)(struct virtio_dev *vdev); /**< user registered virtio device callback */ + void *priv; /**< pointer to virtio_dev private data */ + int vrings_num; /**< number of vrings */ + struct virtqueue vqs[1]; /**< array of virtqueues */ +}; + +struct virtqueue { + char vq_name[VIRTQUEUE_MAX_NAME_SZ]; /**< virtqueue name */ + struct virtio_device *vdev; /**< pointer to virtio device */ + uint16_t vq_queue_index; + uint16_t vq_nentries; + uint32_t vq_flags; + int vq_alignment; + int vq_ring_size; + boolean vq_inuse; + void *vq_ring_mem; + void (*callback) (struct virtqueue * vq); /**< virtqueue callback */ + void (*notify) (struct virtqueue * vq); /**< virtqueue notify remote function */ + int vq_max_indirect_size; + int vq_indirect_mem_size; + struct vring vq_ring; + uint16_t vq_free_cnt; + uint16_t vq_queued_cnt; + struct metal_io_region *buffers_io; /**< buffers shared memory */ + + /* + * Head of the free chain in the descriptor table. If + * there are no free descriptors, this will be set to + * VQ_RING_DESC_CHAIN_END. + */ + uint16_t vq_desc_head_idx; + + /* + * Last consumed descriptor in the used table, + * trails vq_ring.used->idx. + */ + uint16_t vq_used_cons_idx; + + /* + * Last consumed descriptor in the available table - + * used by the consumer side. + */ + uint16_t vq_available_idx; + + uint8_t padd; + /* + * Used by the host side during callback. Cookie + * holds the address of buffer received from other side. + * Other fields in this structure are not used currently. + * Do we needed??/ + struct vq_desc_extra { + void *cookie; + struct vring_desc *indirect; + uint32_t indirect_paddr; + uint16_t ndescs; + } vq_descx[0]; +}; + +struct vring { + unsigned int num; /**< number of buffers of the vring */ + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; +}; +``` +RPMsg Data struct +=========================== +``` +struct rpmsg_virtio_device { + struct virtio_dev *vdev; /**< pointer to the virtio device */ + struct virtqueue *rvq; /**< pointer to receive virtqueue */ + struct virtqueue *svq; /**< pointer to send virtqueue */ + int buffers_number; /**< number of shared buffers */ + struct metal_io_region *shbuf_io; /**< pointer to the shared buffer I/O region */ + void *shbuf; + int (*new_endpoint_cb)(const char *name, uint32_t addr); /**< name service announcement user designed callback which is used for when there is a name service announcement, there is no local endpoints waiting to bind */ + struct metal_list endpoints; /**< list of endpoints */ +}; + +struct rpmsg_endpoint { + char name[SERVICE_NAME_SIZE]; + struct rpmsg_virtio_dev *rvdev; /**< pointer to the RPMsg virtio device */ + uint32_t addr; /**< endpoint local address */ + uint32_t dest_addr; /**< endpoint default target address */ + int (*cb)(struct rpmsg_endpoint *ept, void *data, struct metal_io_region *io, size_t len, uint32_t addr); /**< endpoint callback */ + void (*destroy)(struct rpmsg_endpoint *ept); /**< user registerd endpoint destory callback */ + /* Whether we need another callback for ack ns announcement? */ +}; +``` diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-ns-dynamic.gv b/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-ns-dynamic.gv new file mode 100644 index 00000000000000..6058f1046928fe --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-ns-dynamic.gv @@ -0,0 +1,97 @@ +// RPMsg dynamic endpoint creation + +digraph G { + rankdir="LR"; + + subgraph roles { + node [style="filled", fillcolor="lightblue"]; + master [label="Master"]; + slave [label="Slave"]; + } + + subgraph m_comment_nodes { + node [group=m_comment, shape="note", style="filled", fillcolor="yellow"]; + rank="same"; + m_remoteproc_init_comment [label="this is initialize rproc call"]; + m_remoteproc_boot_comment [label="it will setup vdev before booting the remote"]; + m_rpmsg_vdev_init_comment [label="\l* It will initialize vrings with the shared memory\l* If vdev supports name service, it will create name service endpoint;\l* it sets vdev status to DRVIER_READY, And will notify remote.\l"]; + m_rpmsg_create_ep_comment [label="\if vdev supports name service,\lit will send out name service.\l"]; + m_rpmsg_send_comment [label="\lIf endpoint hasn't binded, it fail\lreturn failure to indicate ep hasn't been binded.\l"]; + + } + + subgraph m_flow_nodes { + node [shape="box"]; + rank="same"; + m_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"] + m_remoteproc_load [label="calls remoteproc_load() to load applicaiton"]; + m_remoteproc_boot [shape="box", label="ret=remoteproc_boot(&rproc)"]; + m_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, MASTER, NULL);"]; + m_rpmsg_shmpool_init[label="rpmsg_virtio_init_shm_pool(shpool, shbuf, shbuf_pool_size);"]; + m_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, shpool);"]; + m_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, call ns_bind_cb.\l"]; + m_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"]; + m_rpmsg_send [label="rpmsg_send(ept,data)"]; + m_rpmsg_rx_cb [label="rpmsg_rx_callback()"]; + m_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"]; + m_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"]; + + m_remoteproc_init -> m_remoteproc_load -> m_remoteproc_boot -> m_remoteproc_get_vdev -> + m_rpmsg_shmpool_init -> m_rpmsg_vdev_init -> m_rpmsg_create_ep -> m_rpmsg_ns_cb -> m_rpmsg_send; + m_rpmsg_send -> m_rpmsg_rx_cb -> m_ep_cb -> + m_rpmsg_destroy_ep [dir="none", style="dashed"]; + } + + subgraph s_flow_nodes { + rank="same"; + node [shape="box"]; + s_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"]; + + s_remoteproc_parse_rsc [label="ret = remoteproc_set_rsc_table(rproc, &rsc_table, rsc_size)"]; + s_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, SLAVE, rst_cb);"]; + s_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, NULL);"]; + s_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, it will call ns_bind_cb()."]; + s_rpmsg_ns_bind_cb [label="s_rpsmg_ns_bind_cb(ept_name, remote_addr)"]; + s_rpmsg_create_ep [label="\lept=rpmsg_create_endpoint(ept, rdev, ept_name, ept_addr, remote_addr,\lendpoint_cb, ns_unbind_cb);\l"]; + s_rpmsg_send [label="rpmsg_send(ept,data)"]; + s_rpmsg_rx_cb [label="rpmsg_rx_callback()"]; + s_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"]; + s_rpmsg_ns_unbind_cb [label="\lrpmsg_ns_callback() will call the previous\lregistered endpoint unbind callback\l"]; + + s_remoteproc_init -> s_remoteproc_parse_rsc -> s_remoteproc_get_vdev -> + s_rpmsg_vdev_init -> s_rpmsg_ns_cb -> s_rpmsg_ns_bind_cb -> + s_rpmsg_create_ep; + s_rpmsg_create_ep-> s_rpmsg_rx_cb -> s_ep_cb -> s_rpmsg_send -> + s_rpmsg_ns_unbind_cb [dir="none", style="dash"]; + + } + + subgraph s_comment_nodes { + node [group=s_comment, shape="note", style="filled", fillcolor="yellow"]; + rank="same"; + s_rpmsg_vdev_init_comment [label="\l* If vdev supports name service, it will create name service endpoint;\l* It will not return until the master set status to DRIVER READY\l"]; + s_rpmsg_rx_cb_comment [label="\l* It will look for the endpoint which matches the destination address.\lIf the two endpoints hasn't binded yet,\lit will set the local endpoint's destination address with the source address in the message\l"]; + } + + master -> m_remoteproc_init [dir="none"]; + slave -> s_remoteproc_init [dir="none"]; + s_rpmsg_create_ep -> m_rpmsg_ns_cb [label="NS annoucement"]; + m_rpmsg_create_ep -> s_rpmsg_ns_cb [label="NS annoucement"]; + m_rpmsg_send -> s_rpmsg_rx_cb [label="RPMsg data"]; + s_rpmsg_send -> m_rpmsg_rx_cb [label="RPMsg data"]; + m_rpmsg_destroy_ep -> s_rpmsg_ns_unbind_cb [label="Endpoint destroy NS"]; + + m_remoteproc_init_comment -> m_remoteproc_init [dir="none"]; + m_remoteproc_boot_comment -> m_remoteproc_boot [dir="none"]; + m_rpmsg_vdev_init_comment -> m_rpmsg_vdev_init [dir="none"]; + m_rpmsg_create_ep_comment -> m_rpmsg_create_ep [dir="none"]; + m_rpmsg_send_comment -> m_rpmsg_send [dir="none"]; + + s_rpmsg_vdev_init -> s_rpmsg_vdev_init_comment [dir="none"]; + s_rpmsg_rx_cb -> s_rpmsg_rx_cb_comment [dir="none"]; + + {rank=same; master; m_remoteproc_init} + {rank=same; slave; s_remoteproc_init} + +} + diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-ns.gv b/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-ns.gv new file mode 100644 index 00000000000000..6c9e10f3b10b9e --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-ns.gv @@ -0,0 +1,95 @@ +// RPMsg dynamic endpoints binding + +digraph G { + rankdir="LR"; + + subgraph roles { + node [style="filled", fillcolor="lightblue"]; + master [label="Master"]; + slave [label="Slave"]; + } + + subgraph m_comment_nodes { + node [group=m_comment, shape="note", style="filled", fillcolor="yellow"]; + rank="same"; + m_remoteproc_init_comment [label="this is initialize rproc call"]; + m_remoteproc_boot_comment [label="it will setup vdev before booting the remote"]; + m_rpmsg_vdev_init_comment [label="\l* It will initialize vrings with the shared memory\l* As vdev doesn't support name service, it will not create name service endpoint;\l* it sets vdev status to DRVIER_READY, And will notify remote.\l"]; + m_rpmsg_create_ep_comment [label="\lIf vdev supports name service,\lit will send out name service.\l"]; + m_rpmsg_send_comment [label="\lIf endpoint hasn't binded, it fail\lreturn failure to indicate ep hasn't been binded.\l"]; + + } + + subgraph m_flow_nodes { + node [shape="box"]; + rank="same"; + m_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"] + m_remoteproc_load [label="calls remoteproc_load() to load applicaiton"]; + m_remoteproc_boot [shape="box", label="ret=remoteproc_boot(&rproc)"]; + m_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, MASTER, NULL);"]; + m_rpmsg_shmpool_init[label="rpmsg_virtio_init_shm_pool(shpool, shbuf, shbuf_pool_size);"]; + m_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, shpool);"]; + m_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, call ns_bind_cb.\l"]; + m_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"]; + m_rpmsg_send [label="rpmsg_send(ept,data)"]; + m_rpmsg_rx_cb [label="rpmsg_rx_callback()"]; + m_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"]; + m_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"]; + + m_remoteproc_init -> m_remoteproc_load -> m_remoteproc_boot -> m_remoteproc_get_vdev -> + m_rpmsg_shmpool_init -> m_rpmsg_vdev_init -> m_rpmsg_ns_cb -> m_rpmsg_create_ep -> m_rpmsg_send; + m_rpmsg_send -> m_rpmsg_rx_cb -> m_ep_cb -> + m_rpmsg_destroy_ep [dir="none", style="dashed"]; + } + + subgraph s_flow_nodes { + rank="same"; + node [shape="box"]; + s_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"]; + + s_remoteproc_parse_rsc [label="ret = remoteproc_set_rsc_table(rproc, &rsc_table, rsc_size)"]; + s_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, SLAVE, rst_cb);"]; + s_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, NULL);"]; + s_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"]; + s_rpmsg_ns_cb [label="\lrpmsg_ns_callback() will see if there is a local ep registered.\lIf yes, bind the ep; otherwise, call ns_binc_cb.\l"]; + s_rpmsg_send [label="rpmsg_send(ept,data)"]; + s_rpmsg_rx_cb [label="rpmsg_rx_callback()"]; + s_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"]; + s_rpmsg_ns_unbind_cb [label="\lrpmsg_ns_callback() will call the previous\lregistered endpoint unbind callback\l"]; + + s_remoteproc_init -> s_remoteproc_parse_rsc -> s_remoteproc_get_vdev -> + s_rpmsg_vdev_init -> s_rpmsg_create_ep; + s_rpmsg_create_ep -> s_rpmsg_ns_cb -> s_rpmsg_rx_cb -> + s_ep_cb -> s_rpmsg_send -> s_rpmsg_ns_unbind_cb [dir="none", style="dash"]; + + } + + subgraph s_comment_nodes { + node [group=s_comment, shape="note", style="filled", fillcolor="yellow"]; + rank="same"; + s_rpmsg_vdev_init_comment [label="\l* If vdev supports name service, it will create name service endpoint;\l* It will not return until the master set status to DRIVER READY\l"]; + s_rpmsg_rx_cb_comment [label="\l* It will look for the endpoint which matches the destination address.\lIf the two endpoints hasn't binded yet,\lit will set the local endpoint's destination address with the source address in the message\l"]; + } + + master -> m_remoteproc_init [dir="none"]; + slave -> s_remoteproc_init [dir="none"]; + s_rpmsg_create_ep -> m_rpmsg_ns_cb [label="NS annoucement"]; + m_rpmsg_create_ep -> s_rpmsg_ns_cb [label="NS annoucement"]; + m_rpmsg_send -> s_rpmsg_rx_cb [label="RPMsg data"]; + s_rpmsg_send -> m_rpmsg_rx_cb [label="RPMsg data"]; + m_rpmsg_destroy_ep -> s_rpmsg_ns_unbind_cb [label="Endpoint destroy NS"]; + + m_remoteproc_init_comment -> m_remoteproc_init [dir="none"]; + m_remoteproc_boot_comment -> m_remoteproc_boot [dir="none"]; + m_rpmsg_vdev_init_comment -> m_rpmsg_vdev_init [dir="none"]; + m_rpmsg_create_ep_comment -> m_rpmsg_create_ep [dir="none"]; + m_rpmsg_send_comment -> m_rpmsg_send [dir="none"]; + + s_rpmsg_vdev_init -> s_rpmsg_vdev_init_comment [dir="none"]; + s_rpmsg_rx_cb -> s_rpmsg_rx_cb_comment [dir="none"]; + + {rank=same; master; m_remoteproc_init} + {rank=same; slave; s_remoteproc_init} + +} + diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-static-ep.gv b/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-static-ep.gv new file mode 100644 index 00000000000000..ec95744ace20de --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/img-src/coprocessor-rpmsg-static-ep.gv @@ -0,0 +1,87 @@ +// RPMsg static endpoints + +digraph G { + rankdir="LR"; + + subgraph roles { + node [style="filled", fillcolor="lightblue"]; + master [label="Master"]; + slave [label="Slave"]; + } + + subgraph m_comment_nodes { + node [group=m_comment, shape="note", style="filled", fillcolor="yellow"]; + rank="same"; + m_remoteproc_init_comment [label="this is initialize rproc call"]; + m_remoteproc_boot_comment [label="it will setup vdev before booting the remote"]; + m_rpmsg_vdev_init_comment [label="\l* It will initialize vrings with the shared memory\l* As vdev doesn't support name service, it will not create name service endpoint;\l* it sets vdev status to DRVIER_READY, And will notify remote.\l"]; + m_rpmsg_create_ep_comment [label="\lAs vdev doesn't supports name service,\lit will not send out name service.\l"]; + } + + subgraph m_flow_nodes { + node [shape="box"]; + rank="same"; + m_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"]; + m_remoteproc_load [label="calls remoteproc_load() to load applicaiton"]; + m_remoteproc_boot [shape="box", label="ret=remoteproc_boot(&rproc)"]; + m_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, MASTER, NULL);"]; + m_rpmsg_shmpool_init[label="rpmsg_virtio_init_shm_pool(shpool, shbuf, shbuf_pool_size);"]; + m_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, shpool);"]; + m_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"]; + m_rpmsg_send [label="rpmsg_send(ept,data)"]; + m_rpmsg_rx_cb [label="rpmsg_rx_callback()"]; + m_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"]; + m_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"]; + + m_remoteproc_init -> m_remoteproc_load -> m_remoteproc_boot -> m_remoteproc_get_vdev -> + m_rpmsg_shmpool_init -> m_rpmsg_vdev_init -> m_rpmsg_create_ep -> m_rpmsg_send; + m_rpmsg_send -> m_rpmsg_rx_cb -> m_ep_cb -> + m_rpmsg_destroy_ep [dir="none", style="dashed"]; + } + + subgraph s_flow_nodes { + rank="same"; + node [shape="box"]; + s_remoteproc_init [label="rproc = remoteproc_init(&remoteproc_ops, &arg);"]; + + s_remoteproc_parse_rsc [label="ret = remoteproc_set_rsc_table(rproc, &rsc_table, rsc_size)"]; + s_remoteproc_get_vdev [label="vdev=remoteproc_create_virtio(rproc, rpmsg_vdev_id, SLAVE, rst_cb);"]; + s_rpmsg_vdev_init [label="rpdev=rpmsg_init_vdev(rpvdev, vdev, ns_bind_cb, &shm_io, NULL);"]; + s_rpmsg_create_ep [label="\lept=rpmsg_create_ept(ept, rdev, ept_name, ept_addr, dest_addr, \lendpoint_cb, ns_unbind_cb);\l"]; + s_rpmsg_send [label="rpmsg_send(ept,data)"]; + s_rpmsg_rx_cb [label="rpmsg_rx_callback()"]; + s_ep_cb [label="endpoint_cb(ept, data, size, src_addr)"]; + s_rpmsg_destroy_ep [label="rpmsg_destroy_endpoint(ept)"]; + + s_remoteproc_init -> s_remoteproc_parse_rsc -> s_remoteproc_get_vdev -> + s_rpmsg_vdev_init -> s_rpmsg_create_ep; + s_rpmsg_create_ep -> s_rpmsg_rx_cb -> + s_ep_cb -> s_rpmsg_send -> s_rpmsg_destroy_ep [dir="none", style="dash"]; + + } + + subgraph s_comment_nodes { + node [group=s_comment, shape="note", style="filled", fillcolor="yellow"]; + rank="same"; + s_rpmsg_vdev_init_comment [label="\l* As vdev doesn't support name service, it will not create name service endpoint;\l* It will not return until the master set status to DRIVER READY\l"]; + s_rpmsg_rx_cb_comment [label="\l* It will look for the endpoint which matches the destination address.\lIf no endpoint has found, it will drop the message.\l"]; + } + + master -> m_remoteproc_init [dir="none"]; + slave -> s_remoteproc_init [dir="none"]; + m_rpmsg_send -> s_rpmsg_rx_cb [label="RPMsg data"]; + s_rpmsg_send -> m_rpmsg_rx_cb [label="RPMsg data"]; + + m_remoteproc_init_comment -> m_remoteproc_init [dir="none"]; + m_remoteproc_boot_comment -> m_remoteproc_boot [dir="none"]; + m_rpmsg_vdev_init_comment -> m_rpmsg_vdev_init [dir="none"]; + m_rpmsg_create_ep_comment -> m_rpmsg_create_ep [dir="none"]; + + s_rpmsg_vdev_init -> s_rpmsg_vdev_init_comment [dir="none"]; + s_rpmsg_rx_cb -> s_rpmsg_rx_cb_comment [dir="none"]; + + {rank=same; master; m_remoteproc_init} + {rank=same; slave; s_remoteproc_init} + +} + diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img-src/gen-graph.py b/ext/lib/ipc/open-amp/open-amp/docs/img-src/gen-graph.py new file mode 100644 index 00000000000000..28871b4a295f34 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/img-src/gen-graph.py @@ -0,0 +1,56 @@ +from graphviz import Digraph +import argparse +import os +import pydot +import sys +import warnings + +def gen_graph_from_gv(ifile, odir, oformat="png"): + (graph,) = pydot.graph_from_dot_file(ifile) + gen_graph_func = getattr(graph, "write_" + oformat) + filename = os.path.basename(ifile) + ofile = odir + "/" + os.path.splitext(filename)[0] + "." + oformat + gen_graph_func(ofile) + +parser = argparse.ArgumentParser(description='Process some integers.') +parser.add_argument('-i', "--infile", action="append", + help="graphviz file path") +parser.add_argument('-o', '--outdir', + help='sum the integers (default: find the max)') +parser.add_argument('-f', '--outformat', default="png", + help='output image format (default: png)') + +args = parser.parse_args() + +# Image source directory +img_src_dir = os.path.dirname(os.path.realpath(sys.argv[0])) + +img_files = [] +if args.infile: + for f in args.infile: + if not os.path.isfile(f): + f = img_src_dir + "/" + f + if not os.path.isfile(f): + warnings.warn("Input file: " + f + " doesn't exist.") + else: + img_files.append(f) +else: + for f in os.listdir(img_src_dir): + if f.endswith(".gv"): + img_files.append(img_src_dir + "/" + f) + +if not img_files: + sys.exist("ERROR: no found image files.") + +oformat = args.outformat + +if args.outdir: + odir = args.outdir + if not os.path.isdir(odir): + sys.exit("--outdir " + odir + "doesn't exist") +else: + odir = os.path.dirname(img_src_dir) + "/img" + +for f in img_files: + print("Generating " + oformat + " for " + f + " ...") + gen_graph_from_gv(f, odir, oformat) diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img-src/rproc-lcm-state-machine.gv b/ext/lib/ipc/open-amp/open-amp/docs/img-src/rproc-lcm-state-machine.gv new file mode 100644 index 00000000000000..1faab828424d75 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/img-src/rproc-lcm-state-machine.gv @@ -0,0 +1,19 @@ +// Remoteproc Life Cycle Management State Machine + +digraph G { + rankdir="LR" + st_offline [label="Offline"] + st_configured [label="Configured"] + st_ready [label="Ready"] + st_running [label="Running"] + st_stopped [label="Stopped"] + + st_offline -> st_configured + st_configured -> st_ready + st_ready -> st_running + st_ready -> st_stopped + st_stopped -> st_offline + st_running -> st_stopped + + {rank=same; st_configured; st_ready; st_running} +} diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-ns-dynamic.png b/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-ns-dynamic.png new file mode 100644 index 00000000000000..7fe1602486a933 Binary files /dev/null and b/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-ns-dynamic.png differ diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-ns.png b/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-ns.png new file mode 100644 index 00000000000000..4c330d065a8159 Binary files /dev/null and b/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-ns.png differ diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-static-ep.png b/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-static-ep.png new file mode 100644 index 00000000000000..473206991fe1b8 Binary files /dev/null and b/ext/lib/ipc/open-amp/open-amp/docs/img/coprocessor-rpmsg-static-ep.png differ diff --git a/ext/lib/ipc/open-amp/open-amp/docs/img/rproc-lcm-state-machine.png b/ext/lib/ipc/open-amp/open-amp/docs/img/rproc-lcm-state-machine.png new file mode 100644 index 00000000000000..7e8a9d25a1c672 Binary files /dev/null and b/ext/lib/ipc/open-amp/open-amp/docs/img/rproc-lcm-state-machine.png differ diff --git a/ext/lib/ipc/open-amp/open-amp/docs/remoteproc-design.md b/ext/lib/ipc/open-amp/open-amp/docs/remoteproc-design.md new file mode 100644 index 00000000000000..e93f8d5c76cc86 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/remoteproc-design.md @@ -0,0 +1,103 @@ +# Remoteproc Design Document +Remoteproc provides abstraction to manage the life cycle of a remote +application. For now, it only provides APIs on bringing up and +tearing down the remote application, and parsing resource table. +It will extend to crash detection, suspend and resume. + +## Remoteproc LCM States +| State | State Description | +|:------|:------------------| +| Offline | Initial state of a remoteproc instance. The remote presented by the remoteproc instance and its resource has been powered off. | +| Configured | The remote presented by the remoteproc instance has been configured. And ready to load applicaiton. | +| Ready | The remote presented by the remoteproc instance has applicaiton loaded, and ready to run. | +| Stopped | The remote presented by the remoteproc instance has stopped from running. But the remote is still powered on. And the remote's resource hasn't been released. | + +![Rproc LCM States](img/rproc-lcm-state-machine.png) + +### State Transition +| State Transition | Transition Trigger | +|:-----------------|:-------------------| +| Offline -> Configured | Configure the remote to make it able to load application;
`remoteproc_configure(&rproc, &config_data)`| +| Configured -> Ready | load firmware ;
`remoteproc_load(&rproc, &path, &image_store, &image_store_ops, &image_info)` | +| Ready -> Running | start the processor;
`remoteproc_start(&rproc)` | +| Ready -> Stopped | stop the processor;
`remoteproc_stop(&rproc)`;
`remoteproc_shutdown(&rproc)`(Stopped is the intermediate state of shutdown operation) | +| Running -> Stopped | stop the processor;
`remoteproc_stop(&rproc)`;
`remoteproc_shutdown(&rproc)` | +| Stopped -> Offline | shutdown the processor;
`remoteproc_shutdown(&rproc)` | + +## Remote User APIs +* Initialize remoteproc instance: + ``` + struct remoteproc *remoteproc_init(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *priv) + ``` +* Release remoteproc instance: + ``` + int remoteproc_remove(struct remoteproc *rproc) + ``` +* Add memory to remoteproc: + ``` + void remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem) + ``` +* Get memory libmetal I/O region from remoteproc specifying memory name: + ``` + struct metal_io_region *remoteproc_get_io_with_name(struct remoteproc *rproc, const char *name) + ``` +* Get memory libmetal I/O region from remoteproc specifying physical address: + ``` + struct metal_io_region *remoteproc_get_io_with_pa(struct remoteproc *rproc, metal_phys_addr_t pa); + ``` +* Get memory libmetal I/O region from remoteproc specifying virtual address: + ``` + struct metal_io_region *remoteproc_get_io_with_va(struct remoteproc *rproc, void *va); + ``` +* Map memory and add the memory to the remoteproc instance: + ``` + void *remoteproc_mmap(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io); + ``` +* Set resource table to remoteproc: + ``` + int remoteproc_set_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size) + ``` +* Configure the remote presented by the remoteproc instance to make it able + to load applicaiton: + ``` + int remoteproc_config(struct remoteproc *rproc, void *data) + ``` +* Load application to the remote presented by the remoteproc instance to make + it ready to run: + ``` + int remoteproc_load(struct remoteproc *rproc, const char *path, + void *store, struct image_store_ops *store_ops, + void **img_info) + ``` +* Run application on the remote presented by the remoteproc instance: + ``` + int remoteproc_start(struct remoteproc *rproc) + ``` +* Stop application on remote presented by the remoteproc instance: + ``` + int remoteproc_stop(struct remoteproc *rproc) + ``` +* Shutdown the remote presented by the remoteproc instance: + ``` + int remoteproc_shutdown(struct remoteproc *rproc) + ``` +* Create virtio device from the resource table vdev resource, and add it to the + remoteproc instance: + ``` + struct virtio_device *remoteproc_create_virtio(struct remoteproc *rproc, + int vdev_id, unsigned int role, + void (*rst_cb)(struct virtio_device *vdev)) + ``` +* Remove virtio device from the remoteproc instance: + ``` + void remoteproc_remove_virtio(struct remoteproc *rproc, + struct virtio_device *vdev) + ``` + + diff --git a/ext/lib/ipc/open-amp/open-amp/docs/rpmsg-design.md b/ext/lib/ipc/open-amp/open-amp/docs/rpmsg-design.md new file mode 100644 index 00000000000000..206ee020ab3767 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/docs/rpmsg-design.md @@ -0,0 +1,109 @@ +# RPMsg Design Document +RPMsg is a framework to allow communication between two processors. +RPMsg implementation in OpenAMP library is based on virtio. It complies +the RPMsg Linux kernel implementation. It defines the handshaking on +setting up and tearing down the communication between applicaitons +running on two processors. + +## RPMsg User API Flow Chats +### RPMsg Static Endpoint +![Static Endpoint](img/coprocessor-rpmsg-static-ep.png) +### Binding Endpoint Dynamically with Name Service +![Binding Endpoint Dynamically with Name Service](img/coprocessor-rpmsg-ns.png) +### Creating Endpoint Dynamically with Name Service +![Creating Endpoint Dynamically with Name Service](img/coprocessor-rpmsg-ns-dynamic.png) + +## RPMsg User APIs +* RPMsg virtio master to initialize the shared buffers pool(RPMsg virtio slave + doesn't need to use this API): + ``` + void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, + void *shbuf, size_t size) + ``` +* Initialize RPMsg virtio device: + ``` + int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool) + ``` +* Deinitialize RPMsg virtio device: + ``` + void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev)` + ``` +* Get RPMsg device from RPMsg virtio device: + ``` + struct rpmsg_device *rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev) + ``` +* Create RPMsg endpoint: + ``` + int rpmsg_create_ept(struct rpmsg_endpoint *ept, + struct rpmsg_device *rdev, + const char *name, uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, rpmsg_ns_unbind_cb ns_unbind_cb) + ``` +* Destroy RPMsg endpoint: + ``` + void rpmsg_destroy_ept(struct rpsmg_endpoint *ept) + ``` +* Check if the local RPMsg endpoint is binded to the remote, and ready to send + message: + ``` + int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept) + ``` +* Send message with RPMsg endpoint default binding: + ``` + int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, int len) + ``` +* Send message with RPMsg endpoint, specify destination address: + ``` + int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, + uint32_t dst) + ``` +* Send message with RPMsg endpoint using explicit source and destination + addresses: + ``` + int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, + uint32_t src, uint32_t dst, + const void *data, int len) + ``` +* Try to send message with RPMsg endpoint default binding, if no buffer + available, returns: + ``` + int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data, + int len) + ``` +* Try to send message with RPMsg endpoint, specify destination address, + if no buffer available, returns: + ``` + int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, + uint32_t dst) + ``` +* Try to send message with RPMsg endpoint using explicit source and destination + addresses, if no buffer available, returns: + ``` + int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, + uint32_t src, uint32_t dst, + const void *data, int len)` + ``` +## RPMsg User Defined Callbacks +* RPMsg endpoint message received callback: + ``` + int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data, + size_t len, uint32_t src, void *priv) + ``` +* RPMsg name service binding callback. If user defines such callback, when + there is a name service announcement arrives, if there is no registered + endpoint found to bind to this name service, it will call this callback. + If this callback is not defined, it will drop this name service.: + ``` + void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev, + const char *name, uint32_t dest) + ``` +* RPMsg endpoint name service unbind callback. If user defines such callback, + when there is name service destroy arrives, it will call this callback to + notify the user application about the remote has destroyed the service.: + ``` + void (*rpmsg_ns_unbind_cb)(struct rpmsg_endpoint *ept) + ``` diff --git a/ext/lib/ipc/open-amp/open-amp/lib/CMakeLists.txt b/ext/lib/ipc/open-amp/open-amp/lib/CMakeLists.txt index a2eb1d2d515fa5..2be5b86b0d9a3e 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/CMakeLists.txt +++ b/ext/lib/ipc/open-amp/open-amp/lib/CMakeLists.txt @@ -6,7 +6,6 @@ collect (PROJECT_LIB_DIRS "${CMAKE_CURRENT_BINARY_DIR}") collect (PROJECT_INC_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include") -add_subdirectory (common) add_subdirectory (virtio) add_subdirectory (rpmsg) add_subdirectory (remoteproc) diff --git a/ext/lib/ipc/open-amp/open-amp/lib/common/CMakeLists.txt b/ext/lib/ipc/open-amp/open-amp/lib/common/CMakeLists.txt deleted file mode 100644 index 87d05aff1f7a39..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/common/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -collect (PROJECT_LIB_SOURCES hil.c) -collect (PROJECT_LIB_SOURCES sh_mem.c) -collect (PROJECT_LIB_SOURCES firmware.c) diff --git a/ext/lib/ipc/open-amp/open-amp/lib/common/firmware.c b/ext/lib/ipc/open-amp/open-amp/lib/common/firmware.c deleted file mode 100644 index 4dff85ce9548bf..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/common/firmware.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * firmware.c - * - * COMPONENT - * - * OpenAMP stack. - * - * DESCRIPTION - * - * - **************************************************************************/ - -#include -#include - -/** - * config_get_firmware - * - * Searches the given firmware in firmware table list and provides - * it to caller. - * - * @param fw_name - name of the firmware - * @param start_addr - pointer t hold start address of firmware - * @param size - pointer to hold size of firmware - * - * returns - status of function execution - * - */ - -extern struct firmware_info fw_table[]; -extern int fw_table_size; - -int config_get_firmware(char *fw_name, uintptr_t *start_addr, - unsigned int *size) -{ - int idx; - for (idx = 0; idx < fw_table_size; idx++) { - if (!strncmp((char *)fw_table[idx].name, fw_name, sizeof(fw_table[idx].name))) { - *start_addr = fw_table[idx].start_addr; - *size = - fw_table[idx].end_addr - fw_table[idx].start_addr + - 1; - return 0; - } - } - return -1; -} diff --git a/ext/lib/ipc/open-amp/open-amp/lib/common/hil.c b/ext/lib/ipc/open-amp/open-amp/lib/common/hil.c deleted file mode 100644 index bd6546865839cd..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/common/hil.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * hil.c - * - * COMPONENT - * - * OpenAMP Stack. - * - * DESCRIPTION - * - * This file is implementation of generic part of HIL. - * - * - * - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_VRING_MEM_SIZE 0x10000 -#define HIL_DEV_NAME_PREFIX "hil-dev." - -/*--------------------------- Globals ---------------------------------- */ -static METAL_DECLARE_LIST (procs); - -#if defined (OPENAMP_BENCHMARK_ENABLE) - -unsigned long long boot_time_stamp; -unsigned long long shutdown_time_stamp; - -#endif - -struct hil_mem_device { - struct metal_device device; - char name[64]; - metal_phys_addr_t pa; -}; - -metal_phys_addr_t hil_generic_start_paddr = 0; - -static int hil_shm_block_write(struct metal_io_region *io, - unsigned long offset, - const void *restrict src, - memory_order order, - int len) -{ - void *va = metal_io_virt(io, offset); - - (void)order; - memcpy(va, src, len); - metal_cache_flush(va, (unsigned int)len); - return len; -} - -static void hil_shm_block_set(struct metal_io_region *io, - unsigned long offset, - unsigned char value, - memory_order order, - int len) -{ - void *va = metal_io_virt(io, offset); - - (void)order; - memset(va, (int)value, len); - metal_cache_flush(va, (unsigned int)len); -} - -static struct metal_io_region hil_shm_generic_io = { - 0, - &hil_generic_start_paddr, - (size_t)(-1), - (sizeof(metal_phys_addr_t) << 3), - (metal_phys_addr_t)(-1), - 0, - {NULL, NULL, - NULL, hil_shm_block_write, hil_shm_block_set, NULL}, -}; - -struct metal_device *hil_create_generic_mem_dev( - metal_phys_addr_t pa, - size_t size, unsigned int flags) -{ - struct hil_mem_device *dev; - struct metal_device *mdev; - int ret; - - /* If no generic bus is found in libmetal - * there is no need to create the generic device - */ - ret = metal_bus_find("generic", NULL); - if (ret) - return NULL; - dev = metal_allocate_memory(sizeof(*dev)); - metal_assert(dev); - memset(dev, 0, sizeof(*dev)); - sprintf(dev->name, "%s%lx.%lx", HIL_DEV_NAME_PREFIX, pa, - (unsigned long)size); - dev->pa = pa; - mdev = &dev->device; - mdev->name = dev->name; - mdev->num_regions = 1; - metal_io_init(&mdev->regions[0], (void *)pa, &dev->pa, size, - sizeof(pa) << 3, flags, NULL); - - ret = metal_register_generic_device(mdev); - metal_assert(!ret); - ret = metal_device_open("generic", dev->name, &mdev); - metal_assert(!ret); - - return mdev; -} - -void hil_close_generic_mem_dev(struct metal_device *dev) -{ - struct hil_mem_device *mdev; - - if (strncmp(HIL_DEV_NAME_PREFIX, dev->name, - strlen(HIL_DEV_NAME_PREFIX))) { - metal_device_close(dev); - } else { - metal_list_del(&dev->node); - mdev = metal_container_of(dev, struct hil_mem_device, device); - metal_free_memory(mdev); - } -} - -static struct metal_io_region *hil_get_mem_io( - struct metal_device *dev, - metal_phys_addr_t pa, - size_t size) -{ - struct metal_io_region *io; - unsigned int i; - - for (i = 0; i < dev->num_regions; i++) { - io = &dev->regions[i]; - if (!pa && io->size >= size) - return io; - if (metal_io_phys_to_offset(io, pa) == METAL_BAD_OFFSET) - continue; - if (metal_io_phys_to_offset(io, (pa + size)) == - METAL_BAD_OFFSET) - continue; - return io; - } - - return NULL; -} - -struct hil_proc *hil_create_proc(struct hil_platform_ops *ops, - unsigned long cpu_id, void *pdata) -{ - struct hil_proc *proc = 0; - - proc = metal_allocate_memory(sizeof(struct hil_proc)); - if (!proc) - return NULL; - memset(proc, 0, sizeof(struct hil_proc)); - - proc->ops = ops; - proc->num_chnls = 1; - proc->cpu_id = cpu_id; - proc->pdata = pdata; - - /* Setup generic shared memory I/O region */ - proc->sh_buff.io = &hil_shm_generic_io; - - metal_mutex_init(&proc->lock); - metal_list_add_tail(&procs, &proc->node); - - return proc; -} - -/** - * hil_delete_proc - * - * This function deletes the given proc instance and frees the - * associated resources. - * - * @param proc - pointer to hil remote_proc instance - * - */ -void hil_delete_proc(struct hil_proc *proc) -{ - struct metal_list *node; - struct metal_device *dev; - struct metal_io_region *io; - struct proc_vring *vring; - int i; - - metal_list_for_each(&procs, node) { - if (proc == - metal_container_of(node, struct hil_proc, node)) { - metal_list_del(&proc->node); - metal_mutex_acquire(&proc->lock); - proc->ops->release(proc); - /* Close shmem device */ - dev = proc->sh_buff.dev; - io = proc->sh_buff.io; - if (dev) - proc->ops->release_shm(proc, dev, io); - else if (io && io->ops.close) - io->ops.close(io); - - /* Close resource table device */ - dev = proc->rsc_dev; - io = proc->rsc_io; - if (dev) - proc->ops->release_shm(proc, dev, io); - else if (io && io->ops.close) - io->ops.close(io); - - /* Close vring device */ - for (i = 0; i < HIL_MAX_NUM_VRINGS; i++) { - vring = &proc->vdev.vring_info[i]; - dev = vring->dev; - io = vring->io; - if (dev) - proc->ops->release_shm(proc, dev, io); - else if (io && io->ops.close) - io->ops.close(io); - } - - metal_mutex_release(&proc->lock); - metal_mutex_deinit(&proc->lock); - metal_free_memory(proc); - return; - } - } -} - -int hil_init_proc(struct hil_proc *proc) -{ - int ret = 0; - if (!proc->is_initialized && proc->ops->initialize) { - ret = proc->ops->initialize(proc); - if (!ret) - proc->is_initialized = 1; - else - return -1; - } - return 0; -} - -/** - * hil_get_chnl_info - * - * This function returns channels info for given proc. - * - * @param proc - pointer to proc info struct - * @param num_chnls - pointer to integer variable to hold - * number of available channels - * - * @return - pointer to channel info control block - * - */ -struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc, int *num_chnls) -{ - *num_chnls = proc->num_chnls; - return (proc->chnls); -} - -void hil_notified(struct hil_proc *proc, uint32_t notifyid) -{ - struct proc_vdev *pvdev = &proc->vdev; - struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info; - int i; - if (vdev_rsc->status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) { - if (pvdev->rst_cb) - pvdev->rst_cb(proc, 0); - } else { - for(i = 0; i < (int)pvdev->num_vrings; i++) { - struct fw_rsc_vdev_vring *vring_rsc; - vring_rsc = &vdev_rsc->vring[i]; - if (notifyid == (uint32_t)(-1) || - notifyid == vring_rsc->notifyid) - virtqueue_notification( - pvdev->vring_info[i].vq); - } - } -} - -/** - * hil_get_vdev_info - * - * This function return virtio device for remote core. - * - * @param proc - pointer to remote proc - * - * @return - pointer to virtio HW device. - * - */ - -struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc) -{ - return (&proc->vdev); - -} - -/** - * hil_get_vring_info - * - * This function returns vring_info_table. The caller will use - * this table to get the vring HW info which will be subsequently - * used to create virtqueues. - * - * @param vdev - pointer to virtio HW device - * @param num_vrings - pointer to hold number of vrings - * - * @return - pointer to vring hardware info table - */ -struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings) -{ - struct fw_rsc_vdev *vdev_rsc; - struct fw_rsc_vdev_vring *vring_rsc; - struct proc_vring *vring; - int i, ret; - - vdev_rsc = vdev->vdev_info; - *num_vrings = vdev->num_vrings; - if (vdev_rsc) { - vring = &vdev->vring_info[0]; - for (i = 0; i < vdev_rsc->num_of_vrings; i++) { - struct hil_proc *proc = metal_container_of( - vdev, struct hil_proc, vdev); - void *vaddr = METAL_BAD_VA; - - /* Initialize vring with vring resource */ - vring_rsc = &vdev_rsc->vring[i]; - vring[i].num_descs = vring_rsc->num; - vring[i].align = vring_rsc->align; - /* Check if vring needs to reinitialize. - * Vring needs reinitialization if the vdev - * master restarts. - */ - if (vring[i].io) { - vaddr = metal_io_phys_to_virt(vring[i].io, - (metal_phys_addr_t)vring_rsc->da); - } - if (vaddr == (void *)METAL_BAD_VA) { - ret = hil_set_vring(proc, i, NULL, NULL, - (metal_phys_addr_t)vring_rsc->da, - vring_size(vring_rsc->num, - vring_rsc->align)); - if (ret) - return NULL; - vaddr = metal_io_phys_to_virt(vring[i].io, - (metal_phys_addr_t)vring_rsc->da); - } - vring[i].vaddr = vaddr; - } - } - return (vdev->vring_info); -} - -/** - * hil_get_shm_info - * - * This function returns shared memory info control block. The caller - * will use this information to create and manage memory buffers for - * vring descriptor table. - * - * @param proc - pointer to proc instance - * - * @return - pointer to shared memory region used for buffers - * - */ -struct proc_shm *hil_get_shm_info(struct hil_proc *proc) -{ - return (&proc->sh_buff); -} - -void hil_free_vqs(struct virtio_device *vdev) -{ - struct hil_proc *proc = vdev->device; - struct proc_vdev *pvdev = &proc->vdev; - int num_vrings = (int)pvdev->num_vrings; - int i; - - metal_mutex_acquire(&proc->lock); - for(i = 0; i < num_vrings; i++) { - struct proc_vring *pvring = &pvdev->vring_info[i]; - struct virtqueue *vq = pvring->vq; - if (vq) { - virtqueue_free(vq); - pvring->vq = 0; - } - } - metal_mutex_release(&proc->lock); -} - -int hil_enable_vdev_notification(struct hil_proc *proc, int id) -{ - /* We only support single vdev in hil_proc */ - (void)id; - if (!proc) - return -1; - if (proc->ops->enable_interrupt) - proc->ops->enable_interrupt(&proc->vdev.intr_info); - return 0; -} - -/** - * hil_enable_vring_notifications() - * - * This function is called after successful creation of virtqueues. - * This function saves queue handle in the vring_info_table which - * will be used during interrupt handling .This function setups - * interrupt handlers. - * - * @param vring_index - index to vring HW table - * @param vq - pointer to virtqueue to save in vring HW table - * - * @return - execution status - */ -int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq) -{ - struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device; - struct proc_vring *vring_hw = &proc_hw->vdev.vring_info[vring_index]; - /* Save virtqueue pointer for later reference */ - vring_hw->vq = vq; - - if (proc_hw->ops->enable_interrupt) { - proc_hw->ops->enable_interrupt(&vring_hw->intr_info); - } - - return 0; -} - -/** - * hil_vdev_notify() - * - * This function generates IPI to let the other side know that there is - * update in the vritio dev configs - * - * @param vdev - pointer to the viritio device - * - */ -void hil_vdev_notify(struct virtio_device *vdev) -{ - struct hil_proc *proc = vdev->device; - struct proc_vdev *pvdev = &proc->vdev; - - if (proc->ops->notify) { - proc->ops->notify(proc, &pvdev->intr_info); - } -} - -/** - * hil_vring_notify() - * - * This function generates IPI to let the other side know that there is - * job available for it. The required information to achieve this, like interrupt - * vector, CPU id etc is be obtained from the proc_vring table. - * - * @param vq - pointer to virtqueue - * - */ -void hil_vring_notify(struct virtqueue *vq) -{ - struct hil_proc *proc_hw = (struct hil_proc *)vq->vq_dev->device; - struct proc_vring *vring_hw = - &proc_hw->vdev.vring_info[vq->vq_queue_index]; - - if (proc_hw->ops->notify) { - proc_hw->ops->notify(proc_hw, &vring_hw->intr_info); - } -} - -/** - * hil_get_status - * - * This function is used to check if the given core is up and running. - * This call will return after it is confirmed that remote core has - * started. - * - * @param proc - pointer to proc instance - * - * @return - execution status - */ -int hil_get_status(struct hil_proc *proc) -{ - (void)proc; - - /* For future use only. */ - return 0; -} - -/** - * hil_set_status - * - * This function is used to update the status - * of the given core i.e it is ready for IPC. - * - * @param proc - pointer to remote proc - * - * @return - execution status - */ -int hil_set_status(struct hil_proc *proc) -{ - (void)proc; - - /* For future use only. */ - return 0; -} - -/** - * hil_boot_cpu - * - * This function boots the remote processor. - * - * @param proc - pointer to remote proc - * @param start_addr - start address of remote cpu - * - * @return - execution status - */ -int hil_boot_cpu(struct hil_proc *proc, unsigned int start_addr) -{ - - if (proc->ops->boot_cpu) { - proc->ops->boot_cpu(proc, start_addr); - } -#if defined (OPENAMP_BENCHMARK_ENABLE) - boot_time_stamp = metal_get_timestamp(); -#endif - - return 0; -} - -/** - * hil_shutdown_cpu - * - * This function shutdowns the remote processor - * - * @param proc - pointer to remote proc - * - */ -void hil_shutdown_cpu(struct hil_proc *proc) -{ - if (proc->ops->shutdown_cpu) { - proc->ops->shutdown_cpu(proc); - } -#if defined (OPENAMP_BENCHMARK_ENABLE) - shutdown_time_stamp = metal_get_timestamp(); -#endif -} - -/** - * hil_get_firmware - * - * This function returns address and size of given firmware name passed as - * parameter. - * - * @param fw_name - name of the firmware - * @param start_addr - pointer t hold start address of firmware - * @param size - pointer to hold size of firmware - * - * returns - status of function execution - * - */ -int hil_get_firmware(char *fw_name, uintptr_t *start_addr, - unsigned int *size) -{ - return (config_get_firmware(fw_name, start_addr, size)); -} - -int hil_poll (struct hil_proc *proc, int nonblock) -{ - return proc->ops->poll(proc, nonblock); -} - -int hil_set_shm (struct hil_proc *proc, - const char *bus_name, const char *name, - metal_phys_addr_t paddr, size_t size) -{ - struct metal_device *dev; - struct metal_io_region *io; - int ret; - - if (!proc) - return -1; - if (name && bus_name) { - ret = metal_device_open(bus_name, name, &dev); - if (ret) - return ret; - proc->sh_buff.dev = dev; - proc->sh_buff.io = NULL; - } else if (name) { - ret = metal_shmem_open(name, size, &io); - if (ret) - return ret; - proc->sh_buff.io = io; - } - if (!size) { - if (proc->sh_buff.io) { - io = proc->sh_buff.io; - proc->sh_buff.start_paddr = metal_io_phys(io, 0); - proc->sh_buff.size = io->size; - } else if (proc->sh_buff.dev) { - dev = proc->sh_buff.dev; - io = &dev->regions[0]; - proc->sh_buff.io = io; - proc->sh_buff.start_paddr = metal_io_phys(io, 0); - proc->sh_buff.size = io->size; - } - } else if (!paddr) { - if (proc->sh_buff.io) { - io = proc->sh_buff.io; - if (io->size != size) - return -1; - proc->sh_buff.start_paddr = metal_io_phys(io, 0); - proc->sh_buff.size = io->size; - } else if (proc->sh_buff.dev) { - dev = proc->sh_buff.dev; - io = &dev->regions[0]; - proc->sh_buff.io = io; - proc->sh_buff.start_paddr = metal_io_phys(io, 0); - proc->sh_buff.size = size; - } - } else { - if (proc->sh_buff.io) { - io = proc->sh_buff.io; - if (size > io->size) - return -1; - if (metal_io_phys_to_offset(io, paddr) == - METAL_BAD_OFFSET) - return -1; - proc->sh_buff.start_paddr = paddr; - proc->sh_buff.size = size; - } else if (proc->sh_buff.dev) { - dev = proc->sh_buff.dev; - io = hil_get_mem_io(dev, paddr, size); - if (!io) - return -1; - proc->sh_buff.io = io; - proc->sh_buff.start_paddr = metal_io_phys(io, 0); - proc->sh_buff.size = size; - } else { - io = proc->ops->alloc_shm(proc, paddr, size, &dev); - metal_assert(io); - proc->sh_buff.dev = dev; - proc->sh_buff.io = io; - proc->sh_buff.start_paddr = paddr; - proc->sh_buff.size = size; - } - } - proc->sh_buff.start_addr = metal_io_phys_to_virt(proc->sh_buff.io, - proc->sh_buff.start_paddr); - return 0; -} - -int hil_set_rsc (struct hil_proc *proc, - const char *bus_name, const char *name, - metal_phys_addr_t paddr, size_t size) -{ - struct metal_device *dev; - struct metal_io_region *io; - int ret; - - if (!proc) - return -1; - - if (name && bus_name) { - ret = metal_device_open(bus_name, name, &dev); - if (ret) - return ret; - proc->rsc_dev = dev; - io = hil_get_mem_io(dev, 0, size); - if (!io) - return -1; - proc->rsc_io = io; - } else if (name) { - ret = metal_shmem_open(name, size, &io); - if (ret) - return ret; - proc->rsc_io = io; - } else { - if (proc->rsc_dev || proc->rsc_io) - return 0; - io = proc->ops->alloc_shm(proc, paddr, size, &dev); - if (dev) { - proc->rsc_dev = dev; - proc->rsc_io = io; - } - } - - return 0; -} - -int hil_set_vring (struct hil_proc *proc, int index, - const char *bus_name, const char *name, - metal_phys_addr_t paddr, size_t size) -{ - struct metal_device *dev; - struct metal_io_region *io; - struct proc_vring *vring; - int ret; - - if (!proc) - return -1; - if (index >= HIL_MAX_NUM_VRINGS) - return -1; - vring = &proc->vdev.vring_info[index]; - if (name && bus_name) { - ret = metal_device_open(bus_name, name, &dev); - if (ret) - return ret; - vring->dev = dev; - } else if (name) { - ret = metal_shmem_open(name, size, &io); - if (ret) - return ret; - vring->io = io; - } else { - if (vring->dev) { - dev = vring->dev; - io = hil_get_mem_io(dev, paddr, size); - if (io) { - vring->io = io; - return 0; - } - proc->ops->release_shm(proc, dev, NULL); - } else if (vring->io) { - io = vring->io; - if (size <= io->size && - metal_io_phys_to_offset(io, paddr) != - METAL_BAD_OFFSET) - return 0; - } - io = proc->ops->alloc_shm(proc, paddr, size, &dev); - if (!io) - return -1; - vring->io = io;; - } - - return 0; -} - -int hil_set_vdev_ipi (struct hil_proc *proc, int index, - unsigned int irq, void *data) -{ - struct proc_intr *vring_intr; - - /* As we support only one vdev for now */ - (void)index; - - if (!proc) - return -1; - vring_intr = &proc->vdev.intr_info; - vring_intr->vect_id = irq; - vring_intr->data = data; - return 0; -} - -int hil_set_vring_ipi (struct hil_proc *proc, int index, - unsigned int irq, void *data) -{ - struct proc_intr *vring_intr; - - if (!proc) - return -1; - vring_intr = &proc->vdev.vring_info[index].intr_info; - vring_intr->vect_id = irq; - vring_intr->data = data; - return 0; -} - -int hil_set_rpmsg_channel (struct hil_proc *proc, int index, - char *name) -{ - if (!proc) - return -1; - if (index >= HIL_MAX_NUM_CHANNELS) - return -1; - strcpy(proc->chnls[index].name, name); - return 0; -} - -int hil_set_vdev_rst_cb (struct hil_proc *proc, int index, - hil_proc_vdev_rst_cb_t cb) -{ - (void)index; - proc->vdev.rst_cb = cb; - return 0; -} - diff --git a/ext/lib/ipc/open-amp/open-amp/lib/common/sh_mem.c b/ext/lib/ipc/open-amp/open-amp/lib/common/sh_mem.c deleted file mode 100644 index bd841cc47bb4f1..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/common/sh_mem.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -/************************************************************************** - * FILE NAME - * - * sh_mem.c - * - * COMPONENT - * - * OpenAMP stack. - * - * DESCRIPTION - * - * Source file for fixed buffer size memory management service. Currently - * it is only being used to manage shared memory. - * - **************************************************************************/ -#include -#include -#include - -/** - * sh_mem_create_pool - * - * Creates new memory pool with the given parameters. - * - * @param start_addr - start address of the memory region - * @param size - size of the memory - * @param buff_size - fixed buffer size - * - * @return - pointer to memory pool - * - */ -struct sh_mem_pool *sh_mem_create_pool(void *start_addr, unsigned int size, - unsigned int buff_size) -{ - struct sh_mem_pool *mem_pool; - int pool_size; - int num_buffs, bmp_size; - - if (!start_addr || !size || !buff_size) - return NULL; - - /* Word align the buffer size */ - buff_size = WORD_ALIGN(buff_size); - - /* Get number of buffers. */ - num_buffs = (size / buff_size) + ((size % buff_size) == 0 ? 0 : 1); - - /* - * Size of the bitmap required to maintain buffers info. One word(32 bit) can - * keep track of 32 buffers. - */ - bmp_size = (num_buffs / BITMAP_WORD_SIZE) - + ((num_buffs % BITMAP_WORD_SIZE) == 0 ? 0 : 1); - - /* Total size required for pool control block. */ - pool_size = sizeof(struct sh_mem_pool) + BITMAP_WORD_SIZE * bmp_size; - - /* Create pool control block. */ - mem_pool = metal_allocate_memory(pool_size); - - if (mem_pool) { - /* Initialize pool parameters */ - memset(mem_pool, 0x00, pool_size); - metal_mutex_init(&mem_pool->lock); - mem_pool->start_addr = start_addr; - mem_pool->buff_size = buff_size; - mem_pool->bmp_size = bmp_size; - mem_pool->total_buffs = num_buffs; - } - - return mem_pool; -} - -/** - * sh_mem_get_buffer - * - * Allocates fixed size buffer from the given memory pool. - * - * @param pool - pointer to memory pool - * - * @return - pointer to allocated buffer - * - */ -void *sh_mem_get_buffer(struct sh_mem_pool *pool) -{ - void *buff = NULL; - int bit_idx; - unsigned int idx; - - if (!pool) - return NULL; - - metal_mutex_acquire(&pool->lock); - - if (pool->used_buffs >= pool->total_buffs) { - metal_mutex_release(&pool->lock); - return NULL; - } - - for (idx = 0; idx < pool->bmp_size; idx++) { - /* - * Find the first 0 bit in the buffers bitmap. The 0th bit - * represents a free buffer. - */ - bit_idx = get_first_zero_bit( - *(unsigned long*)SH_MEM_POOL_LOCATE_BITMAP(pool,idx)); - if (bit_idx >= 0) { - /* Set bit to mark it as consumed. */ - *(unsigned long*)(SH_MEM_POOL_LOCATE_BITMAP(pool,idx)) - |= ((unsigned long)1 << (unsigned long)bit_idx); - buff = (char *)pool->start_addr + - pool->buff_size * (idx * BITMAP_WORD_SIZE + - bit_idx); - pool->used_buffs++; - break; - } - } - - metal_mutex_release(&pool->lock); - - return buff; -} - -/** - * sh_mem_free_buffer - * - * Frees the given buffer. - * - * @param pool - pointer to memory pool - * @param buff - pointer to buffer - * - * @return - none - */ -void sh_mem_free_buffer(void *buff, struct sh_mem_pool *pool) -{ - unsigned long *bitmask; - int bmp_idx, bit_idx, buff_idx; - - if (!pool || !buff) - return; - - /* Acquire the pool lock */ - metal_mutex_acquire(&pool->lock); - - /* Map the buffer address to its index. */ - buff_idx = ((char *)buff - (char *)pool->start_addr) / pool->buff_size; - - /* Translate the buffer index to bitmap index. */ - bmp_idx = buff_idx / BITMAP_WORD_SIZE; - bit_idx = buff_idx % BITMAP_WORD_SIZE; - bitmask = (unsigned long*)(SH_MEM_POOL_LOCATE_BITMAP(pool, bmp_idx)); - - /* Mark the buffer as free */ - *bitmask ^= (1 << bit_idx); - - pool->used_buffs--; - - /* Release the pool lock. */ - metal_mutex_release(&pool->lock); - -} - -/** - * sh_mem_delete_pool - * - * Deletes the given memory pool. - * - * @param pool - pointer to memory pool - * - * @return - none - */ -void sh_mem_delete_pool(struct sh_mem_pool *pool) -{ - - if (pool) { - metal_mutex_deinit(&pool->lock); - metal_free_memory(pool); - } -} - -/** - * get_first_zero_bit - * - * Provides position of first 0 bit in a 32 bit value - * - * @param value - given value - * - * @return - 0th bit position - */ -int get_first_zero_bit(unsigned long value) -{ - unsigned int idx = 0; - value = ((~value) & (value + 1)); - while (value) { - idx++; - value >>= 1; - } - return ((int)idx-1); -} diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/compiler.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/compiler.h index cfb630582e2eae..acb4c9b3699718 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/compiler.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/compiler.h @@ -57,7 +57,10 @@ extern "C" { #endif #else -/* There is no default definition here to avoid wrong structures packing in case of not supported compiler */ +/* + * There is no default definition here to avoid wrong structures packing in case + * of not supported compiler + */ #error Please implement the structure packing macros for your compiler here! #endif diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/elf_loader.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/elf_loader.h index 3d4cff891661da..3c6ec4af15385f 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/elf_loader.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/elf_loader.h @@ -8,23 +8,33 @@ #ifndef ELF_LOADER_H_ #define ELF_LOADER_H_ +#include #include #if defined __cplusplus extern "C" { #endif -/* ELF base types - 32-bit. */ -typedef uintptr_t Elf32_Addr; -typedef unsigned short Elf32_Half; -typedef unsigned int Elf32_Off; -typedef signed int Elf32_Sword; -typedef unsigned int Elf32_Word; +/* ELF32 base types - 32-bit. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* ELF64 base types - 64-bit. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; /* Size of ELF identifier field in the ELF file header. */ #define EI_NIDENT 16 -/* ELF file header */ +/* ELF32 file header */ typedef struct { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; @@ -40,9 +50,26 @@ typedef struct { Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; - } Elf32_Ehdr; +/* ELF64 file header */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + /* e_ident */ #define ET_NONE 0 #define ET_REL 1 /* Re-locatable file */ @@ -73,19 +100,30 @@ typedef struct { #define EI_PAD 9 /* Start of padding bytes */ #define EI_NIDENT 16 /* Size of e_ident[] */ -/* EI_MAG0 to EI_MAG3 - A file's first 4 bytes hold amagic number, identifying the file as an ELF object file */ -#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +/* + * EI_MAG0 to EI_MAG3 - A file's first 4 bytes hold amagic number, identifying + * the file as an ELF object file + */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ #define ELFMAG1 'E' /* e_ident[EI_MAG1] */ #define ELFMAG2 'L' /* e_ident[EI_MAG2] */ #define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 -/* EI_CLASS - The next byte, e_ident[EI_CLASS], identifies the file's class, or capacity. */ +/* + * EI_CLASS - The next byte, e_ident[EI_CLASS], identifies the file's class, or + * capacity. + */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ -/* EI_DATA - Byte e_ident[EI_DATA] specifies the data encoding of the remote_proc-specific data in the object -file. The following encodings are currently defined. */ +/* + * EI_DATA - Byte e_ident[EI_DATA] specifies the data encoding of the + * remote_proc-specific data in the object file. The following encodings are + * currently defined. + */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* See Data encodings, below */ #define ELFDATA2MSB 2 /* See Data encodings, below */ @@ -93,7 +131,45 @@ file. The following encodings are currently defined. */ /* EI_OSABI - We do not define an OS specific ABI */ #define ELFOSABI_NONE 0 -/* ELF section header. */ +/* ELF32 program header */ +typedef struct elf32_phdr{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +/* ELF64 program header */ +typedef struct elf64_phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + +/* segment types */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* ELF32 section header. */ typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; @@ -105,9 +181,22 @@ typedef struct { Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; - } Elf32_Shdr; +/* ELF64 section header. */ +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + /* sh_type */ #define SHT_NULL 0 #define SHT_PROGBITS 1 @@ -146,6 +235,12 @@ typedef struct { } Elf32_Rel; +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; + +} Elf64_Rel; + /* Relocation entry with addend */ typedef struct { Elf32_Addr r_offset; @@ -154,9 +249,17 @@ typedef struct { } Elf32_Rela; +typedef struct elf64_rela { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + /* Macros to extract information from 'r_info' field of relocation entries */ -#define ELF32_R_SYM(i) ((i)>>8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) /* Symbol table entry */ typedef struct { @@ -169,44 +272,157 @@ typedef struct { } Elf32_Sym; +typedef struct elf64_sym { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + /* ARM specific dynamic relocation codes */ -#define R_ARM_GLOB_DAT 21 /* 0x15 */ -#define R_ARM_JUMP_SLOT 22 /* 0x16 */ -#define R_ARM_RELATIVE 23 /* 0x17 */ -#define R_ARM_ABS32 2 /* 0x02 */ +#define R_ARM_GLOB_DAT 21 /* 0x15 */ +#define R_ARM_JUMP_SLOT 22 /* 0x16 */ +#define R_ARM_RELATIVE 23 /* 0x17 */ +#define R_ARM_ABS32 2 /* 0x02 */ /* ELF decoding information */ -struct elf_decode_info { - Elf32_Ehdr elf_header; - unsigned char *section_headers_start; - char *shstrtab; +struct elf32_info { + Elf32_Ehdr ehdr; + unsigned int load_state; + Elf32_Phdr *phdrs; + Elf32_Shdr *shdrs; + void *shstrtab; +}; - Elf32_Shdr *dynsym; - Elf32_Shdr *dynstr; - Elf32_Shdr *rel_plt; - Elf32_Shdr *rel_dyn; - Elf32_Shdr *rsc; +struct elf64_info { + Elf64_Ehdr ehdr; + unsigned int load_state; + Elf64_Phdr *phdrs; + Elf64_Shdr *shdrs; + void *shstrtab; +}; - unsigned char *dynsym_addr; - unsigned char *dynstr_addr; +#define ELF_STATE_INIT 0x0UL +#define ELF_STATE_WAIT_FOR_PHDRS 0x100UL +#define ELF_STATE_WAIT_FOR_SHDRS 0x200UL +#define ELF_STATE_WAIT_FOR_SHSTRTAB 0x400UL +#define ELF_STATE_HDRS_COMPLETE 0x800UL +#define ELF_STATE_MASK 0xFF00UL +#define ELF_NEXT_SEGMENT_MASK 0x00FFUL - char *firmware; +extern struct loader_ops elf_ops; -}; +/** + * elf_identify - check if it is an ELF file + * + * It will check if the input image header is an ELF header. + * + * @img_data: firmware private data which will be passed to user defined loader + * operations + * @len: firmware header length + * + * return 0 for success or negative value for failure. + */ +int elf_identify(const void *img_data, size_t len); + +/** + * elf_load_header - Load ELF headers + * + * It will get the ELF header, the program header, and the section header. + * + * @img_data: image data + * @offset: input image data offset to the start of image file + * @len: input image data length + * @img_info: pointer to store image information data + * @last_load_state: last state return by this function + * @noffset: pointer to next offset required by loading ELF header + * @nlen: pointer to next data length required by loading ELF header + * + * return ELF loading header state, or negative value for failure + */ +int elf_load_header(const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + size_t *noffset, size_t *nlen); -/* ELF Loader functions. */ -int elf_loader_init(struct remoteproc_loader *loader); -void *elf_loader_retrieve_entry_point(struct remoteproc_loader *loader); -void *elf_loader_retrieve_resource_section(struct remoteproc_loader *loader, - unsigned int *size); -int elf_loader_load_remote_firmware(struct remoteproc_loader *loader); -int elf_loader_attach_firmware(struct remoteproc_loader *loader, - void *firmware); -int elf_loader_detach_firmware(struct remoteproc_loader *loader); -void *elf_get_load_address(struct remoteproc_loader *loader); +/** + * elf_load - load ELF data + * + * It will parse the ELF image and return the target device address, + * offset to the start of the ELF image of the data to load and the + * length of the data to load. + * + * @rproc: pointer to remoteproc instance + * @img_data: image data which will passed to the function. + * it can be NULL, if image data doesn't need to be handled + * by the load function. E.g. binary data which was + * loaded to the target memory. + * @offset: last loaded image data offset to the start of image file + * @len: last loaded image data length + * @img_info: pointer to store image information data + * @last_load_state: the returned state of the last function call. + * @da: target device address, if the data to load is not for target memory + * the da will be set to ANY. + * @noffset: pointer to next offset required by loading ELF header + * @nlen: pointer to next data length required by loading ELF header + * @padding: value to pad it is possible that a size of a segment in memory + * is larger than what it is in the ELF image. e.g. a segment + * can have stack section .bss. It doesn't need to copy image file + * space, in this case, it will be packed with 0. + * @nmemsize: pointer to next data target memory size. The size of a segment + * in the target memory can be larger than the its size in the + * image file. + * + * return 0 for success, otherwise negative value for failure + */ +int elf_load(struct remoteproc *rproc, const void *img_data, + size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize); + +/** + * elf_release - Release ELF image information + * + * It will release ELF image information data. + * + * @img_info: pointer to ELF image information + */ +void elf_release(void *img_info); + +/** + * elf_get_entry - Get entry point + * + * It will return entry point specified in the ELF file. + * + * @img_info: pointer to ELF image information + * + * return entry address + */ +metal_phys_addr_t elf_get_entry(void *img_info); + +/** + * elf_locate_rsc_table - locate the resource table information + * + * It will return the length of the resource table, and the device address of + * the resource table. + * + * @img_info: pointer to ELF image information + * @da: pointer to the device address + * @offset: pointer to the offset to in the ELF image of the resource + * table section. + * @size: pointer to the size of the resource table section. + * + * return 0 if successfully locate the resource table, negative value for + * failure. + */ +int elf_locate_rsc_table(void *img_info, metal_phys_addr_t *da, + size_t *offset, size_t *size); #if defined __cplusplus } #endif -#endif /* ELF_LOADER_H_ */ +#endif /* ELF_LOADER_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/firmware.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/firmware.h deleted file mode 100644 index 4bddc8d7ce4c47..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/firmware.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef FIRMWARE_H -#define FIRMWARE_H - -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* Max supported firmwares */ -#define FW_COUNT 4 - -struct firmware_info { - char name[32]; - unsigned int start_addr; - unsigned int end_addr; -}; - -int config_get_firmware(char *fw_name, uintptr_t *start_addr, - unsigned int *size); - -#if defined __cplusplus -} -#endif - -#endif /* FIRMWARE_H */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/hil.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/hil.h deleted file mode 100644 index 2bd9211acdffe4..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/hil.h +++ /dev/null @@ -1,712 +0,0 @@ -#ifndef _HIL_H_ -#define _HIL_H_ - -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * hil.h - * - * DESCRIPTION - * - * This file defines interface layer to access hardware features. This - * interface is used by both RPMSG and remoteproc components. - * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* Configurable parameters */ -#define HIL_MAX_CORES 2 -#define HIL_MAX_NUM_VRINGS 2 -#define HIL_MAX_NUM_CHANNELS 1 -/* Reserved CPU id */ -#define HIL_RSVD_CPU_ID 0xffffffff - -struct hil_proc; - -typedef void (*hil_proc_vdev_rst_cb_t)(struct hil_proc *proc, int id); - -/** - * struct proc_shm - * - * This structure is maintained by hardware interface layer for - * shared memory information. The shared memory provides buffers - * for use by the vring to exchange messages between the cores. - * - */ -struct proc_shm { - /* Start address of shared memory used for buffers. */ - void *start_addr; - /* Start physical address of shared memory used for buffers. */ - metal_phys_addr_t start_paddr; - /* sharmed memory I/O region */ - struct metal_io_region *io; - /* sharmed memory metal device */ - struct metal_device *dev; - /* Size of shared memory. */ - unsigned long size; -}; - -/** -* struct proc_intr -* -* This structure is maintained by hardware interface layer for -* notification(interrupts) mechanism. The most common notification mechanism -* is Inter-Processor Interrupt(IPI). There can be other mechanism depending -* on SoC architecture. -* -*/ -struct proc_intr { - /* Interrupt number for vring - use for IPI */ - unsigned int vect_id; - /* Interrupt priority */ - unsigned int priority; - /* Interrupt trigger type */ - unsigned int trigger_type; - /* IPI metal device */ - struct metal_device *dev; - /* IPI device I/O */ - struct metal_io_region *io; - /* Private data */ - void *data; -}; - -/** -* struct proc_vring -* -* This structure is maintained by hardware interface layer to keep -* vring physical memory and notification info. -* -*/ -struct proc_vring { - /* Pointer to virtqueue encapsulating the vring */ - struct virtqueue *vq; - /* Vring logical address */ - void *vaddr; - /* Vring metal device */ - struct metal_device *dev; - /* Vring I/O region */ - struct metal_io_region *io; - /* Number of vring descriptors */ - unsigned short num_descs; - /* Vring alignment */ - unsigned long align; - /* Vring interrupt control block */ - struct proc_intr intr_info; -}; - -/** - * struct proc_vdev - * - * This structure represents a virtio HW device for remote processor. - * Currently only one virtio device per processor is supported. - * - */ -struct proc_vdev { - /* Address for the vdev info */ - void *vdev_info; - /* Vdev interrupt control block */ - struct proc_intr intr_info; - /* Vdev reset callback */ - hil_proc_vdev_rst_cb_t rst_cb; - /* Number of vrings */ - unsigned int num_vrings; - /* Virtio device features */ - unsigned int dfeatures; - /* Virtio gen features */ - unsigned int gfeatures; - /* Vring info control blocks */ - struct proc_vring vring_info[HIL_MAX_NUM_VRINGS]; -}; - -/** - * struct proc_chnl - * - * This structure represents channel IDs that would be used by - * the remote in the name service message. This will be extended - * further to support static channel creation. - * - */ -struct proc_chnl { - /* Channel ID */ - char name[32]; -}; - -/** -* struct hil_proc -* -* This structure represents a remote processor and encapsulates shared -* memory and notification info required for IPC. -* -*/ -struct hil_proc { - /* HIL CPU ID */ - unsigned long cpu_id; - /* HIL platform ops table */ - struct hil_platform_ops *ops; - /* Resource table metal device */ - struct metal_device *rsc_dev; - /* Resource table I/O region */ - struct metal_io_region *rsc_io; - /* Shared memory info */ - struct proc_shm sh_buff; - /* Virtio device hardware info */ - struct proc_vdev vdev; - /* Number of RPMSG channels */ - unsigned long num_chnls; - /* RPMsg channels array */ - struct proc_chnl chnls[HIL_MAX_NUM_CHANNELS]; - /* Initialized status */ - int is_initialized; - /* hil_proc lock */ - metal_mutex_t lock; - /* private data */ - void *pdata; - /* List node */ - struct metal_list node; -}; - -/** - * hil_create_proc - * - * This function creates a HIL proc instance - * - * @param ops - hil proc platform operations - * @param cpu_id - remote CPU ID. - * E.g. the CPU ID of the remote processor in its - * cluster. - * @param pdata - private data - * @return - pointer to proc instance - * - */ -struct hil_proc *hil_create_proc(struct hil_platform_ops *ops, - unsigned long cpu_id, void *pdata); - -/** - * hil_delete_proc - * - * This function deletes the given proc instance and frees the - * associated resources. - * - * @param proc - pointer to HIL proc instance - * - */ -void hil_delete_proc(struct hil_proc *proc); - -/** - * hil_init_proc - * - * This function initialize a HIL proc instance with the given platform data - * @param proc - pointer to the hil_proc to initialize - * - * @return - 0 succeeded, non-0 for failure - * - */ -int hil_init_proc(struct hil_proc *proc); - -/** - * hil_notified() - * - * This function is called when notification is received. - * This function gets the corresponding virtqueue and generates - * call back for it. - * - * @param proc - pointer to hil_proc - * @param notifyid - notifyid - * - */ -void hil_notified(struct hil_proc *proc, uint32_t notifyid); - -/** - * hil_get_vdev_info - * - * This function return virtio device for remote core. - * - * @param proc - pointer to remote proc - * - * @return - pointer to virtio HW device. - * - */ -struct proc_vdev *hil_get_vdev_info(struct hil_proc *proc); - -/** - * hil_get_chnl_info - * - * This function returns channels info for given proc. - * - * @param proc - pointer to proc info struct - * @param num_chnls - pointer to integer variable to hold - * number of available channels - * - * @return - pointer to channel info control block - * - */ -struct proc_chnl *hil_get_chnl_info(struct hil_proc *proc, int *num_chnls); - -/** - * hil_get_vring_info - * - * This function returns vring_info_table. The caller will use - * this table to get the vring HW info which will be subsequently - * used to create virtqueues. - * - * @param vdev - pointer to virtio HW device - * @param num_vrings - pointer to hold number of vrings - * - * @return - pointer to vring hardware info table - */ -struct proc_vring *hil_get_vring_info(struct proc_vdev *vdev, int *num_vrings); - -/** - * hil_get_shm_info - * - * This function returns shared memory info control block. The caller - * will use this information to create and manage memory buffers for - * vring descriptor table. - * - * @param proc - pointer to proc instance - * - * @return - pointer to shared memory region used for buffers - * - */ -struct proc_shm *hil_get_shm_info(struct hil_proc *proc); - -/** - * hil_free_virtqueues - * - * This function remove virt queues of the vdev. - - * @param vdev - pointer to the vdev which needs to remove vqs - */ -void hil_free_vqs(struct virtio_device *vdev); - -/** - * hil_enable_vdev_notification() - * - * This function enable handler for vdev notification. - * - * @param proc - pointer to hil_proc - * @param id - vdev index - * - * @return - execution status - */ -int hil_enable_vdev_notification(struct hil_proc *proc, int id); - -/** - * hil_enable_vring_notifications() - * - * This function is called after successful creation of virtqueues. - * This function saves queue handle in the vring_info_table which - * will be used during interrupt handling .This function setups - * interrupt handlers. - * - * @param vring_index - index to vring HW table - * @param vq - pointer to virtqueue to save in vring HW table - * - * @return - execution status - */ -int hil_enable_vring_notifications(int vring_index, struct virtqueue *vq); - -/** - * hil_vdev_notify() - * - * This function generates IPI to let the other side know that there is - * change to virtio device configs. - * - * @param vdev - pointer to virtio device - * - */ -void hil_vdev_notify(struct virtio_device *vdev); - -/** - * hil_vring_notify() - * - * This function generates IPI to let the other side know that there is - * job available for it. The required information to achieve this, like interrupt - * vector, CPU id etc is be obtained from the proc_vring table. - * - * @param vq - pointer to virtqueue - * - */ -void hil_vring_notify(struct virtqueue *vq); - -/** - * hil_get_status - * - * This function is used to check if the given core is up and running. - * This call will return after it is confirmed that remote core has - * started. - * - * @param proc - pointer to proc instance - * - * @return - execution status - */ -int hil_get_status(struct hil_proc *proc); - -/** - * hil_set_status - * - * This function is used to update the status - * of the given core i.e it is ready for IPC. - * - * @param proc - pointer to remote proc - * - * @return - execution status - */ - -int hil_set_status(struct hil_proc *proc); - -/** hil_create_generic_mem_dev - * - * This function creates generic memory device. - * This is a helper function. - * - * @param pa - physical base address - * @param size - size of the memory - * @param flags - flags of the memory region - * - * @return - pointer to the memory device - */ -struct metal_device *hil_create_generic_mem_dev( metal_phys_addr_t pa, - size_t size, unsigned int flags); - -/** hil_close_generic_mem_dev - * - * This function closes the generic memory device. - * - * @param dev - pointer to the memory device. - */ -void hil_close_generic_mem_dev(struct metal_device *dev); - -/** - * hil_boot_cpu - * - * This function starts remote processor at given address. - * - * @param proc - pointer to remote proc - * @param load_addr - load address of remote firmware - * - * @return - execution status - */ -int hil_boot_cpu(struct hil_proc *proc, unsigned int load_addr); - -/** - * hil_shutdown_cpu - * - * This function shutdowns the remote processor - * - * @param proc - pointer to remote proc - * - */ -void hil_shutdown_cpu(struct hil_proc *proc); - -/** - * hil_get_firmware - * - * This function returns address and size of given firmware name passed as - * parameter. - * - * @param fw_name - name of the firmware - * @param start_addr - pointer t hold start address of firmware - * @param size - pointer to hold size of firmware - * - * returns - status of function execution - * - */ -int hil_get_firmware(char *fw_name, uintptr_t *start_addr, - unsigned int *size); - -/** - * hil_poll - * - * This function polls the remote processor. - * If it is blocking mode, it will not return until the remoteproc - * is signaled. If it is non-blocking mode, it will return 0 - * if the remoteproc has pending signals, it will return non 0 - * otherwise. - * - * @param proc - hil_proc to poll - * @param nonblock - 0 for blocking, non-0 for non-blocking. - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_poll (struct hil_proc *proc, int nonblock); - -/** - * hil_set_shm - * - * This function set HIL proc shared memory - * - * @param proc - hil_proc to set - * @param bus_name - bus name of the shared memory device - * @param name - name of the shared memory, or platform device - * mandatory for Linux system. - * @param paddr - physical address of the memory - * @param size - size of the shared memory - * - * If name argument exists, it will open the specified libmetal - * shared memory or the specified libmetal device if bus_name - * is specified to get the I/O region of the shared memory. - * If memory name doesn't exist, it will create a metal device - * for teh shared memory. - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_set_shm (struct hil_proc *proc, - const char *bus_name, const char *name, - metal_phys_addr_t paddr, size_t size); - -/** - * hil_set_rsc - * - * This function set HIL proc RSC I/O - * - * @param proc - hil_proc to set vdev io regsion - * @param bus_name - bus name of the vdev device - * @param name - name of the shared memory, or platform device - * mandatory for Linux system. - * @param paddr - physical address of the memory - * @param size - size of the shared memory - * - * If name argument exists, it will open the specified libmetal - * shared memory or the specified libmetal device if bus_name - * is specified to get the I/O region of the shared memory. - * If memory name doesn't exist, it will create a metal device - * for teh shared memory. - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_set_rsc (struct hil_proc *proc, - const char *bus_name, const char *name, - metal_phys_addr_t paddr, size_t size); -/** - * hil_set_vring - * - * This function set HIL proc vring - * - * @param proc - hil_proc to set - * @param index - vring index - * @param bus_name - bus name of the vring device - * @param name - name of the shared memory, or platform device - * mandatory for Linux system. - * @param paddr - physical address of the memory - * @param size - size of the shared memory - * - * If name argument exists, it will open the specified libmetal - * shared memory or the specified libmetal device if bus_name - * is specified to get the I/O region of the shared memory. - * If memory name doesn't exist, it will create a metal device - * for teh shared memory. - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_set_vring (struct hil_proc *proc, int index, - const char *bus_name, const char *name, - metal_phys_addr_t paddr, size_t size); - -/** - * hil_set_vdev_ipi - * - * This function set HIL proc vdev IPI - * - * @param proc - hil_proc to set - * @param index - vring index for the IPI - * @param irq - IPI irq vector ID - * @param data - IPI data - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_set_vdev_ipi (struct hil_proc *proc, int index, - unsigned int irq, void *data); - -/** - * hil_set_vring_ipi - * - * This function set HIL proc vring IPI - * - * @param proc - hil_proc to set - * @param index - vring index for the IPI - * @param irq - IPI irq vector ID - * @param data - IPI data - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_set_vring_ipi (struct hil_proc *proc, int index, - unsigned int irq, void *data); - -/** - * hil_set_rpmsg_channel - * - * This function set HIL proc rpmsg_channel - * - * @param proc - hil_proc to set - * @param index - vring index for the rpmsg_channel - * @param name - RPMsg channel name - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_set_rpmsg_channel (struct hil_proc *proc, int index, - char *name); - -/** - * hil_set_vdev_rst_cb - * - * This function set HIL proc vdev reset callback - * - * @param proc - hil_proc to set - * @param index - vdev index - * @param cb - reset callback - * - * @return - 0 for no errors, non-0 for errors. - */ -int hil_set_vdev_rst_cb (struct hil_proc *proc, int index, - hil_proc_vdev_rst_cb_t cb); - -/** - * - * This structure is an interface between HIL and platform porting - * component. It is required for the user to provide definitions of - * these functions when framework is ported to new hardware platform. - * - */ -struct hil_platform_ops { - /** - * enable_interrupt() - * - * This function enables interrupt(IPI) - * - * @param intr - pointer to intr information - * - * @return - execution status - */ - int (*enable_interrupt) (struct proc_intr *intr); - - /** - * notify() - * - * This function generates IPI to let the other side know that there is - * job available for it. - * - * @param proc - pointer to the hil_proc - * @param intr_info - pointer to interrupt info control block - */ - void (*notify) (struct hil_proc *proc, struct proc_intr * intr_info); - - /** - * boot_cpu - * - * This unction boots the remote processor. - * - * @param proc - pointer to the hil_proc - * @param start_addr - start address of remote cpu - * - * @return - execution status - */ - int (*boot_cpu) (struct hil_proc *proc, unsigned int start_addr); - - /** - * shutdown_cpu - * - * This function shutdowns the remote processor. - * - * @param proc - pointer to the hil_proc - * - */ - void (*shutdown_cpu) (struct hil_proc *proc); - - /** - * poll - * - * This function polls the remote processor. - * - * @param proc - hil_proc to poll - * @param nonblock - 0 for blocking, non-0 for non-blocking. - * - * @return - 0 for no errors, non-0 for errors. - */ - int (*poll) (struct hil_proc *proc, int nonblock); - - /** - * alloc_shm - * - * This function is to allocate shared memory - * - * @param[in] proc - pointer to the remote processor - * @param[in] pa - physical address - * @param[in] size - size of the shared memory - * @param[out] dev - pointer to the mem dev pointer - * - * @return - NULL, pointer to the I/O region - * - */ - struct metal_io_region *(*alloc_shm) (struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev); - - /** - * release_shm - * - * This function is to release shared memory - * - * @param[in] proc - pointer to the remote processor - * @param[in] dev - pointer to the mem dev - * @param[in] io - pointer to the I/O region - * - */ - void (*release_shm) (struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io); - - /** - * initialize - * - * This function initialize remote processor with platform data. - * - * @param proc - hil_proc to poll - * - * @return NULL on failure, hil_proc pointer otherwise - * - */ - int (*initialize) (struct hil_proc *proc); - - /** - * release - * - * This function is to release remote processor resource - * - * @param[in] proc - pointer to the remote processor - * - */ - void (*release) (struct hil_proc *proc); -}; - -/* Utility macros for register read/write */ -#define HIL_MEM_READ8(addr) *(volatile unsigned char *)(addr) -#define HIL_MEM_READ16(addr) *(volatile unsigned short *)(addr) -#define HIL_MEM_READ32(addr) *(volatile unsigned long *)(addr) -#define HIL_MEM_WRITE8(addr,data) *(volatile unsigned char *)(addr) = (unsigned char)(data) -#define HIL_MEM_WRITE16(addr,data) *(volatile unsigned short *)(addr) = (unsigned short)(data) -#define HIL_MEM_WRITE32(addr,data) *(volatile unsigned long *)(addr) = (unsigned long)(data) - -#if defined __cplusplus -} -#endif - -#endif /* _HIL_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/open_amp.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/open_amp.h index be822de8319d14..1a01688a9f85a2 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/open_amp.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/open_amp.h @@ -9,7 +9,9 @@ #define OPEN_AMP_H_ #include +#include #include +#include #endif /* OPEN_AMP_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc.h index fec634c302307a..90d908729c6afb 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc.h @@ -1,6 +1,7 @@ /* - * Remote remote_proc Framework + * Remoteproc Framework * + * Copyright(c) 2018 Xilinx Ltd. * Copyright(c) 2011 Texas Instruments, Inc. * Copyright(c) 2011 Google, Inc. * All rights reserved. @@ -11,13 +12,16 @@ #ifndef REMOTEPROC_H #define REMOTEPROC_H -#include -#include +#include +#include +#include #if defined __cplusplus extern "C" { #endif +#define RSC_NOTIFY_ID_ANY 0xFFFFFFFFUL + /** * struct resource_table - firmware resource table header * @ver: version number @@ -78,6 +82,8 @@ struct fw_rsc_hdr { * the remote remote_proc will be writing logs. * @RSC_VDEV: declare support for a virtio device, and serve as its * virtio header. + * @RSC_VENDOR_START: start of the vendor specific resource types range + * @RSC_VENDOR_END : end of the vendor specific resource types range * @RSC_LAST: just keep this one at the end * * For more details regarding a specific resource type, please see its @@ -96,9 +102,12 @@ enum fw_resource_type { RSC_RPROC_MEM = 4, RSC_FW_CHKSUM = 5, RSC_LAST = 6, + RSC_VENDOR_START = 128, + RSC_VENDOR_END = 512, }; #define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) +#define FW_RSC_U32_ADDR_ANY (0xFFFFFFFF) /** * struct fw_rsc_carveout - physically contiguous memory request @@ -294,6 +303,22 @@ struct fw_rsc_vdev { struct fw_rsc_vdev_vring vring[0]; } OPENAMP_PACKED_END; +/** + * struct fw_rsc_vendor - remote processor vendor specific resource + * @len: length of the resource + * + * This resource entry tells the host the vendor specific resource + * required by the remote. + * + * These request entries should precede other shared resource entries + * such as vdevs, vrings. + */ +OPENAMP_PACKED_BEGIN +struct fw_rsc_vendor { + uint32_t type; + uint32_t len; +} OPENAMP_PACKED_END; + /** * struct fw_rsc_rproc_mem - remote processor memory * @da: device address @@ -332,172 +357,515 @@ struct fw_rsc_fw_chksum { uint8_t chksum[64]; } OPENAMP_PACKED_END; +struct loader_ops; +struct image_store_ops; +struct remoteproc_ops; + +/** + * struct remoteproc_mem + * + * This structure presents the memory used by the remote processor + * + * @da: device memory + * @pa: physical memory + * @size: size of the memory + * @io: pointer to the I/O region + * @node: list node + */ +struct remoteproc_mem { + metal_phys_addr_t da; + metal_phys_addr_t pa; + size_t size; + char name[32]; + struct metal_io_region *io; + struct metal_list node; +}; + /** - * struct remote_proc + * struct remoteproc * * This structure is maintained by the remoteproc to represent the remote * processor instance. This structure acts as a prime parameter to use * the remoteproc APIs. * - * @proc : hardware interface layer processor control - * @rdev : remote device , used by RPMSG "messaging" framework. - * @loader : pointer remoteproc loader - * @channel_created : create channel callback - * @channel_destroyed : delete channel callback - * @default_cb : default callback for channel - * @role : remote proc role , RPROC_MASTER/RPROC_REMOTE - * - */ -struct remote_proc { - struct hil_proc *proc; - struct remote_device *rdev; - struct remoteproc_loader *loader; - rpmsg_chnl_cb_t channel_created; - rpmsg_chnl_cb_t channel_destroyed; - rpmsg_rx_cb_t default_cb; - int role; + * @bootadd: boot address + * @loader: executable loader + * @lock: mutext lock + * @ops: remoteproc operations + * @rsc_table: pointer to resource table + * @rsc_len: length of resource table + * @rsc_io: metal I/O region of resource table + * @mems: remoteproc memories + * @vdevs: remoteproc virtio devices + * @bitmap: bitmap for notify IDs for remoteproc subdevices + * @state: remote processor state + * @priv: private data + */ +struct remoteproc { + metal_mutex_t lock; + void *rsc_table; + size_t rsc_len; + struct metal_io_region *rsc_io; + struct metal_list mems; + struct metal_list vdevs; + unsigned long bitmap; + struct remoteproc_ops *ops; + metal_phys_addr_t bootaddr; + struct loader_ops *loader; + unsigned int state; + void *priv; }; /** - * struct resc_table_info + * struct remoteproc_ops + * + * remoteproc operations needs to be implemented by each remoteproc driver + * + * @init: initialize the remoteproc instance + * @remove: remove the remoteproc instance + * @mmap: memory mapped the mempory with physical address or destination + * address as input. + * @handle_rsc: handle the vendor specific resource + * @config: configure the remoteproc to make it ready to load and run + * executable + * @start: kick the remoteproc to run application + * @stop: stop the remoteproc from running application, the resource such as + * memory may not be off. + * @shutdown: shutdown the remoteproc and release its resources. + * @notify: notify the remote + */ +struct remoteproc_ops { + struct remoteproc *(*init)(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *arg); + void (*remove)(struct remoteproc *rproc); + void *(*mmap)(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io); + int (*handle_rsc)(struct remoteproc *rproc, void *rsc, size_t len); + int (*config)(struct remoteproc *rproc, void *data); + int (*start)(struct remoteproc *rproc); + int (*stop)(struct remoteproc *rproc); + int (*shutdown)(struct remoteproc *rproc); + int (*notify)(struct remoteproc *rproc, uint32_t id); +}; + +/* Remoteproc error codes */ +#define RPROC_EBASE 0 +#define RPROC_ENOMEM (RPROC_EBASE + 1) +#define RPROC_EINVAL (RPROC_EBASE + 2) +#define RPROC_ENODEV (RPROC_EBASE + 3) +#define RPROC_EAGAIN (RPROC_EBASE + 4) +#define RPROC_ERR_RSC_TAB_TRUNC (RPROC_EBASE + 5) +#define RPROC_ERR_RSC_TAB_VER (RPROC_EBASE + 6) +#define RPROC_ERR_RSC_TAB_RSVD (RPROC_EBASE + 7) +#define RPROC_ERR_RSC_TAB_VDEV_NRINGS (RPROC_EBASE + 9) +#define RPROC_ERR_RSC_TAB_NP (RPROC_EBASE + 10) +#define RPROC_ERR_RSC_TAB_NS (RPROC_EBASE + 11) +#define RPROC_ERR_LOADER_STATE (RPROC_EBASE + 12) +#define RPROC_EMAX (RPROC_EBASE + 16) +#define RPROC_EPTR (void *)(-1) +#define RPROC_EOF (void *)(-1) + +static inline long RPROC_PTR_ERR(const void *ptr) +{ + return (long)ptr; +} + +static inline int RPROC_IS_ERR(const void *ptr) +{ + if ((unsigned long)ptr >= (unsigned long)(-RPROC_EMAX)) + return 1; + else + return 0; +} + +static inline void *RPROC_ERR_PTR(long error) +{ + return (void *)error; +} + +/** + * enum rproc_state - remote processor states + * @RPROC_OFFLINE: remote is offline + * @RPROC_READY: remote is ready to start + * @RPROC_RUNNING: remote is up and running + * @RPROC_SUSPENDED: remote is suspended + * @RPROC_ERROR: remote has error; need to recover + * @RPROC_STOPPED: remote is stopped + * @RPROC_LAST: just keep this one at the end + */ +enum remoteproc_state { + RPROC_OFFLINE = 0, + RPROC_CONFIGURED = 1, + RPROC_READY = 2, + RPROC_RUNNING = 3, + RPROC_SUSPENDED = 4, + RPROC_ERROR = 5, + RPROC_STOPPED = 6, + RPROC_LAST = 7, +}; + +/** + * remoteproc_init * - * This structure is maintained by the remoteproc to allow applications - * to pass resource table info during remote initialization. + * Initializes remoteproc resource. * - * @rsc_tab : pointer to resource table control block - * @size : size of resource table. + * @rproc - pointer to remoteproc instance + * @ops - pointer to remoteproc operations + * @priv - pointer to private data * + * @returns created remoteproc pointer */ -struct rsc_table_info { - struct resource_table *rsc_tab; - int size; -}; +struct remoteproc *remoteproc_init(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *priv); -/* Definitions for device types , null pointer, etc.*/ -#define RPROC_SUCCESS 0 -#define RPROC_NULL (void *)0 -#define RPROC_TRUE 1 -#define RPROC_FALSE 0 -#define RPROC_MASTER 1 -#define RPROC_REMOTE 0 -/* Number of msecs to wait for remote context to come up */ -#define RPROC_BOOT_DELAY 500 +/** + * remoteproc_remove + * + * Remove remoteproc resource + * + * @rproc - pointer to remoteproc instance + * + * returns 0 for success, negative value for failure + */ +int remoteproc_remove(struct remoteproc *rproc); -/* Remoteproc error codes */ -#define RPROC_ERR_BASE -4000 -#define RPROC_ERR_CPU_INIT (RPROC_ERR_BASE -1) -#define RPROC_ERR_NO_RSC_TABLE (RPROC_ERR_BASE -2) -#define RPROC_ERR_NO_MEM (RPROC_ERR_BASE -3) -#define RPROC_ERR_RSC_TAB_TRUNC (RPROC_ERR_BASE -4) -#define RPROC_ERR_RSC_TAB_VER (RPROC_ERR_BASE -5) -#define RPROC_ERR_RSC_TAB_RSVD (RPROC_ERR_BASE -6) -#define RPROC_ERR_RSC_TAB_VDEV_NRINGS (RPROC_ERR_BASE -7) -#define RPROC_ERR_RSC_TAB_NP (RPROC_ERR_BASE -8) -#define RPROC_ERR_RSC_TAB_NS (RPROC_ERR_BASE -9) -#define RPROC_ERR_INVLD_FW (RPROC_ERR_BASE -10) -#define RPROC_ERR_LOADER (RPROC_ERR_BASE -11) -#define RPROC_ERR_PARAM (RPROC_ERR_BASE -12) -#define RPROC_ERR_PTR (void*)0xDEADBEAF +/** + * remoteproc_init_mem + * + * Initialize remoteproc memory + * + * @mem - pointer to remoteproc memory + * @char - memory name + * @pa - physcial address + * @da - device address + * @size - memory size + * @io - pointer to the I/O region + */ +static inline void +remoteproc_init_mem(struct remoteproc_mem *mem, const char *name, + metal_phys_addr_t pa, metal_phys_addr_t da, + size_t size, struct metal_io_region *io) +{ + if (!mem) + return; + if (name) + strncpy(mem->name, name, sizeof(mem->name)); + else + mem->name[0] = 0; + mem->pa = pa; + mem->da = da; + mem->io = io; + mem->size = size; +} + +/** + * remoteproc_add_mem + * + * Add remoteproc memory + * + * @rproc - pointer to remoteproc + * @mem - pointer to remoteproc memory + */ +static inline void +remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem) +{ + if (!rproc || !mem) + return; + metal_list_add_tail(&rproc->mems, &mem->node); +} /** - * remoteproc_resource_init + * remoteproc_get_io_with_name * - * Initializes resources for remoteproc remote configuration.Only - * remoteproc remote applications are allowed to call this function. + * get remoteproc memory I/O region with name * - * @param rsc_info - pointer to resource table info control - * block - * @param proc - pointer to the hil_proc - * @param channel_created - callback function for channel creation - * @param channel_destroyed - callback function for channel deletion - * @param default_cb - default callback for channel I/O - * @param rproc_handle - pointer to new remoteproc instance - * @param init_env - 1 to initialize environment, 0 not to - * @param rpmsg_role - 1 for rpmsg master, or 0 for rpmsg slave + * @rproc - pointer to the remote processor + * @name - name of the shared memory + * @io - pointer to the pointer of the I/O region * - * @param returns - status of execution + * returns metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_name(struct remoteproc *rproc, + const char *name); + +/** + * remoteproc_get_io_with_pa + * + * get remoteproc memory I/O region with physical address * + * @rproc - pointer to the remote processor + * @pa - physical address + * + * returns metal I/O region pointer, NULL for failure */ -int remoteproc_resource_init(struct rsc_table_info *rsc_info, - struct hil_proc *proc, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, - rpmsg_rx_cb_t default_cb, - struct remote_proc **rproc_handle, - int rpmsg_role); +struct metal_io_region * +remoteproc_get_io_with_pa(struct remoteproc *rproc, + metal_phys_addr_t pa); /** - * remoteproc_resource_deinit + * remoteproc_get_io_with_da + * + * get remoteproc memory I/O region with device address + * + * @rproc - pointer to the remote processor + * @da - device address + * @offset - I/O region offset of the device address * - * Uninitializes resources for remoteproc remote configuration. + * returns metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_da(struct remoteproc *rproc, + metal_phys_addr_t da, + unsigned long *offset); + +/** + * remoteproc_get_io_with_va * - * @param rproc - pointer to remoteproc instance + * get remoteproc memory I/O region with virtual address * - * @param returns - status of execution + * @rproc - pointer to the remote processor + * @va - virtual address * + * returns metal I/O region pointer, NULL for failure */ +struct metal_io_region * +remoteproc_get_io_with_va(struct remoteproc *rproc, + void *va); -int remoteproc_resource_deinit(struct remote_proc *rproc); +/** + * remoteproc_mmap + * + * remoteproc mmap memory + * + * @rproc - pointer to the remote processor + * @pa - physical address pointer + * @da - device address pointer + * @size - size of the memory + * @attribute - memory attribute + * @io - pointer to the I/O region + * + * returns pointer to the memory + */ +void *remoteproc_mmap(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io); /** - * remoteproc_init + * remoteproc_parse_rsc_table + * + * Parse resource table of remoteproc + * + * @rproc - pointer to remoteproc instance + * @rsc_table - pointer to resource table + * @rsc_size - resource table size * - * Initializes resources for remoteproc master configuration. Only - * remoteproc master applications are allowed to call this function. + * returns 0 for success and negative value for errors + */ +int remoteproc_parse_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size); + +/** + * remoteproc_set_rsc_table * - * @param fw_name - name of firmware - * @param proc - pointer to hil_proc - * @param channel_created - callback function for channel creation - * @param channel_destroyed - callback function for channel deletion - * @param default_cb - default callback for channel I/O - * @param rproc_handle - pointer to new remoteproc instance + * Parse and set resource table of remoteproc * - * @param returns - status of function execution + * @rproc - pointer to remoteproc instance + * @rsc_table - pointer to resource table + * @rsc_size - resource table size * + * returns 0 for success and negative value for errors */ -int remoteproc_init(char *fw_name, struct hil_proc *proc, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, - rpmsg_rx_cb_t default_cb, - struct remote_proc **rproc_handle); +int remoteproc_set_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size); /** - * remoteproc_deinit + * remoteproc_config * - * Uninitializes resources for remoteproc "master" configuration. + * This function configures the remote processor to get it + * ready to load and run executable. * - * @param rproc - pointer to remoteproc instance + * @rproc - pointer to remoteproc instance to start + * @data - configuration data * - * @param returns - status of function execution + * returns 0 for success and negative value for errors + */ +int remoteproc_config(struct remoteproc *rproc, void *data); + +/** + * remoteproc_start + * + * This function starts the remote processor. + * It assumes the firmware is already loaded, * + * @rproc - pointer to remoteproc instance to start + * + * returns 0 for success and negative value for errors */ -int remoteproc_deinit(struct remote_proc *rproc); +int remoteproc_start(struct remoteproc *rproc); /** - * remoteproc_boot + * remoteproc_stop * - * This function loads the image on the remote processor and starts - * its execution from image load address. + * This function stops the remote processor but it + * will not release its resource. * - * @param rproc - pointer to remoteproc instance to boot + * @rproc - pointer to remoteproc instance * - * @param returns - status of function execution + * returns 0 for success and negative value for errors */ -int remoteproc_boot(struct remote_proc *rproc); +int remoteproc_stop(struct remoteproc *rproc); /** * remoteproc_shutdown * - * This function shutdowns the remote execution context. + * This function shutdown the remote processor and + * release its resources. * - * @param rproc - pointer to remoteproc instance to shutdown + * @rproc - pointer to remoteproc instance * - * @param returns - status of function execution + * returns 0 for success and negative value for errors */ -int remoteproc_shutdown(struct remote_proc *rproc); +int remoteproc_shutdown(struct remoteproc *rproc); +/** + * remoteproc_load + * + * load executable, it expects the user application defines how to + * open the executable file and how to get data from the executable file + * and how to load data to the target memory. + * + * @rproc: pointer to the remoteproc instance + * @path: optional path to the image file + * @store: pointer to user defined image store argument + * @store_ops: pointer to image store operations + * @image_info: pointer to memory which stores image information used + * by remoteproc loader + * + * return 0 for success and negative value for failure + */ +int remoteproc_load(struct remoteproc *rproc, const char *path, + void *store, struct image_store_ops *store_ops, + void **img_info); + +/** + * remoteproc_load_noblock + * + * load executable, it expects the caller has loaded image data to local + * memory and passed to the this function. If the function needs more + * image data it will return the next expected image data offset and + * the next expected image data length. If the function requires the + * caller to download image data to the target memory, it will also + * return the target physical address besides the offset and length. + * This function can be used to load firmware in stream mode. In this + * mode, you cannot do seek to the executable file. If the executable + * is ELF, it cannot get the resource table section before it loads + * the full ELF file. Furthermore, application usually don't store + * the data which is loaded to local memory in streaming mode, and + * thus, in this mode, it will load the binrary to the target memory + * before it gets the resource table. And thus, when calling this funciton + * don't put the target exectuable memory in the resource table, as + * this function will parse the resource table after it loads the binary + * to target memory. + * + * @rproc: pointer to the remoteproc instance + * @img_data: pointer to image data for remoteproc loader to parse + * @offset: image data offset to the beginning of the image file + * @len: image data length + * @image_info: pointer to memory which stores image information used + * by remoteproc loader + * @pa: pointer to the target memory physical address. If the next expected + * data doesn't need to load to the target memory, the function will + * set it to ANY. + * @io: pointer to the target memory physical address. If the next expected + * data doesn't need to load to the target memory, the function will + * set it to ANY. + * @noffset: pointer to the next image data offset to the beginning of + * the image file needs to load to local or to the target + * memory. + * @nlen: pointer to the next image data length needs to load to local + * or to the target memory. + * @nmlen: pointer to the memory size. It is only used when the next + * expected data is going to be loaded to the target memory. E.g. + * in ELF, it is possible that loadable segment in memory is + * larger that the segment data in the ELF file. In this case, + * application will need to pad the rest of the memory with + * padding. + * @padding: pointer to the padding value. It is only used when the next + * expected data is going to be loaded to the target memory. + * and the target memory size is larger than the segment data in + * the executable file. + * + * return 0 for success and negative value for failure + */ +int remoteproc_load_noblock(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, + metal_phys_addr_t *pa, struct metal_io_region **io, + size_t *noffset, size_t *nlen, + size_t *nmlen, unsigned char *padding); + +/** + * remoteproc_allocate_id + * + * allocate notifyid for resource + * + * @rproc - pointer to the remoteproc instance + * @start - start of the id range + * @end - end of the id range + * + * return allocated notify id + */ +unsigned int remoteproc_allocate_id(struct remoteproc *rproc, + unsigned int start, + unsigned int end); + +/* remoteproc_create_virtio + * + * create virtio device, it returns pointer to the created virtio device. + * + * @rproc: pointer to the remoteproc instance + * @vdev_id: virtio device ID + * @role: virtio device role + * @rst_cb: virtio device reset callback + * + * return pointer to the created virtio device, NULL for failure. + */ +struct virtio_device * +remoteproc_create_virtio(struct remoteproc *rproc, + int vdev_id, unsigned int role, + void (*rst_cb)(struct virtio_device *vdev)); + +/* remoteproc_remove_virtio + * + * Remove virtio device + * + * @rproc: pointer to the remoteproc instance + * @vdev: pointer to the virtio device + * + */ +void remoteproc_remove_virtio(struct remoteproc *rproc, + struct virtio_device *vdev); + +/* remoteproc_get_notification + * + * remoteproc is got notified, it will check its subdevices + * for the notification + * + * @rproc - pointer to the remoteproc instance + * @notifyid - notificatin id + * + * return 0 for succeed, negative value for failure + */ +int remoteproc_get_notification(struct remoteproc *rproc, + uint32_t notifyid); #if defined __cplusplus } #endif -#endif /* REMOTEPROC_H_ */ +#endif /* REMOTEPROC_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc_loader.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc_loader.h index d7e1c0923b0639..4409a1aa7ad74c 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc_loader.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc_loader.h @@ -23,58 +23,86 @@ #ifndef REMOTEPROC_LOADER_H_ #define REMOTEPROC_LOADER_H_ +#include +#include +#include #include #if defined __cplusplus extern "C" { #endif -/** - * enum loader_type - dynamic name service announcement flags - * - * @ELF_LOADER: an ELF loader - * @FIT_LOADER: a loader for Flattened Image Trees - */ -enum loader_type { - ELF_LOADER = 0, FIT_LOADER = 1, LAST_LOADER = 2, -}; - -/* Loader structure definition. */ +/* Loader feature macros */ +#define SUPPORT_SEEK 1UL -struct remoteproc_loader { - enum loader_type type; - void *remote_firmware; - /* Pointer to firmware decoded info control block */ - void *fw_decode_info; +/* Remoteproc loader any address */ +#define RPROC_LOAD_ANYADDR ((metal_phys_addr_t)-1) - /* Loader callbacks. */ - void *(*retrieve_entry) (struct remoteproc_loader * loader); - void *(*retrieve_rsc) (struct remoteproc_loader * loader, - unsigned int *size); - int (*load_firmware) (struct remoteproc_loader * loader); - int (*attach_firmware) (struct remoteproc_loader * loader, - void *firmware); - int (*detach_firmware) (struct remoteproc_loader * loader); - void *(*retrieve_load_addr) (struct remoteproc_loader * loader); +/* Remoteproc loader Exectuable Image Parsing States */ +/* Remoteproc loader parser intial state */ +#define RPROC_LOADER_NOT_READY 0x0UL +/* Remoteproc loader ready to load, even it can be not finish parsing */ +#define RPROC_LOADER_READY_TO_LOAD 0x10000UL +/* Remoteproc loader post data load */ +#define RPROC_LOADER_POST_DATA_LOAD 0x20000UL +/* Remoteproc loader finished loading */ +#define RPROC_LOADER_LOAD_COMPLETE 0x40000UL +/* Remoteproc loader state mask */ +#define RPROC_LOADER_MASK 0x00FF0000UL +/* Remoteproc loader private mask */ +#define RPROC_LOADER_PRIVATE_MASK 0x0000FFFFUL +/* Remoteproc loader reserved mask */ +#define RPROC_LOADER_RESERVED_MASK 0x0F000000UL +/** + * struct image_store_ops - user defined image store operations + * @open: user defined callback to open the "firmware" to prepare loading + * @close: user defined callback to close the "firmware" to clean up + * after loading + * @load: user defined callback to load the firmware contents to target + * memory or local memory + * @features: loader supported features. e.g. seek + */ +struct image_store_ops { + int (*open)(void *store, const char *path, const void **img_data); + void (*close)(void *store); + int (*load)(void *store, size_t offset, size_t size, + const void **data, + metal_phys_addr_t pa, + struct metal_io_region *io, char is_blocking); + unsigned int features; }; -/* RemoteProc Loader functions. */ -struct remoteproc_loader *remoteproc_loader_init(enum loader_type type); -int remoteproc_loader_delete(struct remoteproc_loader *loader); -int remoteproc_loader_attach_firmware(struct remoteproc_loader *loader, - void *firmware_image); -void *remoteproc_loader_retrieve_entry_point(struct remoteproc_loader *loader); -void *remoteproc_loader_retrieve_resource_section(struct remoteproc_loader - *loader, unsigned int *size); -int remoteproc_loader_load_remote_firmware(struct remoteproc_loader *loader); -void *remoteproc_get_load_address(struct remoteproc_loader *loader); - -/* Supported loaders */ -extern int elf_loader_init(struct remoteproc_loader *loader); +/** + * struct loader_ops - loader oeprations + * @load_header: define how to get the executable headers + * @load_data: define how to load the target data + * @locate_rsc_table: define how to get the resource table target address, + * offset to the ELF image file and size of the resource + * table. + * @release: define how to release the loader + * @get_entry: get entry address + * @get_load_state: get load state from the image information + */ +struct loader_ops { + int (*load_header)(const void *img_data, size_t offset, size_t len, + void **img_info, int last_state, + size_t *noffset, size_t *nlen); + int (*load_data)(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize); + int (*locate_rsc_table)(void *img_info, metal_phys_addr_t *da, + size_t *offset, size_t *size); + void (*release)(void *img_info); + metal_phys_addr_t (*get_entry)(void *img_info); + int (*get_load_state)(void *img_info); +}; #if defined __cplusplus } #endif -#endif /* REMOTEPROC_LOADER_H_ */ +#endif /* REMOTEPROC_LOADER_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc_virtio.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc_virtio.h new file mode 100644 index 00000000000000..b06b951c4d508d --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/remoteproc_virtio.h @@ -0,0 +1,150 @@ +/* + * Remoteproc Virtio Framework + * + * Copyright(c) 2018 Xilinx Ltd. + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Texas Instruments 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 + * OWNER 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 REMOTEPROC_VIRTIO_H +#define REMOTEPROC_VIRTIO_H + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* define vdev notification funciton user should implement */ +typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); + +/** + * struct remoteproc_virtio + * @priv pointer to private data + * @notifyid notification id + * @vdev_rsc address of vdev resource + * @vdev_rsc_io metal I/O region of vdev_info, can be NULL + * @notify notification function + * @vdev virtio device + * @node list node + */ +struct remoteproc_virtio { + void *priv; + uint32_t notify_id; + void *vdev_rsc; + struct metal_io_region *vdev_rsc_io; + rpvdev_notify_func notify; + struct virtio_device vdev; + struct metal_list node; +}; + +/** + * rproc_virtio_create_vdev + * + * Create rproc virtio vdev + * + * @role: 0 - virtio master, 1 - virtio slave + * @notifyid: virtio device notification id + * @rsc: pointer to the virtio device resource + * @rsc_io: pointer to the virtio device resource I/O region + * @priv: pointer to the private data + * @notify: vdev and virtqueue notification function + * @rst_cb: reset virtio device callback + * + * return pointer to the created virtio device for success, + * NULL for failure. + */ +struct virtio_device * +rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, + void *rsc, struct metal_io_region *rsc_io, + void *priv, + rpvdev_notify_func notify, + virtio_dev_reset_cb rst_cb); + +/** + * rproc_virtio_remove_vdev + * + * Create rproc virtio vdev + * + * @vdev - pointer to the virtio device + */ +void rproc_virtio_remove_vdev(struct virtio_device *vdev); + +/** + * rproc_virtio_create_vring + * + * Create rproc virtio vring + * + * @vdev: pointer to the virtio device + * @index: vring index in the virtio device + * @notifyid: remoteproc vring notification id + * @va: vring virtual address + * @io: pointer to vring I/O region + * @num_desc: number of descriptors + * @align: vring alignment + * + * return 0 for success, negative value for failure. + */ +int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, + unsigned int notifyid, void *va, + struct metal_io_region *io, + unsigned int num_descs, unsigned int align); + +/** + * rproc_virtio_notified + * + * remoteproc virtio is got notified + * + * @vdev - pointer to the virtio device + * @notifyid - notify id + * + * return 0 for successful, negative value for failure + */ +int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid); + +/** + * rproc_virtio_wait_remote_ready + * + * Blocking function, waiting for the remote core is ready to start + * communications. + * + * @vdev - pointer to the virtio device + * + * return true when remote processor is ready. + */ +void rproc_virtio_wait_remote_ready(struct virtio_device *vdev); + +#if defined __cplusplus +} +#endif + +#endif /* REMOTEPROC_VIRTIO_H */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg.h index 241556345721b2..6c88d19d8da4b0 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg.h @@ -12,207 +12,171 @@ #ifndef _RPMSG_H_ #define _RPMSG_H_ -#include +#include +#include +#include +#include +#include +#include #if defined __cplusplus extern "C" { #endif -/* The feature bitmap for virtio rpmsg */ -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ -#define RPMSG_NAME_SIZE 32 -#define RPMSG_BUF_HELD (1U << 31) /* Flag to suggest to hold the buffer */ +/* Configurable parameters */ +#define RPMSG_NAME_SIZE (32) +#define RPMSG_ADDR_BMP_SIZE (4) -#define RPMSG_LOCATE_DATA(p) ((unsigned char *) p + sizeof (struct rpmsg_hdr)) - -/** - * struct rpmsg_hdr - common header for all rpmsg messages - * @src: source address - * @dst: destination address - * @reserved: reserved for future use - * @len: length of payload (in bytes) - * @flags: message flags - * - * Every message sent(/received) on the rpmsg bus begins with this header. - */ -OPENAMP_PACKED_BEGIN -struct rpmsg_hdr { - uint32_t src; - uint32_t dst; - uint32_t reserved; - uint16_t len; - uint16_t flags; -} OPENAMP_PACKED_END; +#define RPMSG_NS_EPT_ADDR (0x35) +#define RPMSG_ADDR_ANY 0xFFFFFFFF -/** - * struct rpmsg_hdr_reserved - this is the "union" of the rpmsg_hdr->reserved - * @rfu: reserved for future usage - * @idx: index of a buffer (not to be returned back to the buffer's pool) - * - * This structure has been introduced to keep the backward compatibility. - * It could be integrated into rpmsg_hdr struct, replacing the reserved field. - */ -struct rpmsg_hdr_reserved -{ - uint16_t rfu; /* reserved for future usage */ - uint16_t idx; -}; +/* Error macros. */ +#define RPMSG_SUCCESS 0 +#define RPMSG_ERROR_BASE -2000 +#define RPMSG_ERR_NO_MEM (RPMSG_ERROR_BASE - 1) +#define RPMSG_ERR_NO_BUFF (RPMSG_ERROR_BASE - 2) +#define RPMSG_ERR_PARAM (RPMSG_ERROR_BASE - 3) +#define RPMSG_ERR_DEV_STATE (RPMSG_ERROR_BASE - 4) +#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERROR_BASE - 5) +#define RPMSG_ERR_INIT (RPMSG_ERROR_BASE - 6) +#define RPMSG_ERR_ADDR (RPMSG_ERROR_BASE - 7) + +struct rpmsg_endpoint; +struct rpmsg_device; + +typedef int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data, + size_t len, uint32_t src, void *priv); +typedef void (*rpmsg_ns_unbind_cb)(struct rpmsg_endpoint *ept); +typedef void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev, + const char *name, uint32_t dest); /** - * struct rpmsg_ns_msg - dynamic name service announcement message - * @name: name of remote service that is published - * @addr: address of remote service that is published - * @flags: indicates whether service is created or destroyed + * struct rpmsg_endpoint - binds a local rpmsg address to its user + * @name:name of the service supported + * @rdev: pointer to the rpmsg device + * @addr: local address of the endpoint + * @dest_addr: address of the default remote endpoint binded. + * @cb: user rx callback, return value of this callback is reserved + * for future use, for now, only allow RPMSG_SUCCESS as return value. + * @ns_unbind_cb: end point service service unbind callback, called when remote + * ept is destroyed. + * @node: end point node. + * @addr: local rpmsg address + * @priv: private data for the driver's use * - * This message is sent across to publish a new service, or announce - * about its removal. When we receive these messages, an appropriate - * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe() - * or ->remove() handler of the appropriate rpmsg driver will be invoked - * (if/as-soon-as one is registered). + * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as + * it binds an rpmsg address with an rx callback handler. */ -OPENAMP_PACKED_BEGIN -struct rpmsg_ns_msg { +struct rpmsg_endpoint { char name[RPMSG_NAME_SIZE]; + struct rpmsg_device *rdev; uint32_t addr; - uint32_t flags; -} OPENAMP_PACKED_END; - -/** - * enum rpmsg_ns_flags - dynamic name service announcement flags - * - * @RPMSG_NS_CREATE: a new remote service was just created - * @RPMSG_NS_DESTROY: a known remote service was just destroyed - */ -enum rpmsg_ns_flags { - RPMSG_NS_CREATE = 0, - RPMSG_NS_DESTROY = 1, + uint32_t dest_addr; + rpmsg_ept_cb cb; + rpmsg_ns_unbind_cb ns_unbind_cb; + struct metal_list node; + void *priv; }; -#define RPMSG_ADDR_ANY 0xFFFFFFFF - /** - * rpmsg_channel - devices that belong to the rpmsg bus are called channels - * @name: channel name - * @src: local address - * @dst: destination address - * rdev: rpmsg remote device - * @ept: the rpmsg endpoint of this channel - * @state: channel state + * struct rpmsg_device_ops - RPMsg device operations + * @send_offchannel_raw: send RPMsg data */ -struct rpmsg_channel { - char name[RPMSG_NAME_SIZE]; - uint32_t src; - uint32_t dst; - struct remote_device *rdev; - struct rpmsg_endpoint *rp_ept; - unsigned int state; - struct metal_list node; +struct rpmsg_device_ops { + int (*send_offchannel_raw)(struct rpmsg_device *rdev, + uint32_t src, uint32_t dst, + const void *data, int size, int wait); }; /** - * channel_info - channel info - * @name: channel name - * @src: local address - * @dst: destination address + * struct rpmsg_device - representation of a RPMsg device + * @endpoints: list of endpoints + * @ns_ept: name service endpoint + * @bitmap: table endpoin address allocation. + * @lock: mutex lock for rpmsg management + * @ns_bind_cb: callback handler for name service announcement without local + * endpoints waiting to bind. + * @ops: RPMsg device operations */ - -struct channel_info { - char name[RPMSG_NAME_SIZE]; - uint32_t src; - uint32_t dest; +struct rpmsg_device { + struct metal_list endpoints; + struct rpmsg_endpoint ns_ept; + unsigned long bitmap[RPMSG_ADDR_BMP_SIZE]; + metal_mutex_t lock; + rpmsg_ns_bind_cb ns_bind_cb; + struct rpmsg_device_ops ops; }; /** - * struct rpmsg_endpoint - binds a local rpmsg address to its user - * @rp_chnl: rpmsg channel device - * @cb: rx callback handler - * @addr: local rpmsg address - * @priv: private data for the driver's use - * - * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as - * it binds an rpmsg address with an rx callback handler. - * - * Simple rpmsg drivers shouldn't use this struct directly, because - * things just work: every rpmsg driver provides an rx callback upon - * registering to the bus, and that callback is then bound to its rpmsg - * address when the driver is probed. When relevant inbound messages arrive - * (i.e. messages which their dst address equals to the src address of - * the rpmsg channel), the driver's handler is invoked to process it. + * rpmsg_send_offchannel_raw() - send a message across to the remote processor, + * specifying source and destination address. + * @ept: the rpmsg endpoint + * @data: payload of the message + * @len: length of the payload + * + * This function sends @data of length @len to the remote @dst address from + * the source @src address. + * The message will be sent to the remote processor which the channel belongs + * to. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. * - * More complicated drivers though, that do need to allocate additional rpmsg - * addresses, and bind them to different rx callbacks, must explicitly - * create additional endpoints by themselves (see rpmsg_create_ept()). + * Returns number of bytes it has sent or negative error value on failure. */ -struct rpmsg_endpoint { - struct rpmsg_channel *rp_chnl; - rpmsg_rx_cb_t cb; - uint32_t addr; - void *priv; - struct metal_list node; -}; - -struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl, - rpmsg_rx_cb_t cb, void *priv, - uint32_t addr); - -void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept); - -int -rpmsg_send_offchannel_raw(struct rpmsg_channel *, uint32_t, uint32_t, - const void *, int, int); +int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, + uint32_t dst, const void *data, int size, + int wait); /** * rpmsg_send() - send a message across to the remote processor - * @rpdev: the rpmsg channel - * @data: payload of message - * @len: length of payload + * @ept: the rpmsg endpoint + * @data: payload of the message + * @len: length of the payload * - * This function sends @data of length @len on the @rpdev channel. - * The message will be sent to the remote processor which the @rpdev - * channel belongs to, using @rpdev's source and destination addresses. + * This function sends @data of length @len based on the @ept. + * The message will be sent to the remote processor which the channel belongs + * to, using @ept's source and destination addresses. * In case there are no TX buffers available, the function will block until * one becomes available, or a timeout of 15 seconds elapses. When the latter * happens, -ERESTARTSYS is returned. * - * Can only be called from process context (for now). - * * Returns number of bytes it has sent or negative error value on failure. */ -static inline int rpmsg_send(struct rpmsg_channel *rpdev, const void *data, - int len) +static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, + int len) { - return rpmsg_send_offchannel_raw(rpdev, rpdev->src, rpdev->dst, - data, len, RPMSG_TRUE); + if (ept->dest_addr == RPMSG_ADDR_ANY) + return RPMSG_ERR_ADDR; + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, + len, true); } /** * rpmsg_sendto() - send a message across to the remote processor, specify dst - * @rpdev: the rpmsg channel + * @ept: the rpmsg endpoint * @data: payload of message * @len: length of payload * @dst: destination address * * This function sends @data of length @len to the remote @dst address. - * The message will be sent to the remote processor which the @rpdev - * channel belongs to, using @rpdev's source address. + * The message will be sent to the remote processor which the @ept + * channel belongs to, using @ept's source address. * In case there are no TX buffers available, the function will block until * one becomes available, or a timeout of 15 seconds elapses. When the latter * happens, -ERESTARTSYS is returned. * - * Can only be called from process context (for now). - * * Returns number of bytes it has sent or negative error value on failure. */ -static inline int rpmsg_sendto(struct rpmsg_channel *rpdev, const void *data, +static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data, int len, uint32_t dst) { - return rpmsg_send_offchannel_raw(rpdev, rpdev->src, dst, data, - len, RPMSG_TRUE); + return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, true); } /** * rpmsg_send_offchannel() - send a message using explicit src/dst addresses - * @rpdev: the rpmsg channel + * @ept: the rpmsg endpoint * @src: source address * @dst: destination address * @data: payload of message @@ -220,74 +184,69 @@ static inline int rpmsg_sendto(struct rpmsg_channel *rpdev, const void *data, * * This function sends @data of length @len to the remote @dst address, * and uses @src as the source address. - * The message will be sent to the remote processor which the @rpdev + * The message will be sent to the remote processor which the @ept * channel belongs to. * In case there are no TX buffers available, the function will block until * one becomes available, or a timeout of 15 seconds elapses. When the latter * happens, -ERESTARTSYS is returned. * - * Can only be called from process context (for now). - * * Returns number of bytes it has sent or negative error value on failure. */ -static inline int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, +static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, uint32_t src, uint32_t dst, const void *data, int len) { - return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, - RPMSG_TRUE); + return rpmsg_send_offchannel_raw(ept, src, dst, data, len, true); } /** * rpmsg_trysend() - send a message across to the remote processor - * @rpdev: the rpmsg channel + * @ept: the rpmsg endpoint * @data: payload of message * @len: length of payload * - * This function sends @data of length @len on the @rpdev channel. - * The message will be sent to the remote processor which the @rpdev - * channel belongs to, using @rpdev's source and destination addresses. + * This function sends @data of length @len on the @ept channel. + * The message will be sent to the remote processor which the @ept + * channel belongs to, using @ept's source and destination addresses. * In case there are no TX buffers available, the function will immediately * return -ENOMEM without waiting until one becomes available. * - * Can only be called from process context (for now). - * * Returns number of bytes it has sent or negative error value on failure. */ -static inline int rpmsg_trysend(struct rpmsg_channel *rpdev, const void *data, +static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data, int len) { - return rpmsg_send_offchannel_raw(rpdev, rpdev->src, rpdev->dst, - data, len, RPMSG_FALSE); + if (ept->dest_addr == RPMSG_ADDR_ANY) + return RPMSG_ERR_ADDR; + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, + len, false); } /** - * rpmsg_trysendto() - send a message across to the remote processor, specify dst - * @rpdev: the rpmsg channel + * rpmsg_trysendto() - send a message across to the remote processor, + * specify dst + * @ept: the rpmsg endpoint * @data: payload of message * @len: length of payload * @dst: destination address * * This function sends @data of length @len to the remote @dst address. - * The message will be sent to the remote processor which the @rpdev - * channel belongs to, using @rpdev's source address. + * The message will be sent to the remote processor which the @ept + * channel belongs to, using @ept's source address. * In case there are no TX buffers available, the function will immediately * return -ENOMEM without waiting until one becomes available. * - * Can only be called from process context (for now). - * * Returns number of bytes it has sent or negative error value on failure. */ -static inline int rpmsg_trysendto(struct rpmsg_channel *rpdev, const void *data, +static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, const void *data, int len, uint32_t dst) { - return rpmsg_send_offchannel_raw(rpdev, rpdev->src, dst, data, len, - RPMSG_FALSE); + return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, false); } /** * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses - * @rpdev: the rpmsg channel + * @ept: the rpmsg endpoint * @src: source address * @dst: destination address * @data: payload of message @@ -295,278 +254,101 @@ static inline int rpmsg_trysendto(struct rpmsg_channel *rpdev, const void *data, * * This function sends @data of length @len to the remote @dst address, * and uses @src as the source address. - * The message will be sent to the remote processor which the @rpdev + * The message will be sent to the remote processor which the @ept * channel belongs to. * In case there are no TX buffers available, the function will immediately * return -ENOMEM without waiting until one becomes available. * - * Can only be called from process context (for now). - * * Returns number of bytes it has sent or negative error value on failure. */ -static inline int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, +static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, uint32_t src, uint32_t dst, const void *data, int len) { - return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, - RPMSG_FALSE); + return rpmsg_send_offchannel_raw(ept, src, dst, data, len, false); } /** - * @brief Holds the rx buffer for usage outside the receive callback. - * - * Calling this function prevents the RPMsg receive buffer from being released - * back to the pool of shmem buffers. This API can only be called at rx - * callback context (rpmsg_rx_cb_t). With this API, the application doesn't - * need to copy the message in rx callback. Instead, the rx buffer base address - * is saved in application context and further processed in application - * process. After the message is processed, the application can release the rx - * buffer for future reuse in vring by calling the rpmsg_release_rx_buffer() - * function. - * - * @param[in] rpdev The rpmsg channel - * @param[in] rxbuf RX buffer with message payload - * - * @see rpmsg_release_rx_buffer + * rpmsg_init_ept - initialize rpmsg endpoint + * + * Initialize an RPMsg endpoint with a name, source address, + * remoteproc address, endpoitn callback, and destroy endpoint callback. + * + * @ept: pointer to rpmsg endpoint + * @name: service name associated to the endpoint + * @src: local address of the endpoint + * @dest: target address of the endpoint + * @cb: endpoint callback + * @ns_unbind_cb: end point service unbind callback, called when remote ept is + * destroyed. */ -void rpmsg_hold_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf); - -/** - * @brief Releases the rx buffer for future reuse in vring. - * - * This API can be called at process context when the message in rx buffer is - * processed. - * - * @param rpdev - the rpmsg channel - * @param rxbuf - rx buffer with message payload - * - * @see rpmsg_hold_rx_buffer - */ -void rpmsg_release_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf); - -/** - * @brief Gets the tx buffer for message payload. - * - * This API can only be called at process context to get the tx buffer in vring. - * By this way, the application can directly put its message into the vring tx - * buffer without copy from an application buffer. - * It is the application responsibility to correctly fill the allocated tx - * buffer by data and passing correct parameters to the rpmsg_send_nocopy() or - * rpmsg_sendto_nocopy() function to perform data no-copy-send mechanism. - * - * @param[in] rpdev Pointer to rpmsg channel - * @param[in] size Pointer to store tx buffer size - * @param[in] wait Boolean, wait or not for buffer to become available - * - * @return The tx buffer address on success and NULL on failure - * - * @see rpmsg_send_offchannel_nocopy - * @see rpmsg_sendto_nocopy - * @see rpmsg_send_nocopy - */ -void *rpmsg_get_tx_payload_buffer(struct rpmsg_channel *rpdev, uint32_t *size, - int wait); - -/** - * @brief Sends a message in tx buffer allocated by - * rpmsg_get_tx_payload_buffer() - * - * using explicit src/dst addresses. - * - * This function sends txbuf of length len to the remote dst address, - * and uses src as the source address. - * The message will be sent to the remote processor which the rpdev - * channel belongs to. - * The application has to take the responsibility for: - * 1. tx buffer allocation (rpmsg_get_tx_payload_buffer() ) - * 2. filling the data to be sent into the pre-allocated tx buffer - * 3. not exceeding the buffer size when filling the data - * 4. data cache coherency - * - * After the rpmsg_send_offchannel_nocopy() function is issued the tx buffer is - * no more owned by the sending task and must not be touched anymore unless the - * rpmsg_send_offchannel_nocopy() function fails and returns an error. In that - * case the application should try to re-issue the - * rpmsg_send_offchannel_nocopy() again and if it is still not possible to send - * the message and the application wants to give it up from whatever reasons - * the rpmsg_release_rx_buffer function could be called, passing the pointer to - * the tx buffer to be released as a parameter. - * - * @param[in] rpdev The rpmsg channel - * @param[in] src Source address - * @param[in] dst Destination address - * @param[in] txbuf TX buffer with message filled - * @param[in] len Length of payload - * - * @return number of bytes it has sent or negative error value on failure. - * - * @see rpmsg_get_tx_payload_buffer - * @see rpmsg_sendto_nocopy - * @see rpmsg_send_nocopy - */ -int rpmsg_send_offchannel_nocopy(struct rpmsg_channel *rpdev, uint32_t src, - uint32_t dst, void *txbuf, int len); - -/** - * @brief Sends a message in tx buffer allocated by - * rpmsg_get_tx_payload_buffer() - * - * across to the remote processor, specify dst. - * - * This function sends txbuf of length len to the remote dst address. - * The message will be sent to the remote processor which the rpdev - * channel belongs to, using rpdev's source address. - * The application has to take the responsibility for: - * 1. tx buffer allocation (rpmsg_get_tx_payload_buffer() ) - * 2. filling the data to be sent into the pre-allocated tx buffer - * 3. not exceeding the buffer size when filling the data - * 4. data cache coherency - * - * After the rpmsg_sendto_nocopy() function is issued the tx buffer is no more - * owned by the sending task and must not be touched anymore unless the - * rpmsg_sendto_nocopy() function fails and returns an error. In that case the - * application should try to re-issue the rpmsg_sendto_nocopy() again and if - * it is still not possible to send the message and the application wants to - * give it up from whatever reasons the rpmsg_release_rx_buffer function - * could be called, - * passing the pointer to the tx buffer to be released as a parameter. - * - * @param[in] rpdev The rpmsg channel - * @param[in] txbuf TX buffer with message filled - * @param[in] len Length of payload - * @param[in] dst Destination address - * - * @return number of bytes it has sent or negative error value on failure. - * - * @see rpmsg_get_tx_payload_buffer - * @see rpmsg_send_offchannel_nocopy - * @see rpmsg_send_nocopy - */ -static inline -int rpmsg_sendto_nocopy(struct rpmsg_channel *rpdev, void *txbuf, int len, - uint32_t dst) +static inline void rpmsg_init_ept(struct rpmsg_endpoint *ept, + const char *name, + uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, + rpmsg_ns_unbind_cb ns_unbind_cb) { - if (!rpdev) - return RPMSG_ERR_PARAM; - - return rpmsg_send_offchannel_nocopy(rpdev, (uint32_t)rpdev->src, dst, - txbuf, len); -} - -/** - * @brief Sends a message in tx buffer allocated by - * rpmsg_get_tx_payload_buffer() across to the remote processor. - * - * This function sends txbuf of length len on the rpdev channel. - * The message will be sent to the remote processor which the rpdev - * channel belongs to, using rpdev's source and destination addresses. - * The application has to take the responsibility for: - * 1. tx buffer allocation (rpmsg_get_tx_payload_buffer() ) - * 2. filling the data to be sent into the pre-allocated tx buffer - * 3. not exceeding the buffer size when filling the data - * 4. data cache coherency - * - * After the rpmsg_send_nocopy() function is issued the tx buffer is no more - * owned by the sending task and must not be touched anymore unless the - * rpmsg_send_nocopy() function fails and returns an error. In that case the - * application should try to re-issue the rpmsg_send_nocopy() again and if - * it is still not possible to send the message and the application wants to - * give it up from whatever reasons the rpmsg_release_rx_buffer function - * could be called, passing the pointer to the tx buffer to be released as a - * parameter. - * - * @param[in] rpdev The rpmsg channel - * @param[in] txbuf TX buffer with message filled - * @param[in] len Length of payload - * - * @return 0 on success and an appropriate error value on failure - * - * @see rpmsg_get_tx_payload_buffer - * @see rpmsg_send_offchannel_nocopy - * @see rpmsg_sendto_nocopy - */ -static inline -int rpmsg_send_nocopy(struct rpmsg_channel *rpdev, void *txbuf, int len) -{ - if (!rpdev) - return RPMSG_ERR_PARAM; - - return rpmsg_send_offchannel_nocopy(rpdev, rpdev->src, rpdev->dst, - txbuf, len); + strncpy(ept->name, name, sizeof(ept->name)); + ept->addr = src; + ept->dest_addr = dest; + ept->cb = cb; + ept->ns_unbind_cb = ns_unbind_cb; } /** - * rpmsg_init + * rpmsg_create_ept - create rpmsg endpoint and register it to rpmsg device * - * Thus function allocates and initializes the rpmsg driver resources for - * the given hil_proc.The successful return from this function leaves - * fully enabled IPC link. + * Create a RPMsg endpoint, initialize it with a name, source address, + * remoteproc address, endpoitn callback, and destroy endpoint callback, + * and register it to the RPMsg device. * - * @param proc - pointer to hil_proc - * @param rdev - pointer to newly created remote device - * @param channel_created - callback function for channel creation - * @param channel_destroyed - callback function for channel deletion - * @param default_cb - default callback for channel - * @param role - role of the other device, Master or Remote - * @return - status of function execution + * @ept: pointer to rpmsg endpoint + * @name: service name associated to the endpoint + * @src: local address of the endpoint + * @dest: target address of the endpoint + * @cb: endpoint callback + * @ns_unbind_cb: end point service unbind callback, called when remote ept is + * destroyed. * - */ - -int rpmsg_init(struct hil_proc *proc, - struct remote_device **rdev, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, - rpmsg_rx_cb_t default_cb, int role); - -/** - * rpmsg_deinit - * - * Thus function releases the rpmsg driver resources for given remote - * instance. - * - * @param rdev - pointer to device de-init + * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as + * it binds an rpmsg address with an rx callback handler. * - * @return - none + * Rpmsg client should create an endpoint to discuss with remote. rpmsg client + * provide at least a channel name, a callback for message notification and by + * default endpoint source address should be set to RPMSG_ADDR_ANY. * + * As an option Some rpmsg clients can specify an endpoint with a specific + * source address. */ -void rpmsg_deinit(struct remote_device *rdev); -/** - * rpmsg_get_buffer_size - * - * Returns buffer size available for sending messages. - * - * @param channel - pointer to rpmsg channel/device - * - * @return - buffer size - * - */ -int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl); +int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, + const char *name, uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, rpmsg_ns_unbind_cb ns_unbind_cb); /** - * rpmsg_create_channel - * - * Creates RPMSG channel with the given name for remote device. - * - * @param rdev - pointer to rpmsg remote device - * @param name - channel name + * rpmsg_destroy_ept - destroy rpmsg endpoint and unregister it from rpmsg + * device * - * @return - pointer to new rpmsg channel + * @ept: pointer to the rpmsg endpoint * + * It unregisters the rpmsg endpoint from the rpmsg device and calls the + * destroy endpoint callback if it is provided. */ -struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev, - char *name); +void rpmsg_destroy_ept(struct rpmsg_endpoint *ept); /** - * rpmsg_delete_channel + * is_rpmsg_ept_ready - check if the rpmsg endpoint ready to send * - * Deletes the given RPMSG channel. The channel must first be created with the - * rpmsg_create_channel API. - * - * @param rp_chnl - pointer to rpmsg channel to delete + * @ept: pointer to rpmsg endpoint * + * Returns 1 if the rpmsg endpoint has both local addr and destination + * addr set, 0 otherwise */ -void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl); +static inline unsigned int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept) +{ + return (ept->dest_addr != RPMSG_ADDR_ANY && + ept->addr != RPMSG_ADDR_ANY); +} #if defined __cplusplus } diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_core.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_core.h deleted file mode 100644 index 248ad15b5fe19e..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_core.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _RPMSG_CORE_H_ -#define _RPMSG_CORE_H_ - -#include -#include -#include -#include -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* Configurable parameters */ -#define RPMSG_BUFFER_SIZE 512 -#define RPMSG_MAX_VQ_PER_RDEV 2 -#define RPMSG_NS_EPT_ADDR 0x35 -#define RPMSG_ADDR_BMP_SIZE 4 - -/* Definitions for device types , null pointer, etc.*/ -#define RPMSG_SUCCESS 0 -#define RPMSG_NULL (void *)0 -#define RPMSG_REMOTE 0 -#define RPMSG_MASTER 1 -#define RPMSG_TRUE 1 -#define RPMSG_FALSE 0 - -/* RPMSG channel states. */ -#define RPMSG_CHNL_STATE_IDLE 0 -#define RPMSG_CHNL_STATE_NS 1 -#define RPMSG_CHNL_STATE_ACTIVE 2 - -/* Remote processor/device states. */ -#define RPMSG_DEV_STATE_IDLE 0 -#define RPMSG_DEV_STATE_ACTIVE 1 - -/* Total tick count for 15secs - 1msec tick. */ -#define RPMSG_TICK_COUNT 15000 - -/* Time to wait - In multiple of 10 msecs. */ -#define RPMSG_TICKS_PER_INTERVAL 10 - -/* Error macros. */ -#define RPMSG_ERROR_BASE -2000 -#define RPMSG_ERR_NO_MEM (RPMSG_ERROR_BASE - 1) -#define RPMSG_ERR_NO_BUFF (RPMSG_ERROR_BASE - 2) -#define RPMSG_ERR_MAX_VQ (RPMSG_ERROR_BASE - 3) -#define RPMSG_ERR_PARAM (RPMSG_ERROR_BASE - 4) -#define RPMSG_ERR_DEV_STATE (RPMSG_ERROR_BASE - 5) -#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERROR_BASE - 6) -#define RPMSG_ERR_DEV_INIT (RPMSG_ERROR_BASE - 7) -#define RPMSG_ERR_DEV_ADDR (RPMSG_ERROR_BASE - 8) - -/* Zero-Copy extension macros */ -#define RPMSG_HDR_FROM_BUF(buf) (struct rpmsg_hdr *)((char*)buf - \ - sizeof(struct rpmsg_hdr)) - -struct rpmsg_channel; -typedef void (*rpmsg_rx_cb_t) (struct rpmsg_channel *, void *, int, void *, - unsigned long); -typedef void (*rpmsg_chnl_cb_t) (struct rpmsg_channel * rp_chl); -/** - * remote_device - * - * This structure is maintained by RPMSG driver to represent remote device/core. - * - * @virtd_dev - virtio device for remote core - * @rvq - Rx virtqueue for virtio device - * @tvq - Tx virtqueue for virtio device - * @proc - reference to remote processor - * @rp_channels - rpmsg channels list for the device - * @rp_endpoints - rpmsg endpoints list for the device - * @mem_pool - shared memory pool - * @bitmap - bitmap for channels addresses - * @channel_created - create channel callback - * @channel_destroyed - delete channel callback - * @default_cb - default callback handler for RX data on channel - * @lock - remote device mutex - * @role - role of the remote device, RPMSG_MASTER/RPMSG_REMOTE - * @state - remote device state, IDLE/ACTIVE - * @support_ns - if device supports name service announcement - * - */ -struct remote_device { - struct virtio_device virt_dev; - struct virtqueue *rvq; - struct virtqueue *tvq; - struct hil_proc *proc; - struct metal_list rp_channels; - struct metal_list rp_endpoints; - struct sh_mem_pool *mem_pool; - unsigned long bitmap[RPMSG_ADDR_BMP_SIZE]; - rpmsg_chnl_cb_t channel_created; - rpmsg_chnl_cb_t channel_destroyed; - rpmsg_rx_cb_t default_cb; - metal_mutex_t lock; - unsigned int role; - unsigned int state; - int support_ns; -}; - -/* Core functions */ -int rpmsg_start_ipc(struct remote_device *rdev); -struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev, - char *name, unsigned long src, - unsigned long dst); -void _rpmsg_delete_channel(struct rpmsg_channel *rp_chnl); -struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev, - rpmsg_rx_cb_t cb, void *priv, - unsigned long addr); -void _destroy_endpoint(struct remote_device *rdev, - struct rpmsg_endpoint *rp_ept); -int rpmsg_send_ns_message(struct remote_device *rdev, - struct rpmsg_channel *rp_chnl, unsigned long flags); -int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer, - unsigned long len, unsigned short idx); -void rpmsg_return_buffer(struct remote_device *rdev, void *buffer, - unsigned long len, unsigned short idx); -void *rpmsg_get_tx_buffer(struct remote_device *rdev, unsigned long *len, - unsigned short *idx); -void rpmsg_free_buffer(struct remote_device *rdev, void *buffer); -void rpmsg_free_channel(struct rpmsg_channel *rp_chnl); -void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len, - unsigned short *idx); -int rpmsg_get_address(unsigned long *bitmap, int size); -int rpmsg_release_address(unsigned long *bitmap, int size, int addr); -int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr); -int rpmsg_set_address(unsigned long *bitmap, int size, int addr); -void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, - void *data, int len, void *priv, unsigned long src); - -/* Remote device functions */ -int rpmsg_rdev_init(struct hil_proc *proc, - struct remote_device **rdev, int role, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, - rpmsg_rx_cb_t default_cb); -void rpmsg_rdev_deinit(struct remote_device *rdev); -int rpmsg_rdev_remote_ready(struct remote_device *rdev); -struct rpmsg_channel *rpmsg_rdev_get_chnl_from_id(struct remote_device *rdev, - char *rp_chnl_id); -struct rpmsg_endpoint *rpmsg_rdev_get_endpoint_from_addr( - struct remote_device *rdev, - unsigned long addr); -int rpmsg_rdev_notify(struct remote_device *rdev); -int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs, - const char *names[], vq_callback * callbacks[], - struct virtqueue *vqs[]); -unsigned char rpmsg_rdev_get_status(struct virtio_device *dev); - -void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status); - -uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev); - -void rpmsg_rdev_set_feature(struct virtio_device *dev, uint32_t feature); - -uint32_t rpmsg_rdev_negotiate_feature(struct virtio_device *dev, - uint32_t features); -/* - * Read/write a variable amount from the device specific (ie, network) - * configuration region. This region is encoded in the same endian as - * the guest. - */ -void rpmsg_rdev_read_config(struct virtio_device *dev, uint32_t offset, - void *dst, int length); -void rpmsg_rdev_write_config(struct virtio_device *dev, uint32_t offset, - void *src, int length); -void rpmsg_rdev_reset(struct virtio_device *dev); - -#if defined __cplusplus -} -#endif - -#endif /* _RPMSG_CORE_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_retarget.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_retarget.h index d05d07420ff486..5645e52ed6840d 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_retarget.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_retarget.h @@ -1,59 +1,116 @@ -#include -#include -#include - #ifndef RPMSG_RETARGET_H #define RPMSG_RETARGET_H +#include +#include +#include + #if defined __cplusplus extern "C" { #endif -/* RPC response buffer size */ -#define RPC_BUFF_SIZE 512 +/* File Operations System call definitions */ +#define OPEN_SYSCALL_ID 0x1UL +#define CLOSE_SYSCALL_ID 0x2UL +#define WRITE_SYSCALL_ID 0x3UL +#define READ_SYSCALL_ID 0x4UL +#define ACK_STATUS_ID 0x5UL -/* System call definitions */ -#define OPEN_SYSCALL_ID 1 -#define CLOSE_SYSCALL_ID 2 -#define WRITE_SYSCALL_ID 3 -#define READ_SYSCALL_ID 4 -#define ACK_STATUS_ID 5 -#define TERM_SYSCALL_ID 6 +#define TERM_SYSCALL_ID 0x6UL -#define FILE_NAME_LEN 50 +#define DEFAULT_PROXY_ENDPOINT 0xFFUL -/* Proxy device endpoint ID */ -#define PROXY_ENDPOINT 127 +struct rpmsg_rpc_data; -typedef void (*rpc_shutdown_cb) (struct rpmsg_channel *); +typedef int (*rpmsg_rpc_poll)(void *arg); +typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_data *rpc); -struct _rpc_data { - struct rpmsg_channel *rpmsg_chnl; - struct rpmsg_endpoint *rp_ept; - metal_mutex_t rpc_lock; - atomic_int sync; - struct _sys_rpc *rpc; - struct _sys_rpc *rpc_response; - rpc_shutdown_cb shutdown_cb; +struct rpmsg_rpc_syscall_header { + int32_t int_field1; + int32_t int_field2; + uint32_t data_len; }; -struct _sys_call_args { - int int_field1; - int int_field2; - unsigned int data_len; - char data[0]; +struct rpmsg_rpc_syscall { + uint32_t id; + struct rpmsg_rpc_syscall_header args; }; -/* System call rpc data structure */ -struct _sys_rpc { - unsigned int id; - struct _sys_call_args sys_call_args; +struct rpmsg_rpc_data { + struct rpmsg_endpoint ept; + int ept_destroyed; + atomic_int nacked; + void *respbuf; + size_t respbuf_len; + rpmsg_rpc_poll poll; + void *poll_arg; + rpmsg_rpc_shutdown_cb shutdown_cb; + metal_mutex_t lock; + struct metal_spinlock buflock; }; -/* API prototypes */ -int rpmsg_retarget_init(struct rpmsg_channel *rp_chnl, rpc_shutdown_cb cb); -int rpmsg_retarget_deinit(struct rpmsg_channel *rp_chnl); -int rpmsg_retarget_send(void *data, int len); +/** + * rpmsg_rpc_init - initialize RPMsg remote procedure call + * + * This function is to intialize the remote procedure call + * global data. RPMsg RPC will send request to remote and + * wait for callback. + * + * @rpc: pointer to the global remote procedure call data + * @rdev: pointer to the rpmsg device + * @ept_name: name of the endpoint used by RPC + * @ept_addr: address of the endpoint used by RPC + * @ept_raddr: remote address of the endpoint used by RPC + * @poll_arg: pointer to poll function argument + * @poll: poll function + * @shutdown_cb: shutdown callback function + * + * return 0 for success, and negative value for failure. + */ +int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc, + struct rpmsg_device *rdev, + const char *ept_name, uint32_t ept_addr, + uint32_t ept_raddr, + void *poll_arg, rpmsg_rpc_poll poll, + rpmsg_rpc_shutdown_cb shutdown_cb); + +/** + * rpmsg_rpc_release - release RPMsg remote procedure call + * + * This function is to release remoteproc procedure call + * global data. + * + * @rpc: pointer to the globacl remote procedure call + */ +void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc); + +/** + * rpmsg_rpc_send - Request RPMsg RPC call + * + * This function sends RPC request it will return with the length + * of data and the response buffer. + * + * @rpc: pointer to remoteproc procedure call data struct + * @req: pointer to request buffer + * @len: length of the request data + * @resp: pointer to where store the response buffer + * @resp_len: length of the response buffer + * + * return length of the received response, negative value for failure. + */ +int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc, + void *req, size_t len, + void *resp, size_t resp_len); + +/** + * rpmsg_set_default_rpc - set default RPMsg RPC data + * + * The default RPC data is used to redirect standard C file operations + * to RPMsg channels. + * + * @rpc: pointer to remoteproc procedure call data struct + */ +void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc); #if defined __cplusplus } diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_virtio.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_virtio.h new file mode 100644 index 00000000000000..b1369cacb497ee --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rpmsg_virtio.h @@ -0,0 +1,190 @@ +/* + * rpmsg based on virtio + * + * Copyright (C) 2018 Linaro, Inc. + * + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _RPMSG_VIRTIO_H_ +#define _RPMSG_VIRTIO_H_ + +#include +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* Configurable parameters */ +#ifndef RPMSG_BUFFER_SIZE +#define RPMSG_BUFFER_SIZE (512) +#endif + +/* The feature bitmap for virtio rpmsg */ +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ + +struct rpmsg_virtio_shm_pool; +/** + * struct rpmsg_virtio_shm_pool - shared memory pool used for rpmsg buffers + * @get_buffer: function to get buffer from the pool + * @base: base address of the memory pool + * @avail: available memory size + * @size: total pool size + */ +struct rpmsg_virtio_shm_pool { + void *base; + size_t avail; + size_t size; +}; + +/** + * struct rpmsg_virtio_device - representation of a rpmsg device based on virtio + * @rdev: rpmsg device, first property in the struct + * @vdev: pointer to the virtio device + * @rvq: pointer to receive virtqueue + * @svq: pointer to send virtqueue + * @shbuf_io: pointer to the shared buffer I/O region + * @shpool: pointer to the shared buffers pool + * @endpoints: list of endpoints. + */ +struct rpmsg_virtio_device { + struct rpmsg_device rdev; + struct virtio_device *vdev; + struct virtqueue *rvq; + struct virtqueue *svq; + struct metal_io_region *shbuf_io; + struct rpmsg_virtio_shm_pool *shpool; +}; + +#define RPMSG_REMOTE VIRTIO_DEV_SLAVE +#define RPMSG_MASTER VIRTIO_DEV_MASTER +static inline unsigned int + rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->role; +} + +static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev, + uint8_t status) +{ + rvdev->vdev->func->set_status(rvdev->vdev, status); +} + +static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->func->get_status(rvdev->vdev); +} + +static inline uint32_t + rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->func->get_features(rvdev->vdev); +} + +static inline int + rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, + int flags, unsigned int nvqs, + const char *names[], + vq_callback * callbacks[]) +{ + return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names, + callbacks); +} + +/** + * rpmsg_virtio_get_buffer_size - get rpmsg virtio buffer size + * + * @rdev - pointer to the rpmsg device + * + * @return - next available buffer size for text, negative value for failure + */ +int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev); + +/** + * rpmsg_init_vdev - initialize rpmsg virtio device + * Master side: + * Initialize RPMsg virtio queues and shared buffers, the address of shm can be + * ANY. In this case, function will get shared memory from system shared memory + * pools. If the vdev has RPMsg name service feature, this API will create an + * name service endpoint. + * + * Slave side: + * This API will not return until the driver ready is set by the master side. + * + * @param rvdev - pointer to the rpmsg virtio device + * @param vdev - pointer to the virtio device + * @param ns_bind_cb - callback handler for name service announcement without + * local endpoints waiting to bind. + * @param shm_io - pointer to the share memory I/O region. + * @param shpool - pointer to shared memory pool. rpmsg_virtio_init_shm_pool has + * to be called first to fill this structure. + * + * @return - status of function execution + */ +int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool); + +/** + * rpmsg_deinit_vdev - deinitialize rpmsg virtio device + * + * @param rvdev - pointer to the rpmsg virtio device + */ +void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev); + +/** + * rpmsg_virtio_init_shm_pool - initialize default shared buffers pool + * + * RPMsg virtio has default shared buffers pool implementation. + * The memory assigned to this pool will be dedicated to the RPMsg + * virtio. This function has to be called before calling rpmsg_init_vdev, + * to initialize the rpmsg_virtio_shm_pool structure. + * + * @param shpool - pointer to the shared buffers pool structure + * @param shbuf - pointer to the beginning of shared buffers + * @param size - shared buffers total size + */ +void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, + void *shbuf, size_t size); + +/** + * rpmsg_virtio_get_rpmsg_device - get RPMsg device from RPMsg virtio device + * + * @param rvdev - pointer to RPMsg virtio device + * @return - RPMsg device pointed by RPMsg virtio device + */ +static inline struct rpmsg_device * +rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev) +{ + return &rvdev->rdev; +} + +/** + * rpmsg_virtio_shm_pool_get_buffer - get buffer in the shared memory pool + * + * RPMsg virtio has default shared buffers pool implementation. + * The memory assigned to this pool will be dedicated to the RPMsg + * virtio. If you prefer to have other shared buffers allocation, + * you can implement your rpmsg_virtio_shm_pool_get_buffer function. + * + * @param shpool - pointer to the shared buffers pool + * @param size - shared buffers total size + * @return - buffer pointer if free buffer is available, NULL otherwise. + */ +metal_weak void * +rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, + size_t size); + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_VIRTIO_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rsc_table_parser.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rsc_table_parser.h index c7af24154d811f..b0aa27e2d88f8f 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rsc_table_parser.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/rsc_table_parser.h @@ -9,7 +9,6 @@ #define RSC_TABLE_PARSER_H #include -#include #if defined __cplusplus extern "C" { @@ -20,18 +19,43 @@ extern "C" { #define RSC_TAB_MAX_VRINGS 2 /* Standard control request handling. */ -typedef int (*rsc_handler) (struct remote_proc * rproc, void *rsc); - -/* Function prototypes */ -int handle_rsc_table(struct remote_proc *rproc, - struct resource_table *rsc_table, int len); -int handle_carve_out_rsc(struct remote_proc *rproc, void *rsc); -int handle_trace_rsc(struct remote_proc *rproc, void *rsc); -int handle_dev_mem_rsc(struct remote_proc *rproc, void *rsc); -int handle_vdev_rsc(struct remote_proc *rproc, void *rsc); -int handle_rproc_mem_rsc(struct remote_proc *rproc, void *rsc); -int handle_fw_chksum_rsc(struct remote_proc *rproc, void *rsc); -int handle_mmu_rsc(struct remote_proc *rproc, void *rsc); +typedef int (*rsc_handler) (struct remoteproc *rproc, void *rsc); + +/** + * handle_rsc_table + * + * This function parses resource table. + * + * @param rproc - pointer to remote remoteproc + * @param rsc_table - resource table to parse + * @param size - size of rsc table + * @param io - pointer to the resource table I/O region + * It can be NULL if the resource table + * is in the local memory. + * + * @returns - execution status + * + */ +int handle_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, int len, + struct metal_io_region *io); +int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc); +int handle_trace_rsc(struct remoteproc *rproc, void *rsc); +int handle_vdev_rsc(struct remoteproc *rproc, void *rsc); +int handle_vendor_rsc(struct remoteproc *rproc, void *rsc); + +/** + * find_rsc + * + * find out location of a resource type in the resource table. + * + * @rsc_table - pointer to the resource table + * @rsc_type - type of the resource + * @index - index of the resource of the specified type + * + * return the offset to the resource on success, or 0 on failure + */ +size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index); #if defined __cplusplus } diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/sh_mem.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/sh_mem.h deleted file mode 100644 index f535ec39159d8c..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/sh_mem.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * sh_mem.c - * - * COMPONENT - * - * IPC Stack for uAMP systems. - * - * DESCRIPTION - * - * Header file for fixed buffer size memory management service. Currently - * it is being used to manage shared memory. - * - **************************************************************************/ -#ifndef SH_MEM_H_ -#define SH_MEM_H_ - -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* Macros */ -#define BITMAP_WORD_SIZE (sizeof(unsigned long) << 3) -#define WORD_SIZE sizeof(unsigned long) -#define WORD_ALIGN(a) (((a) & (WORD_SIZE-1)) != 0)? \ - (((a) & (~(WORD_SIZE-1))) + sizeof(unsigned long)):(a) -#define SH_MEM_POOL_LOCATE_BITMAP(pool,idx) ((unsigned char *) pool \ - + sizeof(struct sh_mem_pool) \ - + (BITMAP_WORD_SIZE * idx)) - -/* - * This structure represents a shared memory pool. - * - * @start_addr - start address of shared memory region - * @lock - lock to ensure exclusive access - * @size - size of shared memory* - * @buff_size - size of each buffer - * @total_buffs - total number of buffers in shared memory region - * @used_buffs - number of used buffers - * @bmp_size - size of bitmap array - * - */ - -struct sh_mem_pool { - void *start_addr; - metal_mutex_t lock; - unsigned int size; - unsigned int buff_size; - unsigned int total_buffs; - unsigned int used_buffs; - unsigned int bmp_size; -}; - -/* APIs */ -struct sh_mem_pool *sh_mem_create_pool(void *start_addr, unsigned int size, - unsigned int buff_size); -void sh_mem_delete_pool(struct sh_mem_pool *pool); -void *sh_mem_get_buffer(struct sh_mem_pool *pool); -void sh_mem_free_buffer(void *ptr, struct sh_mem_pool *pool); -int get_first_zero_bit(unsigned long value); - -#if defined __cplusplus -} -#endif - -#endif /* SH_MEM_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio.h index 29278d45a4d12c..463079bf374180 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio.h @@ -8,21 +8,28 @@ #define _VIRTIO_H_ #include +#include #if defined __cplusplus extern "C" { #endif +/* TODO: define this as compiler flags */ +#ifndef VIRTIO_MAX_NUM_VRINGS +#define VIRTIO_MAX_NUM_VRINGS 2 +#endif + /* VirtIO device IDs. */ -#define VIRTIO_ID_NETWORK 0x01 -#define VIRTIO_ID_BLOCK 0x02 -#define VIRTIO_ID_CONSOLE 0x03 -#define VIRTIO_ID_ENTROPY 0x04 -#define VIRTIO_ID_BALLOON 0x05 -#define VIRTIO_ID_IOMEMORY 0x06 -#define VIRTIO_ID_RPMSG 0x07 /* virtio remote remote_proc messaging */ -#define VIRTIO_ID_SCSI 0x08 -#define VIRTIO_ID_9P 0x09 +#define VIRTIO_ID_NETWORK 0x01UL +#define VIRTIO_ID_BLOCK 0x02UL +#define VIRTIO_ID_CONSOLE 0x03UL +#define VIRTIO_ID_ENTROPY 0x04UL +#define VIRTIO_ID_BALLOON 0x05UL +#define VIRTIO_ID_IOMEMORY 0x06UL +#define VIRTIO_ID_RPMSG 0x07UL /* remote processor messaging */ +#define VIRTIO_ID_SCSI 0x08UL +#define VIRTIO_ID_9P 0x09UL +#define VIRTIO_DEV_ANY_ID (-1)UL /* Status byte for guest to report progress. */ #define VIRTIO_CONFIG_STATUS_ACK 0x01 @@ -31,6 +38,15 @@ extern "C" { #define VIRTIO_CONFIG_STATUS_NEEDS_RESET 0x40 #define VIRTIO_CONFIG_STATUS_FAILED 0x80 +/* Virtio device role */ +#define VIRTIO_DEV_MASTER 0UL +#define VIRTIO_DEV_SLAVE 1UL + +struct virtio_device_id { + uint32_t device; + uint32_t vendor; +}; + /* * Generate interrupt when the virtqueue ring is * completely used, even if we've suppressed them. @@ -51,48 +67,70 @@ extern "C" { #define VIRTIO_TRANSPORT_F_START 28 #define VIRTIO_TRANSPORT_F_END 32 -typedef struct _virtio_dispatch_ virtio_dispatch; +typedef void (*virtio_dev_reset_cb)(struct virtio_device *vdev); + +struct virtio_dispatch; struct virtio_feature_desc { uint32_t vfd_val; const char *vfd_str; }; +/** + * struct proc_shm + * + * This structure is maintained by hardware interface layer for + * shared memory information. The shared memory provides buffers + * for use by the vring to exchange messages between the cores. + * + */ +struct virtio_buffer_info { + /* Start address of shared memory used for buffers. */ + void *vaddr; + /* Start physical address of shared memory used for buffers. */ + metal_phys_addr_t paddr; + /* sharmed memory I/O region */ + struct metal_io_region *io; + /* Size of shared memory. */ + unsigned long size; +}; + +/** + * struct remoteproc_vring - remoteproc vring structure + * @vq virtio queue + * @va logical address + * @notifyid vring notify id + * @num_descs number of descriptors + * @align vring alignment + * @io metal I/O region of the vring memory, can be NULL + */ +struct virtio_vring_info { + struct virtqueue *vq; + struct vring_alloc_info info; + uint32_t notifyid; + struct metal_io_region *io; +}; + /* * Structure definition for virtio devices for use by the * applications/drivers - * */ struct virtio_device { - /* - * Since there is no generic device structure so - * keep its type as void. The driver layer will take - * care of it. - */ - void *device; - - /* Device name */ - char *name; - - /* List of virtqueues encapsulated by virtio device. */ - //TODO : Need to implement a list service for ipc stack. - void *vq_list; - - /* Virtio device specific features */ - uint32_t features; - - /* Virtio dispatch table */ - virtio_dispatch *func; - - /* - * Pointer to hold some private data, useful - * in callbacks. - */ - void *data; + uint32_t index; /**< unique position on the virtio bus */ + struct virtio_device_id id; /**< the device type identification + * (used to match it with a driver + */ + uint64_t features; /**< the features supported by both ends. */ + unsigned int role; /**< if it is virtio backend or front end. */ + virtio_dev_reset_cb reset_cb; /**< user registered device callback */ + const struct virtio_dispatch *func; /**< Virtio dispatch table */ + void *priv; /**< TODO: remove pointer to virtio_device private data */ + unsigned int vrings_num; /**< number of vrings */ + struct virtio_vring_info *vrings_info; }; -/* +/* * Helper functions. */ const char *virtio_dev_name(uint16_t devid); @@ -101,21 +139,17 @@ void virtio_describe(struct virtio_device *dev, const char *msg, struct virtio_feature_desc *feature_desc); /* - * Functions for virtio device configuration as defined in Rusty Russell's paper. + * Functions for virtio device configuration as defined in Rusty Russell's + * paper. * Drivers are expected to implement these functions in their respective codes. - * */ -struct _virtio_dispatch_ { - int (*create_virtqueues) (struct virtio_device * dev, int flags, - int nvqs, const char *names[], - vq_callback * callbacks[], - struct virtqueue * vqs[]); - uint8_t(*get_status) (struct virtio_device * dev); - void (*set_status) (struct virtio_device * dev, uint8_t status); - uint32_t(*get_features) (struct virtio_device * dev); - void (*set_features) (struct virtio_device * dev, uint32_t feature); - uint32_t(*negotiate_features) (struct virtio_device * dev, +struct virtio_dispatch { + uint8_t (*get_status)(struct virtio_device *dev); + void (*set_status)(struct virtio_device *dev, uint8_t status); + uint32_t (*get_features)(struct virtio_device *dev); + void (*set_features)(struct virtio_device *dev, uint32_t feature); + uint32_t (*negotiate_features)(struct virtio_device *dev, uint32_t features); /* @@ -123,14 +157,18 @@ struct _virtio_dispatch_ { * configuration region. This region is encoded in the same endian as * the guest. */ - void (*read_config) (struct virtio_device * dev, uint32_t offset, - void *dst, int length); - void (*write_config) (struct virtio_device * dev, uint32_t offset, - void *src, int length); - void (*reset_device) (struct virtio_device * dev); - + void (*read_config)(struct virtio_device *dev, uint32_t offset, + void *dst, int length); + void (*write_config)(struct virtio_device *dev, uint32_t offset, + void *src, int length); + void (*reset_device)(struct virtio_device *dev); + void (*notify)(struct virtqueue *vq); }; +int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback *callbacks[]); + #if defined __cplusplus } #endif diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio_ring.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio_ring.h index 73f10c6679d411..14e7b6b571f6bd 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio_ring.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtio_ring.h @@ -22,15 +22,18 @@ extern "C" { /* The Host uses this in used->flags to advise the Guest: don't kick me * when you add a buffer. It's unreliable, so it's simply an - * optimization. Guest will still kick if it's out of buffers. */ + * optimization. Guest will still kick if it's out of buffers. + */ #define VRING_USED_F_NO_NOTIFY 1 /* The Guest uses this in avail->flags to advise the Host: don't * interrupt me when you consume a buffer. It's unreliable, so it's - * simply an optimization. */ + * simply an optimization. + */ #define VRING_AVAIL_F_NO_INTERRUPT 1 /* VirtIO ring descriptors: 16 bytes. - * These can chain together via "next". */ + * These can chain together via "next". + */ struct vring_desc { /* Address (guest-physical). */ uint64_t addr; @@ -113,17 +116,19 @@ static inline int vring_size(unsigned int num, unsigned long align) size = (size + align - 1) & ~(align - 1); size += sizeof(struct vring_used) + (num * sizeof(struct vring_used_elem)) + sizeof(uint16_t); - return (size); + + return size; } static inline void -vring_init(struct vring *vr, unsigned int num, uint8_t * p, unsigned long align) +vring_init(struct vring *vr, unsigned int num, uint8_t *p, unsigned long align) { vr->num = num; vr->desc = (struct vring_desc *)p; vr->avail = (struct vring_avail *)(p + num * sizeof(struct vring_desc)); vr->used = (struct vring_used *) - (((unsigned long)&vr->avail->ring[num] + align - 1) & ~(align - 1)); + (((unsigned long)&vr->avail->ring[num] + sizeof(uint16_t) + + align - 1) & ~(align - 1)); } /* @@ -136,9 +141,8 @@ vring_init(struct vring *vr, unsigned int num, uint8_t * p, unsigned long align) static inline int vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old) { - - return (uint16_t) (new_idx - event_idx - 1) < - (uint16_t) (new_idx - old); + return (uint16_t)(new_idx - event_idx - 1) < + (uint16_t)(new_idx - old); } #if defined __cplusplus diff --git a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtqueue.h b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtqueue.h index 952a59f94da180..ad24749062c2f9 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtqueue.h +++ b/ext/lib/ipc/open-amp/open-amp/lib/include/openamp/virtqueue.h @@ -20,7 +20,7 @@ extern "C" { typedef uint8_t boolean; #include -#include +#include #include /*Error Codes*/ @@ -35,7 +35,6 @@ typedef uint8_t boolean; #define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8) #define VQUEUE_SUCCESS 0 -#define VQUEUE_DEBUG false /* The maximum virtqueue size is 2^15. Use that value as the end of * descriptor chain terminator since it will never be a valid index @@ -53,29 +52,23 @@ typedef uint8_t boolean; /* Support to suppress interrupt until specific index is reached. */ #define VIRTIO_RING_F_EVENT_IDX (1 << 29) -/* - * Hint on how long the next interrupt should be postponed. This is - * only used when the EVENT_IDX feature is negotiated. - */ -typedef enum { - VQ_POSTPONE_SHORT, - VQ_POSTPONE_LONG, - VQ_POSTPONE_EMPTIED /* Until all available desc are used. */ -} vq_postpone_t; +struct virtqueue_buf { + void *buf; + int len; +}; struct virtqueue { struct virtio_device *vq_dev; - char vq_name[VIRTQUEUE_MAX_NAME_SZ]; + const char *vq_name; uint16_t vq_queue_index; uint16_t vq_nentries; uint32_t vq_flags; - void (*callback) (struct virtqueue * vq); - void (*notify) (struct virtqueue * vq); + void (*callback)(struct virtqueue *vq); + void (*notify)(struct virtqueue *vq); struct vring vq_ring; uint16_t vq_free_cnt; uint16_t vq_queued_cnt; - /** Shared memory I/O region */ - struct metal_io_region *shm_io; + void *shm_io; /* opaque pointer to data needed to allow v2p & p2v */ /* * Head of the free chain in the descriptor table. If @@ -96,7 +89,7 @@ struct virtqueue { */ uint16_t vq_available_idx; -#if (VQUEUE_DEBUG == true) +#ifdef VQUEUE_DEBUG boolean vq_inuse; #endif @@ -123,40 +116,42 @@ struct vring_alloc_info { typedef void vq_callback(struct virtqueue *); typedef void vq_notify(struct virtqueue *); -#if (VQUEUE_DEBUG == true) +#ifdef VQUEUE_DEBUG #include #include #define VQASSERT(_vq, _exp, _msg) \ - do{ \ - if (!(_exp)){ \ + do { \ + if (!(_exp)) { \ metal_log(METAL_LOG_EMERGENCY, \ - "%s: %s - "_msg, \ - __func__, \ - (_vq)->vq_name); \ + "%s: %s - _msg", __func__, (_vq)->vq_name); \ metal_assert(_exp); \ } \ - } while(0) + } while (0) #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \ - VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, \ - "invalid ring index") + VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index") #define VQ_RING_ASSERT_CHAIN_TERM(_vq) \ - VQASSERT((_vq), (_vq)->vq_desc_head_idx == \ - VQ_RING_DESC_CHAIN_END, "full ring terminated incorrectly: invalid head") - -#define VQ_PARAM_CHK(condition, status_var, status_err) \ - if ((status_var == 0) && (condition)) \ - { \ - status_var = status_err; \ - } - -#define VQUEUE_BUSY(vq) if ((vq)->vq_inuse == false) \ - (vq)->vq_inuse = true; \ - else \ - VQASSERT(vq, (vq)->vq_inuse == false, \ - "VirtQueue already in use") + VQASSERT((_vq), (_vq)->vq_desc_head_idx == \ + VQ_RING_DESC_CHAIN_END, \ + "full ring terminated incorrectly: invalid head") + +#define VQ_PARAM_CHK(condition, status_var, status_err) \ + do { \ + if (((status_var) == 0) && (condition)) { \ + status_var = status_err; \ + } \ + } while (0) + +#define VQUEUE_BUSY(vq) \ + do { \ + if (!(vq)->vq_inuse) \ + (vq)->vq_inuse = true; \ + else \ + VQASSERT(vq, !(vq)->vq_inuse,\ + "VirtQueue already in use") \ + } while (0) #define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false) @@ -174,22 +169,31 @@ typedef void vq_notify(struct virtqueue *); int virtqueue_create(struct virtio_device *device, unsigned short id, const char *name, struct vring_alloc_info *ring, - void (*callback) (struct virtqueue * vq), - void (*notify) (struct virtqueue * vq), - struct metal_io_region *shm_io, - struct virtqueue **v_queue); + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue *v_queue); -int virtqueue_add_buffer(struct virtqueue *vq, struct metal_sg *sg, - int readable, int writable, void *cookie); +/* + * virtqueue_set_shmem_io + * + * set virtqueue shared memory I/O region + * + * @vq - virt queue + * @io - pointer to the shared memory I/O region + */ +static inline void virtqueue_set_shmem_io(struct virtqueue *vq, + struct metal_io_region *io) +{ + vq->shm_io = io; +} -int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie, - struct metal_sg *sg, int writable, - boolean has_next); +int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, + int readable, int writable, void *cookie); -void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len, uint16_t *idx); +void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx); -void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t * avail_idx, - uint32_t * len); +void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, + uint32_t *len); int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint32_t len); @@ -200,6 +204,21 @@ int virtqueue_enable_cb(struct virtqueue *vq); void virtqueue_kick(struct virtqueue *vq); +static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra) +{ + struct virtqueue *vqs; + uint32_t vq_size = sizeof(struct virtqueue) + + num_desc_extra * sizeof(struct vq_desc_extra); + + vqs = (struct virtqueue *)metal_allocate_memory(vq_size); + + if (vqs) { + memset(vqs, 0x00, vq_size); + } + + return vqs; +} + void virtqueue_free(struct virtqueue *vq); void virtqueue_dump(struct virtqueue *vq); diff --git a/ext/lib/ipc/open-amp/open-amp/lib/proxy/rpmsg_retarget.c b/ext/lib/ipc/open-amp/open-amp/lib/proxy/rpmsg_retarget.c index 25b7ca349896bc..9035db2299f611 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/proxy/rpmsg_retarget.c +++ b/ext/lib/ipc/open-amp/open-amp/lib/proxy/rpmsg_retarget.c @@ -1,6 +1,8 @@ +#include +#include +#include #include #include -#include #include #include #include @@ -10,82 +12,134 @@ * This files contains rpmsg based redefinitions for C RTL system calls * such as _open, _read, _write, _close. *************************************************************************/ -static struct _rpc_data *rpc_data = 0; +static struct rpmsg_rpc_data *rpmsg_default_rpc; -int send_rpc(void *data, int len); - -void rpc_cb(struct rpmsg_channel *rtl_rp_chnl, void *data, int len, void *priv, - unsigned long src) +static int rpmsg_rpc_ept_cb(struct rpmsg_endpoint *ept, void *data, size_t len, + uint32_t src, void *priv) { + struct rpmsg_rpc_syscall *syscall; + (void)priv; (void)src; - memcpy(rpc_data->rpc_response, data, len); - - atomic_flag_clear(&rpc_data->sync); - if (rpc_data->rpc_response->id == TERM_SYSCALL_ID) { - /* Application terminate signal is received from the proxy app, - * so let the application know of terminate message. - */ - rpc_data->shutdown_cb(rtl_rp_chnl); + if (data != NULL && ept != NULL) { + syscall = data; + if (syscall->id == TERM_SYSCALL_ID) { + rpmsg_destroy_ept(ept); + } else { + struct rpmsg_rpc_data *rpc; + + rpc = metal_container_of(ept, + struct rpmsg_rpc_data, + ept); + metal_spinlock_acquire(&rpc->buflock); + if (rpc->respbuf != NULL && rpc->respbuf_len != 0) { + if (len > rpc->respbuf_len) + len = rpc->respbuf_len; + memcpy(rpc->respbuf, data, len); + } + atomic_flag_clear(&rpc->nacked); + metal_spinlock_release(&rpc->buflock); + } } -} -int send_rpc(void *data, int len) -{ - int retval; - - retval = rpmsg_sendto(rpc_data->rpmsg_chnl, data, len, PROXY_ENDPOINT); - return retval; + return RPMSG_SUCCESS; } -int rpmsg_retarget_init(struct rpmsg_channel *rp_chnl, rpc_shutdown_cb cb) +static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) { - /* Allocate memory for rpc control block */ - rpc_data = (struct _rpc_data *)metal_allocate_memory(sizeof(struct _rpc_data)); - - /* Create a mutex for synchronization */ - metal_mutex_init(&rpc_data->rpc_lock); - - /* Create a mutex for synchronization */ - atomic_store(&rpc_data->sync, 1); + struct rpmsg_rpc_data *rpc; + + rpc = metal_container_of(ept, struct rpmsg_rpc_data, ept); + rpc->ept_destroyed = 1; + rpmsg_destroy_ept(ept); + atomic_flag_clear(&rpc->nacked); + if (rpc->shutdown_cb) + rpc->shutdown_cb(rpc); +} - /* Create a endpoint to handle rpc response from master */ - rpc_data->rpmsg_chnl = rp_chnl; - rpc_data->rp_ept = rpmsg_create_ept(rpc_data->rpmsg_chnl, rpc_cb, - RPMSG_NULL, PROXY_ENDPOINT); - rpc_data->rpc = metal_allocate_memory(RPC_BUFF_SIZE); - rpc_data->rpc_response = metal_allocate_memory(RPC_BUFF_SIZE); - rpc_data->shutdown_cb = cb; +int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc, + struct rpmsg_device *rdev, + const char *ept_name, uint32_t ept_addr, + uint32_t ept_raddr, + void *poll_arg, rpmsg_rpc_poll poll, + rpmsg_rpc_shutdown_cb shutdown_cb) +{ + int ret; + + if (rpc == NULL || rdev == NULL) + return -EINVAL; + metal_spinlock_init(&rpc->buflock); + metal_mutex_init(&rpc->lock); + rpc->shutdown_cb = shutdown_cb; + rpc->poll_arg = poll_arg; + rpc->poll = poll; + rpc->ept_destroyed = 0; + rpc->respbuf = NULL; + rpc->respbuf_len = 0; + atomic_init(&rpc->nacked, 1); + ret = rpmsg_create_ept(&rpc->ept, rdev, + ept_name, ept_addr, ept_raddr, + rpmsg_rpc_ept_cb, rpmsg_service_unbind); + if (ret != 0) { + metal_mutex_release(&rpc->lock); + return -EINVAL; + } + while (!is_rpmsg_ept_ready(&rpc->ept)) { + if (rpc->poll) + rpc->poll(rpc->poll_arg); + } return 0; } -int rpmsg_retarget_deinit(struct rpmsg_channel *rp_chnl) +void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc) { - (void)rp_chnl; - - metal_free_memory(rpc_data->rpc); - metal_free_memory(rpc_data->rpc_response); - metal_mutex_deinit(&rpc_data->rpc_lock); - rpmsg_destroy_ept(rpc_data->rp_ept); - metal_free_memory(rpc_data); - rpc_data = NULL; - - return 0; + if (rpc == NULL) + return; + if (rpc->ept_destroyed == 0) + rpmsg_destroy_ept(&rpc->ept); + metal_mutex_acquire(&rpc->lock); + metal_spinlock_acquire(&rpc->buflock); + rpc->respbuf = NULL; + rpc->respbuf_len = 0; + metal_spinlock_release(&rpc->buflock); + metal_mutex_release(&rpc->lock); + metal_mutex_deinit(&rpc->lock); + + return; } -int rpmsg_retarget_send(void *data, int len) +int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc, + void *req, size_t len, + void *resp, size_t resp_len) { - return send_rpc(data, len); + int ret; + + if (rpc == NULL) + return -EINVAL; + metal_spinlock_acquire(&rpc->buflock); + rpc->respbuf = resp; + rpc->respbuf_len = resp_len; + metal_spinlock_release(&rpc->buflock); + (void)atomic_flag_test_and_set(&rpc->nacked); + ret = rpmsg_send(&rpc->ept, req, len); + if (ret < 0) + return -EINVAL; + if (!resp) + return ret; + while((atomic_flag_test_and_set(&rpc->nacked))) { + if (rpc->poll) + rpc->poll(rpc->poll_arg); + } + return ret; } -static inline void rpmsg_retarget_wait(struct _rpc_data *rpc) +void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc) { - struct hil_proc *proc = rpc->rpmsg_chnl->rdev->proc; - while (atomic_flag_test_and_set(&rpc->sync)) { - hil_poll(proc, 0); - } + if (rpc == NULL) + return; + rpmsg_default_rpc = rpc; } /************************************************************************* @@ -99,40 +153,45 @@ static inline void rpmsg_retarget_wait(struct _rpc_data *rpc) * Open a file. Minimal implementation * *************************************************************************/ +#define MAX_BUF_LEN 496UL + int _open(const char *filename, int flags, int mode) { + struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; + struct rpmsg_rpc_syscall *syscall; + struct rpmsg_rpc_syscall resp; int filename_len = strlen(filename) + 1; - int payload_size = sizeof(struct _sys_rpc) + filename_len; - int retval = -1; + int payload_size = sizeof(*syscall) + filename_len; + unsigned char tmpbuf[MAX_BUF_LEN]; + int ret; - if ((!filename) || (filename_len > FILE_NAME_LEN)) { - return -1; + if (filename == NULL || payload_size > (int)MAX_BUF_LEN) { + return -EINVAL; } - if (!rpc_data) - return retval; + if (rpc == NULL) + return -EINVAL; /* Construct rpc payload */ - rpc_data->rpc->id = OPEN_SYSCALL_ID; - rpc_data->rpc->sys_call_args.int_field1 = flags; - rpc_data->rpc->sys_call_args.int_field2 = mode; - rpc_data->rpc->sys_call_args.data_len = filename_len; - memcpy(&rpc_data->rpc->sys_call_args.data, filename, filename_len); - - /* Transmit rpc request */ - metal_mutex_acquire(&rpc_data->rpc_lock); - send_rpc((void *)rpc_data->rpc, payload_size); - metal_mutex_release(&rpc_data->rpc_lock); - - /* Wait for response from proxy on master */ - rpmsg_retarget_wait(rpc_data); - - /* Obtain return args and return to caller */ - if (rpc_data->rpc_response->id == OPEN_SYSCALL_ID) { - retval = rpc_data->rpc_response->sys_call_args.int_field1; + syscall = (struct rpmsg_rpc_syscall *)tmpbuf; + syscall->id = OPEN_SYSCALL_ID; + syscall->args.int_field1 = flags; + syscall->args.int_field2 = mode; + syscall->args.data_len = filename_len; + memcpy(tmpbuf + sizeof(*syscall), filename, filename_len); + + resp.id = 0; + ret = rpmsg_rpc_send(rpc, tmpbuf, payload_size, + (void *)&resp, sizeof(resp)); + if (ret >= 0) { + /* Obtain return args and return to caller */ + if (resp.id == OPEN_SYSCALL_ID) + ret = resp.args.int_field1; + else + ret = -EINVAL; } - return retval; + return ret; } /************************************************************************* @@ -148,40 +207,46 @@ int _open(const char *filename, int flags, int mode) *************************************************************************/ int _read(int fd, char *buffer, int buflen) { - int payload_size = sizeof(struct _sys_rpc); - int retval = -1; + struct rpmsg_rpc_syscall syscall; + struct rpmsg_rpc_syscall *resp; + struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; + int payload_size = sizeof(syscall); + unsigned char tmpbuf[MAX_BUF_LEN]; + int ret; - if (!buffer || !buflen) - return retval; - if (!rpc_data) - return retval; + if (rpc == NULL || buffer == NULL || buflen == 0) + return -EINVAL; /* Construct rpc payload */ - rpc_data->rpc->id = READ_SYSCALL_ID; - rpc_data->rpc->sys_call_args.int_field1 = fd; - rpc_data->rpc->sys_call_args.int_field2 = buflen; - rpc_data->rpc->sys_call_args.data_len = 0; /*not used */ - - /* Transmit rpc request */ - metal_mutex_acquire(&rpc_data->rpc_lock); - send_rpc((void *)rpc_data->rpc, payload_size); - metal_mutex_release(&rpc_data->rpc_lock); + syscall.id = READ_SYSCALL_ID; + syscall.args.int_field1 = fd; + syscall.args.int_field2 = buflen; + syscall.args.data_len = 0; /*not used */ - /* Wait for response from proxy on master */ - rpmsg_retarget_wait(rpc_data); + resp = (struct rpmsg_rpc_syscall *)tmpbuf; + resp->id = 0; + ret = rpmsg_rpc_send(rpc, (void *)&syscall, payload_size, + tmpbuf, sizeof(tmpbuf)); /* Obtain return args and return to caller */ - if (rpc_data->rpc_response->id == READ_SYSCALL_ID) { - if (rpc_data->rpc_response->sys_call_args.int_field1 > 0) { - memcpy(buffer, - rpc_data->rpc_response->sys_call_args.data, - rpc_data->rpc_response->sys_call_args.data_len); + if (ret >= 0) { + if (resp->id == READ_SYSCALL_ID) { + if (resp->args.int_field1 > 0) { + int tmplen = resp->args.data_len; + unsigned char *tmpptr = tmpbuf; + + tmpptr += sizeof(*resp); + if (tmplen > buflen) + tmplen = buflen; + memcpy(buffer, tmpptr, tmplen); + } + ret = resp->args.int_field1; + } else { + ret = -EINVAL; } - - retval = rpc_data->rpc_response->sys_call_args.int_field1; } - return retval; + return ret; } /************************************************************************* @@ -197,38 +262,43 @@ int _read(int fd, char *buffer, int buflen) *************************************************************************/ int _write(int fd, const char *ptr, int len) { - int retval = -1; - int payload_size = sizeof(struct _sys_rpc) + len; + int ret; + struct rpmsg_rpc_syscall *syscall; + struct rpmsg_rpc_syscall resp; + int payload_size = sizeof(*syscall) + len; + struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; + unsigned char tmpbuf[MAX_BUF_LEN]; + unsigned char *tmpptr; int null_term = 0; - if (fd == 1) { + if (rpc == NULL) + return -EINVAL; + if (fd == 1) null_term = 1; - } - if (!rpc_data) - return retval; - - rpc_data->rpc->id = WRITE_SYSCALL_ID; - rpc_data->rpc->sys_call_args.int_field1 = fd; - rpc_data->rpc->sys_call_args.int_field2 = len; - rpc_data->rpc->sys_call_args.data_len = len + null_term; - memcpy(rpc_data->rpc->sys_call_args.data, ptr, len); - if (null_term) { - *(char *)(rpc_data->rpc->sys_call_args.data + len + null_term) = - 0; - } - - metal_mutex_acquire(&rpc_data->rpc_lock); - send_rpc((void *)rpc_data->rpc, payload_size); - metal_mutex_release(&rpc_data->rpc_lock); - /* Wait for response from proxy on master */ - rpmsg_retarget_wait(rpc_data); - - if (rpc_data->rpc_response->id == WRITE_SYSCALL_ID) { - retval = rpc_data->rpc_response->sys_call_args.int_field1; + syscall = (struct rpmsg_rpc_syscall *)tmpbuf; + syscall->id = WRITE_SYSCALL_ID; + syscall->args.int_field1 = fd; + syscall->args.int_field2 = len; + syscall->args.data_len = len + null_term; + tmpptr = tmpbuf + sizeof(*syscall); + memcpy(tmpptr, ptr, len); + if (null_term == 1) { + *(char *)(tmpptr + len + null_term) = 0; + payload_size += 1; + } + resp.id = 0; + ret = rpmsg_rpc_send(rpc, tmpbuf, payload_size, + (void *)&resp, sizeof(resp)); + + if (ret >= 0) { + if (resp.id == WRITE_SYSCALL_ID) + ret = resp.args.int_field1; + else + ret = -EINVAL; } - return retval; + return ret; } @@ -245,26 +315,29 @@ int _write(int fd, const char *ptr, int len) *************************************************************************/ int _close(int fd) { - int payload_size = sizeof(struct _sys_rpc); - int retval = -1; - - if (!rpc_data) - return retval; - rpc_data->rpc->id = CLOSE_SYSCALL_ID; - rpc_data->rpc->sys_call_args.int_field1 = fd; - rpc_data->rpc->sys_call_args.int_field2 = 0; /*not used */ - rpc_data->rpc->sys_call_args.data_len = 0; /*not used */ - - metal_mutex_acquire(&rpc_data->rpc_lock); - send_rpc((void *)rpc_data->rpc, payload_size); - metal_mutex_release(&rpc_data->rpc_lock); - - /* Wait for response from proxy on master */ - rpmsg_retarget_wait(rpc_data); - - if (rpc_data->rpc_response->id == CLOSE_SYSCALL_ID) { - retval = rpc_data->rpc_response->sys_call_args.int_field1; + int ret; + struct rpmsg_rpc_syscall syscall; + struct rpmsg_rpc_syscall resp; + int payload_size = sizeof(syscall); + struct rpmsg_rpc_data *rpc = rpmsg_default_rpc; + + if (rpc == NULL) + return -EINVAL; + syscall.id = CLOSE_SYSCALL_ID; + syscall.args.int_field1 = fd; + syscall.args.int_field2 = 0; /*not used */ + syscall.args.data_len = 0; /*not used */ + + resp.id = 0; + ret = rpmsg_rpc_send(rpc, (void*)&syscall, payload_size, + (void*)&resp, sizeof(resp)); + + if (ret >= 0) { + if (resp.id == CLOSE_SYSCALL_ID) + ret = resp.args.int_field1; + else + ret = -EINVAL; } - return retval; + return ret; } diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/CMakeLists.txt b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/CMakeLists.txt index acd240ae7672d9..158df1d16e0210 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/CMakeLists.txt +++ b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/CMakeLists.txt @@ -1,5 +1,4 @@ collect (PROJECT_LIB_SOURCES elf_loader.c) collect (PROJECT_LIB_SOURCES remoteproc.c) -collect (PROJECT_LIB_SOURCES remoteproc_loader.c) +collect (PROJECT_LIB_SOURCES remoteproc_virtio.c) collect (PROJECT_LIB_SOURCES rsc_table_parser.c) -add_subdirectory (drivers) diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/CMakeLists.txt b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/CMakeLists.txt deleted file mode 100644 index 15028ee3a9746b..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -if ("${MACHINE}" STREQUAL "zynqmp_r5") - collect (PROJECT_LIB_SOURCES zynqmp_remoteproc_a53.c) -endif ("${MACHINE}" STREQUAL "zynqmp_r5") - -if ("${MACHINE}" STREQUAL "zynq7") - collect (PROJECT_LIB_SOURCES zynq_remoteproc_a9.c) - collect (PROJECT_LIB_SOURCES zynq_a9_trampoline.S) -endif ("${MACHINE}" STREQUAL "zynq7") - -if ("${MACHINE}" STREQUAL "zynqmp") - collect (PROJECT_LIB_SOURCES zynqmp_remoteproc_r5.c) -endif ("${MACHINE}" STREQUAL "zynqmp") - -if ("${PROJECT_SYSTEM}" STREQUAL "linux") - collect (PROJECT_LIB_SOURCES linux_remoteproc.c) -endif ("${PROJECT_SYSTEM}" STREQUAL "linux") diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/linux_remoteproc.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/linux_remoteproc.c deleted file mode 100644 index 68bf05c830f9ec..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/linux_remoteproc.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * Copyright (c) 2016 Xilinx, Inc. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * zynqmp_remoteproc_r5.c - * - * DESCRIPTION - * - * This file is the Implementation of IPC hardware layer interface - * for Xilinx Zynq UltraScale+ MPSoC system. - * - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_VRING_MEM_SIZE 0x20000 -#define _rproc_wait() metal_cpu_yield() - -#define UNIX_PREFIX "unix:" -#define UNIXS_PREFIX "unixs:" - -struct vring_ipi_info { - /* Socket file path */ - char *path; - int fd; - struct metal_io_region *vring_io; - atomic_int sync; -}; - -/*--------------------------- Declare Functions ------------------------ */ -static int _ipi_handler(int vect_id, void *data); -static int _enable_interrupt(struct proc_intr *intr); -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info); -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr); -static void _shutdown_cpu(struct hil_proc *proc); -static int _poll(struct hil_proc *proc, int nonblock); -static int _initialize(struct hil_proc *proc); -static void _release(struct hil_proc *proc); -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev); -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io); - - -/*--------------------------- Globals ---------------------------------- */ -struct hil_platform_ops linux_proc_ops = { - .enable_interrupt = _enable_interrupt, - .notify = _notify, - .boot_cpu = _boot_cpu, - .shutdown_cpu = _shutdown_cpu, - .poll = _poll, - .alloc_shm = _alloc_shm, - .release_shm = _release_shm, - .initialize = _initialize, - .release = _release, -}; - -static int sk_unix_client(const char *descr) -{ - struct sockaddr_un addr; - int fd; - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - - memset(&addr, 0, sizeof addr); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, descr + strlen(UNIX_PREFIX), - sizeof addr.sun_path); - if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) >= 0) { - printf("connected to %s\n", descr + strlen(UNIX_PREFIX)); - return fd; - } - - close(fd); - return -1; -} - -static int sk_unix_server(const char *descr) -{ - struct sockaddr_un addr; - int fd, nfd; - - fd = socket(AF_UNIX, SOCK_STREAM, 0); - - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, descr + strlen(UNIXS_PREFIX), - sizeof addr.sun_path); - unlink(addr.sun_path); - if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - goto fail; - } - - listen(fd, 5); - printf("Waiting for connection on %s\n", addr.sun_path); - nfd = accept(fd, NULL, NULL); - close(fd); - return nfd; -fail: - close(fd); - return -1; -} - -static int event_open(const char *descr) -{ - int fd = -1; - int i; - - if (descr == NULL) { - return fd; - } - - if (memcmp(UNIX_PREFIX, descr, strlen(UNIX_PREFIX)) == 0) { - /* UNIX. Retry to connect a few times to give the peer a - * chance to setup. */ - for (i = 0; i < 100 && fd == -1; i++) { - fd = sk_unix_client(descr); - if (fd == -1) - usleep(i * 10 * 1000); - } - } - if (memcmp(UNIXS_PREFIX, descr, strlen(UNIXS_PREFIX)) == 0) { - /* UNIX. */ - fd = sk_unix_server(descr); - } - printf("Open IPI: %s\n", descr); - return fd; -} - -static int _ipi_handler(int vect_id, void *data) -{ - char dummy_buf[32]; - struct proc_intr *intr = data; - struct vring_ipi_info *ipi = intr->data; - - (void) vect_id; - - read(vect_id, dummy_buf, sizeof(dummy_buf)); - atomic_flag_clear(&ipi->sync); - return 0; -} - -static int _enable_interrupt(struct proc_intr *intr) -{ - struct vring_ipi_info *ipi = intr->data; - - ipi->fd = event_open(ipi->path); - if (ipi->fd < 0) { - fprintf(stderr, "ERROR: Failed to open sock %s for IPI.\n", - ipi->path); - return -1; - } - - intr->vect_id = ipi->fd; - - /* Register ISR */ - metal_irq_register(ipi->fd, _ipi_handler, - NULL, intr); - return 0; -} - -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info) -{ - - (void)proc; - struct vring_ipi_info *ipi = (struct vring_ipi_info *)(intr_info->data); - if (ipi == NULL) - return; - - char dummy = 1; - send(ipi->fd, &dummy, 1, MSG_NOSIGNAL); -} - -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr) -{ - (void)proc; - (void)load_addr; - return -1; -} - -static void _shutdown_cpu(struct hil_proc *proc) -{ - (void)proc; - return; -} - -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev) -{ - (void)proc; - (void)pa; - (void)size; - - *dev = NULL; - return NULL; - -} - -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io) -{ - (void)proc; - (void)io; - hil_close_generic_mem_dev(dev); -} - -static int _poll(struct hil_proc *proc, int nonblock) -{ - (void) nonblock; - struct proc_vring *vring; - struct vring_ipi_info *ipi; - unsigned int flags; - - int num_vrings = proc->vdev.num_vrings; - int ret = 0; - int notified; - int i; - - metal_assert(proc); - - notified = 0; - while (1) { - for (i = 0; i < num_vrings; i++) { - vring = &proc->vdev.vring_info[i]; - ipi = (struct vring_ipi_info *)(vring->intr_info.data); - flags = metal_irq_save_disable(); - if (!(atomic_flag_test_and_set(&ipi->sync))) { - metal_irq_restore_enable(flags); - virtqueue_notification(vring->vq); - notified = 1; - } else { - metal_irq_restore_enable(flags); - } - } - if (notified) - return 0; - if (nonblock) - return -EAGAIN; - _rproc_wait(); - } - return ret; -} - -/** - * @brief _adjust_vring_io - Adjust the vring I/O region to map to the - * specified start device address. - * @param[in] io - vring I/O region - * @param[in] start_phy - start device address of the vring, this is - * not the actual physical address. - * @return adjusted I/O region - */ -static struct metal_io_region *_create_vring_io(struct metal_io_region *in_io, - int start_phy) -{ - struct metal_io_region *io = 0; - metal_phys_addr_t *phys; - io = metal_allocate_memory(sizeof(struct metal_io_region)); - if (!io) { - fprintf(stderr, "ERROR: Failed to allocation I/O for vring.\n"); - return NULL; - } - phys = metal_allocate_memory(sizeof(metal_phys_addr_t)); - if (!phys) { - fprintf(stderr, "ERROR: Failed to allocation phys for vring.\n"); - metal_free_memory(io); - return NULL; - } - *phys = (metal_phys_addr_t)start_phy; - metal_io_init(io, in_io->virt, phys, in_io->size, - sizeof(metal_phys_addr_t)*8 - 1, 0, NULL); - return io; -} - -static int _initialize(struct hil_proc *proc) -{ - struct proc_vring *vring; - struct vring_ipi_info *ipi; - struct metal_io_region *io; - int i; - if (proc) { - for (i = 0; i < 2; i++) { - vring = &proc->vdev.vring_info[i]; - ipi = (struct vring_ipi_info *)vring->intr_info.data; - if (ipi && !ipi->vring_io && vring->io) { - io = _create_vring_io(vring->io, 0); - if (!io) - return -1; - ipi->vring_io = vring->io; - vring->io = io; - atomic_store(&ipi->sync, 1); - } - } - } - return 0; -} - -static void _release(struct hil_proc *proc) -{ - struct proc_vring *vring; - struct vring_ipi_info *ipi; - int i; - if (proc) { - for (i = 0; i < 2; i++) { - vring = &proc->vdev.vring_info[i]; - ipi = (struct vring_ipi_info *)vring->intr_info.data; - if (ipi) { - if (ipi->fd >= 0) { - metal_irq_unregister(ipi->fd, 0, NULL, - vring); - close(ipi->fd); - } - if (ipi->vring_io) { - metal_free_memory(vring->io->physmap); - metal_free_memory(vring->io); - vring->io = NULL; - if (ipi->vring_io->ops.close) - ipi->vring_io->ops.close(ipi->vring_io); - ipi->vring_io = NULL; - } - } - } - } -} - diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynq_a9_trampoline.S b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynq_a9_trampoline.S deleted file mode 100644 index 404fba349c0c7e..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynq_a9_trampoline.S +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -.global zynq_trampoline -zynq_trampoline: - ldr r0, [pc] - bx r0 -.global zynq_trampoline_jump -zynq_trampoline_jump: - .word -.global zynq_trampoline_end -zynq_trampoline_end: diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynq_remoteproc_a9.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynq_remoteproc_a9.c deleted file mode 100644 index f775df113216af..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynq_remoteproc_a9.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * platform.c - * - * DESCRIPTION - * - * This file is the Implementation of IPC hardware layer interface - * for Xilinx Zynq ZC702EVK platform. - * - **************************************************************************/ - -#include -#include -#include -#include -#include -#include - -/* ------------------------- Macros --------------------------*/ -#define SCUGIC_PERIPH_BASE 0xF8F00000 -#define SCUGIC_DIST_BASE (SCUGIC_PERIPH_BASE + 0x00001000) -#define ESAL_DP_SLCR_BASE 0xF8000000 -#define GIC_DIST_SOFTINT 0xF00 -#define GIC_SFI_TRIG_CPU_MASK 0x00FF0000 -#define GIC_SFI_TRIG_SATT_MASK 0x00008000 -#define GIC_SFI_TRIG_INTID_MASK 0x0000000F -#define GIC_CPU_ID_BASE (1 << 4) -#define A9_CPU_SLCR_RESET_CTRL 0x244 -#define A9_CPU_SLCR_CLK_STOP (1 << 4) -#define A9_CPU_SLCR_RST (1 << 0) - -#define unlock_slcr() HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x08, 0xDF0DDF0D) -#define lock_slcr() HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + 0x04, 0x767B767B) - -/* L2Cpl310 L2 cache controller base address. */ -#define HIL_PL130_BASE 0xF8F02000 - -/********************/ -/* Register offsets */ -/********************/ - -#define HIL_PL130_INVALLINE 0x770 -#define HIL_PL130_CLEANINVLINE 0x7F0 - - -#define HIL_PA_SBZ_MASK ~(HIL_CACHE_LINE_SIZE - 1UL) -#define HIL_CACHE_LINE_SIZE 32 -#define HIL_CACHE_INV_ALL_WAYS 0xFF -#define HIL_CACHE_UNLOCK_ALL_WAYS 0xFFFF0000 -#define HIL_CACHE_CLEAR_INT 0x1FF - -/* Memory attributes */ -#define NORM_NONCACHE 0x11DE2 /* Normal Non-cacheable */ -#define STRONG_ORDERED 0xC02 /* Strongly ordered */ -#define DEVICE_MEMORY 0xC06 /* Device memory */ -#define RESERVED 0x0 /* reserved memory */ - -#define HIL_DEV_NAME_PREFIX "hil-dev." - -#define _rproc_wait() asm volatile("wfi") - -/*--------------------------- Declare Functions ------------------------ */ -static int _enable_interrupt(struct proc_intr *intr); -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info); -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr); -static void _shutdown_cpu(struct hil_proc *proc); -static int _poll(struct hil_proc *proc, int nonblock); -static int _initialize(struct hil_proc *proc); -static void _release(struct hil_proc *proc); -static int _ipi_handler(int vect_id, void *data); -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev); -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io); - -/*--------------------------- Globals ---------------------------------- */ -struct hil_platform_ops zynq_a9_proc_ops = { - .enable_interrupt = _enable_interrupt, - .notify = _notify, - .boot_cpu = _boot_cpu, - .shutdown_cpu = _shutdown_cpu, - .poll = _poll, - .alloc_shm = _alloc_shm, - .release_shm = _release_shm, - .initialize = _initialize, - .release = _release, -}; - -struct hil_mem_device { - struct metal_device device; - char name[64]; - metal_phys_addr_t pa; -}; - -static metal_phys_addr_t git_dist_base_addr = SCUGIC_DIST_BASE; -static struct metal_io_region gic_dist_io = { - (void *)SCUGIC_DIST_BASE, - &git_dist_base_addr, - 0x1000, - (sizeof(metal_phys_addr_t) << 3), - (metal_phys_addr_t)(-1), - 0, - {NULL}, -}; - -//volatile unsigned int ipi_counter = 0; -//volatile unsigned int enableirq_counter = 0; - -int _ipi_handler(int vect_id, void *data) -{ - struct proc_intr *intr_info = data; - - (void) vect_id; - - atomic_flag_clear((atomic_uint *)&(intr_info->data)); - - //ipi_counter++; - return 0; -} - -static int _enable_interrupt(struct proc_intr *intr) -{ - //enableirq_counter++; - /* Register ISR */ - metal_irq_register(intr->vect_id, _ipi_handler, - intr->dev, intr); - - /* Enable the interrupts */ - metal_irq_enable(intr->vect_id); - - /* FIXME: This is a workaround for Zynq. As Linux is possible - * to have already generate the soft IRQ - */ - atomic_flag_clear((atomic_uint *)&(intr->data)); - return 0; -} - -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info) -{ - unsigned long mask = 0; - - mask = ((1 << (GIC_CPU_ID_BASE + proc->cpu_id)) | (intr_info->vect_id)) - & (GIC_SFI_TRIG_CPU_MASK | GIC_SFI_TRIG_INTID_MASK); - - /* Trigger IPI */ - metal_io_write32(&gic_dist_io, GIC_DIST_SOFTINT, mask); -} - -static int _poll(struct hil_proc *proc, int nonblock) -{ - struct proc_vring *vring; - unsigned int flags; - struct proc_intr *intr_info; - int i = 0; - int kicked = 0; - - while(1) { - vring = &proc->vdev.vring_info[i]; - intr_info = &(vring->intr_info); - flags = metal_irq_save_disable(); - if (!(atomic_flag_test_and_set( - (atomic_uint *)&(intr_info->data)))) { - metal_irq_restore_enable(flags); - virtqueue_notification(vring->vq); - kicked = 1; - if (i) - return 0; - i++; - } else if (!i) { - metal_irq_restore_enable(flags); - i++; - } else { - if (kicked) { - metal_irq_restore_enable(flags); - return 0; - } else if (nonblock) { - metal_irq_restore_enable(flags); - return -EAGAIN; - } else { - _rproc_wait(); - metal_irq_restore_enable(flags); - i--; - continue; - } - } - } -} - -extern char zynq_trampoline; -extern char zynq_trampoline_jump; -extern char zynq_trampoline_end; - -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr) -{ - /* FIXME: Will need to add the boot_cpu implementation back */ -#if 0 - unsigned int reg; - unsigned int tramp_size; - unsigned int tramp_addr = 0; - - if (load_addr) { - tramp_size = zynq_trampoline_end - zynq_trampoline; - if ((load_addr < tramp_size) || (load_addr & 0x3)) { - return -1; - } - - tramp_size = &zynq_trampoline_jump - &zynq_trampoline; - - /* - * Trampoline code is copied to address 0 from where remote core is expected to - * fetch first instruction after reset.If master is using the address 0 then - * this mem copy will screwed the system. It is user responsibility to not - * copy trampoline code in such cases. - * - */ - memcpy((char *)tramp_addr, &zynq_trampoline, tramp_size); - /* Write image address at the word reserved at the trampoline end */ - HIL_MEM_WRITE32((char *)(tramp_addr + tramp_size), load_addr); - } - - unlock_slcr(); - - reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL); - reg &= ~(A9_CPU_SLCR_CLK_STOP << cpu_id); - HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg); - /* De-assert reset signal and start clock to start the core */ - reg &= ~(A9_CPU_SLCR_RST << cpu_id); - HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg); - - lock_slcr(); - -#else - (void)proc; - (void)load_addr; -#endif - return 0; -} - -static void _shutdown_cpu(struct hil_proc *proc) -{ - /* FIXME: Will need to add the shutdown CPU implementation back */ -#if 0 - unsigned int reg; - - unlock_slcr(); - - reg = HIL_MEM_READ32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL); - /* Assert reset signal and stop clock to halt the core */ - reg |= (A9_CPU_SLCR_CLK_STOP | A9_CPU_SLCR_RST) << cpu_id; - HIL_MEM_WRITE32(ESAL_DP_SLCR_BASE + A9_CPU_SLCR_RESET_CTRL, reg); - - lock_slcr(); -#else - (void)proc; -#endif -} - -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev) -{ - (void)proc; - - *dev = hil_create_generic_mem_dev(pa, size, - NORM_NONCACHE | STRONG_ORDERED); - if ((*dev)) - return &((*dev)->regions[0]); - - return NULL; - -} - -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io) -{ - (void)proc; - (void)io; - hil_close_generic_mem_dev(dev); -} - -static int _initialize(struct hil_proc *proc) -{ - int i; - struct proc_intr *intr_info; - - for (i = 0; i < 2; i++) { - intr_info = &(proc->vdev.vring_info[i].intr_info); - atomic_store((atomic_uint *)&(intr_info->data), 1); - } - - return 0; -} - -static void _release(struct hil_proc *proc) -{ - (void)proc; - return; -} - diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynqmp_remoteproc_a53.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynqmp_remoteproc_a53.c deleted file mode 100644 index cb2bd8230f07ff..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynqmp_remoteproc_a53.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * Copyright (c) 2015 Xilinx, Inc. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * platform.c - * - * DESCRIPTION - * - * This file is the Implementation of IPC hardware layer interface - * for Xilinx Zynq ZC702EVK platform. - * - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* IPI REGs OFFSET */ -#define IPI_TRIG_OFFSET 0x00000000 /* IPI trigger register offset */ -#define IPI_OBS_OFFSET 0x00000004 /* IPI observation register offset */ -#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */ -#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */ -#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */ -#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */ - -/* memory attributes */ -#define DEVICE_SHARED 0x00000001U /*device, shareable*/ -#define DEVICE_NONSHARED 0x00000010U /*device, non shareable*/ -#define NORM_NSHARED_NCACHE 0x00000008U /* Non cacheable non shareable */ -#define NORM_SHARED_NCACHE 0x0000000CU /* Non cacheable shareable */ -#define PRIV_RW_USER_RW (0x00000003U<<8U) /*Full Access*/ - -#define _rproc_wait() asm volatile("wfi") - -/* -- FIX ME: ipi info is to be defined -- */ -struct ipi_info { - const char *name; - const char *bus_name; - struct metal_device *dev; - struct metal_io_region *io; - metal_phys_addr_t paddr; - uint32_t ipi_chn_mask; - int registered; - atomic_int sync; -}; - -/*--------------------------- Declare Functions ------------------------ */ -static int _enable_interrupt(struct proc_intr *intr); -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info); -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr); -static void _shutdown_cpu(struct hil_proc *proc); -static int _poll(struct hil_proc *proc, int nonblock); -static int _initialize(struct hil_proc *proc); -static void _release(struct hil_proc *proc); - -static int _ipi_handler(int vect_id, void *data); -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev); -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io); - -/*--------------------------- Globals ---------------------------------- */ -struct hil_platform_ops zynqmp_r5_a53_proc_ops = { - .enable_interrupt = _enable_interrupt, - .notify = _notify, - .boot_cpu = _boot_cpu, - .shutdown_cpu = _shutdown_cpu, - .poll = _poll, - .alloc_shm = _alloc_shm, - .release_shm = _release_shm, - .initialize = _initialize, - .release = _release, -}; - -int _ipi_handler(int vect_id, void *data) -{ - struct proc_intr *intr = data; - struct ipi_info *ipi = intr->data; - struct metal_io_region *io = ipi->io; - unsigned int ipi_intr_status = - (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET); - - (void) vect_id; - - if (ipi_intr_status & ipi->ipi_chn_mask) { - atomic_flag_clear(&ipi->sync); - metal_io_write32(io, IPI_ISR_OFFSET, - ipi->ipi_chn_mask); - return 0; - } - return -1; -} - -static int _enable_interrupt(struct proc_intr *intr) -{ - struct ipi_info *ipi = - (struct ipi_info *)(intr->data); - struct metal_io_region *io = ipi->io; - - if (ipi->registered) { - return 0; - } - - /* Register ISR */ - metal_irq_register(intr->vect_id, _ipi_handler, - intr->dev, intr); - /* Enable IPI interrupt */ - metal_irq_enable(intr->vect_id); - metal_io_write32(io, IPI_IER_OFFSET, ipi->ipi_chn_mask); - ipi->registered = 1; - - return 0; -} - -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info) -{ - - (void)proc; - struct ipi_info *ipi = (struct ipi_info *)(intr_info->data); - if (ipi == NULL) - return; - - /* Trigger IPI */ - metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask); -} - -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr) -{ - (void)proc; - (void)load_addr; - return -1; -} - -static void _shutdown_cpu(struct hil_proc *proc) -{ - (void)proc; - return; -} - -static int _poll(struct hil_proc *proc, int nonblock) -{ - struct proc_vdev *vdev; - struct ipi_info *ipi; - unsigned int flags; - - vdev = &proc->vdev; - ipi = (struct ipi_info *)(vdev->intr_info.data); - while(1) { - flags = metal_irq_save_disable(); - if (!(atomic_flag_test_and_set(&ipi->sync))) { - metal_irq_restore_enable(flags); - hil_notified(proc, (uint32_t)(-1)); - return 0; - } - if (nonblock) { - metal_irq_restore_enable(flags); - return -EAGAIN; - } - _rproc_wait(); - metal_irq_restore_enable(flags); - } -} - -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev) -{ - (void)proc; - - *dev = hil_create_generic_mem_dev(pa, size, - NORM_SHARED_NCACHE | PRIV_RW_USER_RW); - if ((*dev)) - return &((*dev)->regions[0]); - - return NULL; - -} - -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io) -{ - (void)proc; - (void)io; - hil_close_generic_mem_dev(dev); -} - -static int _initialize(struct hil_proc *proc) -{ - int ret; - struct proc_intr *intr_info; - struct ipi_info *ipi; - - if (!proc) - return -1; - - intr_info = &(proc->vdev.intr_info); - ipi = intr_info->data; - - if (ipi && ipi->name && ipi->bus_name) { - ret = metal_device_open(ipi->bus_name, ipi->name, - &ipi->dev); - if (ret) - return -ENODEV; - ipi->io = metal_device_io_region(ipi->dev, 0); - } else if (ipi->paddr) { - ipi->io = metal_allocate_memory( - sizeof(struct metal_io_region)); - if (!ipi->io) - goto error; - metal_io_init(ipi->io, (void *)ipi->paddr, - &ipi->paddr, 0x1000, - sizeof(metal_phys_addr_t) << 3, - 0, - NULL); - } - - if (ipi->io) { - metal_io_write32(ipi->io, IPI_IDR_OFFSET, - ipi->ipi_chn_mask); - atomic_store(&ipi->sync, 1); - } - ipi->registered = 0; - return 0; - -error: - _release(proc); - return -1; -} - -static void _release(struct hil_proc *proc) -{ - struct proc_intr *intr_info; - struct ipi_info *ipi; - - if (!proc) - return; - intr_info = &(proc->vdev.intr_info); - ipi = (struct ipi_info *)(intr_info->data); - if (ipi) { - if (ipi->io) { - metal_io_write32(ipi->io, IPI_IDR_OFFSET, - ipi->ipi_chn_mask); - if (ipi->dev) { - metal_device_close(ipi->dev); - ipi->dev = NULL; - } else { - metal_free_memory(ipi->io); - } - ipi->io = NULL; - } - } - -} - diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynqmp_remoteproc_r5.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynqmp_remoteproc_r5.c deleted file mode 100644 index b432688e38742e..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/drivers/zynqmp_remoteproc_r5.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * Copyright (c) 2015 Xilinx, Inc. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * zynqmp_remoteproc_r5.c - * - * DESCRIPTION - * - * This file is the Implementation of IPC hardware layer interface - * for Xilinx Zynq UltraScale+ MPSoC system. - * - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* IPI REGs OFFSET */ -#define IPI_TRIG_OFFSET 0x00000000 /** IPI trigger register offset */ -#define IPI_OBS_OFFSET 0x00000004 /** IPI observation register offset */ -#define IPI_ISR_OFFSET 0x00000010 /* IPI interrupt status register offset */ -#define IPI_IMR_OFFSET 0x00000014 /* IPI interrupt mask register offset */ -#define IPI_IER_OFFSET 0x00000018 /* IPI interrupt enable register offset */ -#define IPI_IDR_OFFSET 0x0000001C /* IPI interrupt disable register offset */ - -#define _rproc_wait() metal_cpu_yield() - -/* -- FIX ME: ipi info is to be defined -- */ -struct ipi_info { - const char *name; - const char *bus_name; - struct metal_device *dev; - struct metal_io_region *io; - metal_phys_addr_t paddr; - uint32_t ipi_chn_mask; - atomic_int sync; -}; - -/*--------------------------- Declare Functions ------------------------ */ -static int _enable_interrupt(struct proc_intr *intr); -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info); -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr); -static void _shutdown_cpu(struct hil_proc *proc); -static int _poll(struct hil_proc *proc, int nonblock); -static int _initialize(struct hil_proc *proc); -static void _release(struct hil_proc *proc); -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev); -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io); - -/*--------------------------- Globals ---------------------------------- */ -struct hil_platform_ops zynqmp_a53_r5_proc_ops = { - .enable_interrupt = _enable_interrupt, - .notify = _notify, - .boot_cpu = _boot_cpu, - .shutdown_cpu = _shutdown_cpu, - .poll = _poll, - .alloc_shm = _alloc_shm, - .release_shm = _release_shm, - .initialize = _initialize, - .release = _release, -}; - -static int _enable_interrupt(struct proc_intr *intr) -{ - (void)intr; - return 0; -} - -static void _notify(struct hil_proc *proc, struct proc_intr *intr_info) -{ - - (void)proc; - struct ipi_info *ipi = (struct ipi_info *)(intr_info->data); - if (ipi == NULL) - return; - - /* Trigger IPI */ - metal_io_write32(ipi->io, IPI_TRIG_OFFSET, ipi->ipi_chn_mask); -} - -static int _boot_cpu(struct hil_proc *proc, unsigned int load_addr) -{ - (void)proc; - (void)load_addr; - return -1; -} - -static void _shutdown_cpu(struct hil_proc *proc) -{ - (void)proc; - return; -} - -static int _poll(struct hil_proc *proc, int nonblock) -{ - struct proc_vdev *vdev; - struct ipi_info *ipi; - struct metal_io_region *io; - - vdev = &proc->vdev; - ipi = (struct ipi_info *)(vdev->intr_info.data); - io = ipi->io; - while(1) { - unsigned int ipi_intr_status = - (unsigned int)metal_io_read32(io, IPI_ISR_OFFSET); - if (ipi_intr_status & ipi->ipi_chn_mask) { - metal_io_write32(io, IPI_ISR_OFFSET, - ipi->ipi_chn_mask); - hil_notified(proc, (uint32_t)(-1)); - return 0; - } else if (nonblock) { - return -EAGAIN; - } - _rproc_wait(); - } -} - -static struct metal_io_region* _alloc_shm(struct hil_proc *proc, - metal_phys_addr_t pa, - size_t size, - struct metal_device **dev) -{ - (void)proc; - (void)pa; - (void)size; - - *dev = NULL; - return NULL; - -} - -static void _release_shm(struct hil_proc *proc, - struct metal_device *dev, - struct metal_io_region *io) -{ - (void)proc; - (void)io; - hil_close_generic_mem_dev(dev); -} - -static int _initialize(struct hil_proc *proc) -{ - int ret; - struct proc_intr *intr_info; - struct ipi_info *ipi; - unsigned int ipi_intr_status; - - if (!proc) - return -1; - - intr_info = &(proc->vdev.intr_info); - ipi = intr_info->data; - - if (ipi && ipi->name && ipi->bus_name) { - ret = metal_device_open(ipi->bus_name, ipi->name, - &ipi->dev); - if (ret) - return -ENODEV; - ipi->io = metal_device_io_region(ipi->dev, 0); - intr_info->vect_id = (uintptr_t)ipi->dev->irq_info; - } else if (ipi->paddr) { - ipi->io = metal_allocate_memory( - sizeof(struct metal_io_region)); - if (!ipi->io) - goto error; - metal_io_init(ipi->io, (void *)ipi->paddr, - &ipi->paddr, 0x1000, - (unsigned)(-1), - 0, - NULL); - } - - if (ipi->io) { - ipi_intr_status = (unsigned int)metal_io_read32( - ipi->io, IPI_ISR_OFFSET); - if (ipi_intr_status & ipi->ipi_chn_mask) - metal_io_write32(ipi->io, IPI_ISR_OFFSET, - ipi->ipi_chn_mask); - metal_io_write32(ipi->io, IPI_IDR_OFFSET, - ipi->ipi_chn_mask); - atomic_store(&ipi->sync, 1); - } - - return 0; - -error: - _release(proc); - return -1; -} - -static void _release(struct hil_proc *proc) -{ - struct proc_intr *intr_info; - struct ipi_info *ipi; - - if (!proc) - return; - intr_info = &(proc->vdev.intr_info); - ipi = (struct ipi_info *)(intr_info->data); - if (ipi) { - if (ipi->io) { - metal_io_write32(ipi->io, IPI_IDR_OFFSET, - ipi->ipi_chn_mask); - if (ipi->dev) { - metal_device_close(ipi->dev); - ipi->dev = NULL; - } else { - metal_free_memory(ipi->io); - } - ipi->io = NULL; - } - - } -} - - diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/elf_loader.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/elf_loader.c index 7000c17b546a71..e15a7843bbe6db 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/elf_loader.c +++ b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/elf_loader.c @@ -7,656 +7,705 @@ #include #include +#include #include +#include -/* Local functions. */ - -static int elf_loader_get_needed_sections(struct elf_decode_info *elf_info); -static int elf_loader_relocs_specific(struct elf_decode_info *elf_info, - Elf32_Shdr * section); -static void *elf_loader_get_entry_point_address(struct elf_decode_info - *elf_info); -static int elf_loader_relocate_link(struct elf_decode_info *elf_info); -static int elf_loader_seek_and_read(void *firmware, void *destination, - Elf32_Off offset, Elf32_Word size); -static int elf_loader_read_headers(void *firmware, - struct elf_decode_info *elf_info); -static int elf_loader_load_sections(void *firmware, - struct elf_decode_info *elf_info); -static int elf_loader_get_decode_info(void *firmware, - struct elf_decode_info *elf_info); -static int elf_loader_reloc_entry(struct elf_decode_info *elf_info, - Elf32_Rel * rel_entry); -static Elf32_Addr elf_loader_get_dynamic_symbol_addr(struct elf_decode_info - *elf_info, int index); - -/** - * elf_loader_init - * - * Initializes ELF loader. - * - * @param loader - pointer to remoteproc loader - * - * @return - 0 if success, error otherwise - */ -int elf_loader_init(struct remoteproc_loader *loader) +static int elf_is_64(const void *elf_info) { + const unsigned char *tmp = elf_info; - /* Initialize loader function table */ - loader->load_firmware = elf_loader_load_remote_firmware; - loader->retrieve_entry = elf_loader_retrieve_entry_point; - loader->retrieve_rsc = elf_loader_retrieve_resource_section; - loader->attach_firmware = elf_loader_attach_firmware; - loader->detach_firmware = elf_loader_detach_firmware; - loader->retrieve_load_addr = elf_get_load_address; - - return RPROC_SUCCESS; + if (tmp[EI_CLASS] == ELFCLASS64) + return 1; + else + return 0; } -/** - * elf_loader_attach_firmware - * - * Attaches an ELF firmware to the loader - * - * @param loader - pointer to remoteproc loader - * @param firmware - pointer to the firmware start location - * - * @return - 0 if success, error otherwise - */ -int elf_loader_attach_firmware(struct remoteproc_loader *loader, void *firmware) +static size_t elf_ehdr_size(const void *elf_info) { + if (elf_info == NULL) + return sizeof(Elf64_Ehdr); + else if (elf_is_64(elf_info) != 0) + return sizeof(Elf64_Ehdr); + else + return sizeof(Elf32_Ehdr); +} - struct elf_decode_info *elf_info; - int status; +static size_t elf_phoff(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; - /* Allocate memory for decode info structure. */ - elf_info = metal_allocate_memory(sizeof(struct elf_decode_info)); + return ehdr->e_phoff; + } else { + const Elf64_Ehdr *ehdr = elf_info; - if (!elf_info) { - return RPROC_ERR_NO_MEM; + return ehdr->e_phoff; } +} - /* Clear the ELF decode struct. */ - memset(elf_info, 0, sizeof(struct elf_decode_info)); +static size_t elf_phentsize(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; - /* Get the essential information to decode the ELF. */ - status = elf_loader_get_decode_info(firmware, elf_info); + return ehdr->e_phentsize; + } else { + const Elf64_Ehdr *ehdr = elf_info; - if (status) { - /* Free memory. */ - metal_free_memory(elf_info); - return status; + return ehdr->e_phentsize; } - - elf_info->firmware = firmware; - loader->fw_decode_info = elf_info; - - return status; } -/** - * elf_loader_detach_firmware - * - * Detaches ELF firmware from the loader - * - * @param loader - pointer to remoteproc loader - * - * @return - 0 if success, error otherwise - */ -int elf_loader_detach_firmware(struct remoteproc_loader *loader) +static int elf_phnum(const void *elf_info) { + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; - struct elf_decode_info *elf_info = - (struct elf_decode_info *)loader->fw_decode_info; - if (elf_info) { - /* Free memory. */ - metal_free_memory(elf_info->shstrtab); - metal_free_memory(elf_info->section_headers_start); - metal_free_memory(elf_info); - } + return ehdr->e_phnum; + } else { + const Elf64_Ehdr *ehdr = elf_info; - return RPROC_SUCCESS; + return ehdr->e_phnum; + } } -/** - * elf_loader_retrieve_entry_point - * - * Retrieves the ELF entrypoint. - * - * @param loader - pointer to remoteproc loader - * - * @return - entrypoint - */ -void *elf_loader_retrieve_entry_point(struct remoteproc_loader *loader) +static size_t elf_shoff(const void *elf_info) { + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shoff; + } else { + const Elf64_Ehdr *ehdr = elf_info; - return elf_loader_get_entry_point_address((struct elf_decode_info *) - loader->fw_decode_info); + return ehdr->e_shoff; + } } -/** - * elf_loader_retrieve_resource_section - * - * Retrieves the resource section. - * - * @param loader - pointer to remoteproc loader - * @param size - pointer to contain the size of the section - * - * @return - pointer to resource section - */ -void *elf_loader_retrieve_resource_section(struct remoteproc_loader *loader, - unsigned int *size) +static size_t elf_shentsize(const void *elf_info) { + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; - Elf32_Shdr *rsc_header; - void *resource_section = NULL; - struct elf_decode_info *elf_info = - (struct elf_decode_info *)loader->fw_decode_info; + return ehdr->e_shentsize; + } else { + const Elf64_Ehdr *ehdr = elf_info; - if (elf_info->rsc) { - /* Retrieve resource section header. */ - rsc_header = elf_info->rsc; - /* Retrieve resource section size. */ - *size = rsc_header->sh_size; - - /* Locate the start of resource section. */ - resource_section = (void *)((uintptr_t)elf_info->firmware - + rsc_header->sh_offset); + return ehdr->e_shentsize; } - - /* Return the address of resource section. */ - return resource_section; } -/** - * elf_loader_load_remote_firmware - * - * Loads the ELF firmware. - * - * @param loader - pointer to remoteproc loader - * - * @return - 0 if success, error otherwise - */ -int elf_loader_load_remote_firmware(struct remoteproc_loader *loader) +static int elf_shnum(const void *elf_info) { + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; - struct elf_decode_info *elf_info = - (struct elf_decode_info *)loader->fw_decode_info; - int status; + return ehdr->e_shnum; + } else { + const Elf64_Ehdr *ehdr = elf_info; - /* Load ELF sections. */ - status = elf_loader_load_sections(elf_info->firmware, elf_info); - - if (!status) { - - /* Perform dynamic relocations if needed. */ - status = elf_loader_relocate_link(elf_info); + return ehdr->e_shnum; } - - return status; } -/** - * elf_get_load_address - * - * Provides firmware load address. - * - * @param loader - pointer to remoteproc loader - * - * @return - load address pointer - */ -void *elf_get_load_address(struct remoteproc_loader *loader) +static int elf_shstrndx(const void *elf_info) { + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; - struct elf_decode_info *elf_info = - (struct elf_decode_info *)loader->fw_decode_info; - int status = 0; - Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start); - - /* Traverse all sections except the reserved null section. */ - int section_count = elf_info->elf_header.e_shnum - 1; - while ((section_count > 0) && (status == 0)) { - /* Compute the pointer to section header. */ - current = (Elf32_Shdr *) (((unsigned char *)current) - + elf_info->elf_header.e_shentsize); - /* Get the name of current section. */ - char *current_name = elf_info->shstrtab + current->sh_name; - if (!strcmp(current_name, ".text")) { - return ((void *)(current->sh_addr)); - } - /* Move to the next section. */ - section_count--; - } + return ehdr->e_shstrndx; + } else { + const Elf64_Ehdr *ehdr = elf_info; - return (RPROC_ERR_PTR); + return ehdr->e_shstrndx; + } } -/** - * elf_loader_get_needed_sections - * - * Retrieves the sections we need during the load and link from the - * section headers list. - * - * @param elf_info - ELF object decode info container. - * - * @return- Pointer to the ELF section header. - */ - -static int elf_loader_get_needed_sections(struct elf_decode_info *elf_info) +static void *elf_phtable_ptr(void *elf_info) { - Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start); - - /* We are interested in the following sections: - .dynsym - .dynstr - .rel.plt - .rel.dyn - */ - int sections_to_find = 5; - - /* Search for sections but skip the reserved null section. */ - - int section_count = elf_info->elf_header.e_shnum - 1; - while ((section_count > 0) && (sections_to_find > 0)) { - /* Compute the section header pointer. */ - current = (Elf32_Shdr *) (((unsigned char *)current) - + elf_info->elf_header.e_shentsize); - - /* Get the name of current section. */ - char *current_name = elf_info->shstrtab + current->sh_name; - - /* Proceed if the section is allocatable and is not executable. */ - if ((current->sh_flags & SHF_ALLOC) - && !(current->sh_flags & SHF_EXECINSTR)) { - /* Check for '.dynsym' or '.dynstr' or '.rel.plt' or '.rel.dyn'. */ - if (*current_name == '.') { - current_name++; - - /* Check for '.dynsym' or 'dynstr'. */ - if (*current_name == 'd') { - current_name++; - - /* Check for '.dynsym'. */ - if (strncmp(current_name, "ynsym", 5) == 0) { - elf_info->dynsym = current; - sections_to_find--; - } - - /* Check for '.dynstr'. */ - else if (strncmp(current_name, "ynstr", 5) == 0) { - elf_info->dynstr = current; - sections_to_find--; - } - } - - /* Check for '.rel.plt' or '.rel.dyn'. */ - else if (*current_name == 'r') { - current_name++; - - /* Check for '.rel.plt'. */ - if (strncmp(current_name, "el.plt", 6) == 0) { - elf_info->rel_plt = current; - sections_to_find--; - } - - /* Check for '.rel.dyn'. */ - else if (strncmp(current_name, "el.dyn", 6) == 0) { - elf_info->rel_dyn = current; - sections_to_find--; - } - - /* Check for '.resource_table'. */ - else if (strncmp(current_name, "esource_table", 13) - == 0) { - elf_info->rsc = current; - sections_to_find--; - } - } - } - } + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; - /* Move to the next section. */ - section_count--; - } + return (void *)&einfo->phdrs; + } else { + struct elf64_info *einfo = elf_info; - /* Return remaining sections section. */ - return (sections_to_find); + return (void *)&einfo->phdrs; + } } -/** - * elf_loader_relocs_specific - * - * Processes the relocations contained in the specified section. - * - * @param elf_info - elf decoding information. - * @param section - header of the specified relocation section. - * - * @return - 0 if success, error otherwise - */ -static int elf_loader_relocs_specific(struct elf_decode_info *elf_info, - Elf32_Shdr * section) +static void *elf_shtable_ptr(void *elf_info) { + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; - unsigned char *section_load_addr = (unsigned char *)section->sh_addr; - int status = 0; - unsigned int i; + return (void *)(&einfo->shdrs); + } else { + struct elf64_info *einfo = elf_info; - /* Check the section type. */ - if (section->sh_type == SHT_REL) { - /* Traverse the list of relocation entries contained in the section. */ - for (i = 0; (i < section->sh_size) && (status == 0); - i += section->sh_entsize) { - /* Compute the relocation entry address. */ - Elf32_Rel *rel_entry = - (Elf32_Rel *) (section_load_addr + i); - - /* Process the relocation entry. */ - status = elf_loader_reloc_entry(elf_info, rel_entry); - } + return (void *)(&einfo->shdrs); } - - /* Return status to caller. */ - return (status); } -/** - * elf_loader_get_entry_point_address - * - * Retrieves the entry point address from the specified ELF object. - * - * @param elf_info - elf object decode info container. - * @param runtime_buffer - buffer containing ELF sections which are - * part of runtime. - * - * @return - entry point address of the specified ELF object. - */ -static void *elf_loader_get_entry_point_address(struct elf_decode_info - *elf_info) +static void **elf_shstrtab_ptr(void *elf_info) { - return ((void *)elf_info->elf_header.e_entry); -} + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; -/** - * elf_loader_relocate_link - * - * Relocates and links the given ELF object. - * - * @param elf_info - elf object decode info container. + return &einfo->shstrtab; + } else { + struct elf64_info *einfo = elf_info; - * - * @return - 0 if success, error otherwise - */ + return &einfo->shstrtab; + } +} -static int elf_loader_relocate_link(struct elf_decode_info *elf_info) +static unsigned int *elf_load_state(void *elf_info) { - int status = 0; + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; - /* Check of .rel.dyn section exists in the ELF. */ - if (elf_info->rel_dyn) { - /* Relocate and link .rel.dyn section. */ - status = - elf_loader_relocs_specific(elf_info, elf_info->rel_dyn); + return &einfo->load_state; + } else { + struct elf64_info *einfo = elf_info; + + return &einfo->load_state; } +} - /* Proceed to check if .rel.plt section exists, if no error encountered yet. */ - if (status == 0 && elf_info->rel_plt) { - /* Relocate and link .rel.plt section. */ - status = - elf_loader_relocs_specific(elf_info, elf_info->rel_plt); +static void elf_parse_segment(void *elf_info, const void *elf_phdr, + unsigned int *p_type, size_t *p_offset, + metal_phys_addr_t *p_vaddr, + metal_phys_addr_t *p_paddr, + size_t *p_filesz, size_t *p_memsz) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Phdr *phdr = elf_phdr; + + if (p_type != NULL) + *p_type = (unsigned int)phdr->p_type; + if (p_offset != NULL) + *p_offset = (size_t)phdr->p_offset; + if (p_vaddr != NULL) + *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr; + if (p_paddr != NULL) + *p_paddr = (metal_phys_addr_t)phdr->p_paddr; + if (p_filesz != NULL) + *p_filesz = (size_t)phdr->p_filesz; + if (p_memsz != NULL) + *p_memsz = (size_t)phdr->p_memsz; + } else { + const Elf64_Phdr *phdr = elf_phdr; + + if (p_type != NULL) + *p_type = (unsigned int)phdr->p_type; + if (p_offset != NULL) + *p_offset = (size_t)phdr->p_offset; + if (p_vaddr != NULL) + if (p_vaddr != NULL) + *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr; + if (p_paddr != NULL) + *p_paddr = (metal_phys_addr_t)phdr->p_paddr; + if (p_filesz != NULL) + *p_filesz = (size_t)phdr->p_filesz; + if (p_memsz != NULL) + *p_memsz = (size_t)phdr->p_memsz; } +} - /* Return status to caller */ - return (status); +static const void *elf_get_segment_from_index(void *elf_info, int index) +{ + if (elf_is_64(elf_info) == 0) { + const struct elf32_info *einfo = elf_info; + const Elf32_Ehdr *ehdr = &einfo->ehdr; + const Elf32_Phdr *phdrs = einfo->phdrs; + + if (phdrs == NULL) + return NULL; + if (index < 0 || index > ehdr->e_phnum) + return NULL; + return &phdrs[index]; + } else { + const struct elf64_info *einfo = elf_info; + const Elf64_Ehdr *ehdr = &einfo->ehdr; + const Elf64_Phdr *phdrs = einfo->phdrs; + + if (phdrs == NULL) + return NULL; + if (index < 0 || index > ehdr->e_phnum) + return NULL; + return &phdrs[index]; + } } -/** - * elf_loader_seek_and_read - * - * Seeks to the specified offset in the given file and reads the data - * into the specified destination location. - * - * @param firmware - firmware to read from. - * @param destination - Location into which the data should be read. - * @param offset - Offset to seek in the file. - * @param size - Size of the data to read. +static void *elf_get_section_from_name(void *elf_info, const char *name) +{ + unsigned int i; + const char *name_table; + + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + Elf32_Ehdr *ehdr = &einfo->ehdr; + Elf32_Shdr *shdr = einfo->shdrs; + + name_table = einfo->shstrtab; + if (shdr == NULL || name_table == NULL) + return NULL; + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (strcmp(name, name_table + shdr->sh_name)) + continue; + else + return shdr; + } + } else { + struct elf64_info *einfo = elf_info; + Elf64_Ehdr *ehdr = &einfo->ehdr; + Elf64_Shdr *shdr = einfo->shdrs; + + name_table = einfo->shstrtab; + if (shdr == NULL || name_table == NULL) + return NULL; + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (strcmp(name, name_table + shdr->sh_name)) + continue; + else + return shdr; + } + } + return NULL; +} - * - * @return - 0 if success, error otherwise - */ +static void *elf_get_section_from_index(void *elf_info, int index) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + Elf32_Ehdr *ehdr = &einfo->ehdr; + Elf32_Shdr *shdr = einfo->shdrs; + + if (shdr == NULL) + return NULL; + if (index > ehdr->e_shnum) + return NULL; + return &einfo->shdrs[index]; + } else { + struct elf64_info *einfo = elf_info; + Elf64_Ehdr *ehdr = &einfo->ehdr; + Elf64_Shdr *shdr = einfo->shdrs; + + if (shdr == NULL) + return NULL; + if (index > ehdr->e_shnum) + return NULL; + return &einfo->shdrs[index]; + } +} -static int elf_loader_seek_and_read(void *firmware, void *destination, - Elf32_Off offset, Elf32_Word size) +static void elf_parse_section(void *elf_info, void *elf_shdr, + unsigned int *sh_type, unsigned int *sh_flags, + metal_phys_addr_t *sh_addr, + size_t *sh_offset, size_t *sh_size, + unsigned int *sh_link, unsigned int *sh_info, + unsigned int *sh_addralign, + size_t *sh_entsize) { - char *src = (char *)firmware; + if (elf_is_64(elf_info) == 0) { + Elf32_Shdr *shdr = elf_shdr; + + if (sh_type != NULL) + *sh_type = shdr->sh_type; + if (sh_flags != NULL) + *sh_flags = shdr->sh_flags; + if (sh_addr != NULL) + *sh_addr = (metal_phys_addr_t)shdr->sh_addr; + if (sh_offset != NULL) + *sh_offset = shdr->sh_offset; + if (sh_size != NULL) + *sh_size = shdr->sh_size; + if (sh_link != NULL) + *sh_link = shdr->sh_link; + if (sh_info != NULL) + *sh_info = shdr->sh_info; + if (sh_addralign != NULL) + *sh_addralign = shdr->sh_addralign; + if (sh_entsize != NULL) + *sh_entsize = shdr->sh_entsize; + } else { + Elf64_Shdr *shdr = elf_shdr; + + if (sh_type != NULL) + *sh_type = shdr->sh_type; + if (sh_flags != NULL) + *sh_flags = shdr->sh_flags; + if (sh_addr != NULL) + *sh_addr = (metal_phys_addr_t)(shdr->sh_addr & + (metal_phys_addr_t)(-1)); + if (sh_offset != NULL) + *sh_offset = shdr->sh_offset; + if (sh_size != NULL) + *sh_size = shdr->sh_size; + if (sh_link != NULL) + *sh_link = shdr->sh_link; + if (sh_info != NULL) + *sh_info = shdr->sh_info; + if (sh_addralign != NULL) + *sh_addralign = shdr->sh_addralign; + if (sh_entsize != NULL) + *sh_entsize = shdr->sh_entsize; + } +} - /* Seek to the specified offset. */ - src = src + offset; +static const void *elf_next_load_segment(void *elf_info, int *nseg, + metal_phys_addr_t *da, + size_t *noffset, size_t *nfsize, + size_t *nmsize) +{ + const void *phdr; + unsigned int p_type = PT_NULL; + + if (elf_info == NULL || nseg == NULL) + return NULL; + while(p_type != PT_LOAD) { + phdr = elf_get_segment_from_index(elf_info, *nseg); + if (phdr == NULL) + return NULL; + elf_parse_segment(elf_info, phdr, &p_type, noffset, + da, NULL, nfsize, nmsize); + *nseg = *nseg + 1; + } + return phdr; +} - /* Read the data. */ - memcpy((char *)destination, src, size); +static size_t elf_info_size(const void *img_data) +{ + if (elf_is_64(img_data) == 0) + return sizeof(struct elf32_info); + else + return sizeof(struct elf64_info); +} - /* Return status to caller. */ - return (0); +int elf_identify(const void *img_data, size_t len) +{ + if (len < SELFMAG || img_data == NULL) + return -RPROC_EINVAL; + if (memcmp(img_data, ELFMAG, SELFMAG) != 0) + return -RPROC_EINVAL; + else + return 0; } -/** - * elf_loader_read_headers - * - * Reads the ELF headers (ELF header, section headers and the section - * headers string table) essential to access further information from - * the file containing the ELF object. - * - * @param firmware - firmware to read from. - * @param elf_info - ELF object decode info container. - * - * @return - 0 if success, error otherwise - */ -static int elf_loader_read_headers(void *firmware, - struct elf_decode_info *elf_info) +int elf_load_header(const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + size_t *noffset, size_t *nlen) { - int status = 0; - unsigned int section_count; - - /* Read the ELF header. */ - status = elf_loader_seek_and_read(firmware, &(elf_info->elf_header), 0, - sizeof(Elf32_Ehdr)); - - /* Ensure the read was successful. */ - if (!status) { - /* Get section count from the ELF header. */ - section_count = elf_info->elf_header.e_shnum; - - /* Allocate memory to read in the section headers. */ - elf_info->section_headers_start = metal_allocate_memory(section_count * elf_info->elf_header.e_shentsize); - - /* Check if the allocation was successful. */ - if (elf_info->section_headers_start) { - /* Read the section headers list. */ - status = elf_loader_seek_and_read(firmware, - elf_info-> - section_headers_start, - elf_info->elf_header. - e_shoff, - section_count * - elf_info->elf_header. - e_shentsize); - - /* Ensure the read was successful. */ - if (!status) { - /* Compute the pointer to section header string table section. */ - Elf32_Shdr *section_header_string_table = - (Elf32_Shdr *) (elf_info-> - section_headers_start + - elf_info->elf_header. - e_shstrndx * - elf_info->elf_header. - e_shentsize); - - /* Allocate the memory for section header string table. */ - elf_info->shstrtab = metal_allocate_memory(section_header_string_table->sh_size); - - /* Ensure the allocation was successful. */ - if (elf_info->shstrtab) { - /* Read the section headers string table. */ - status = - elf_loader_seek_and_read(firmware, - elf_info-> - shstrtab, - section_header_string_table-> - sh_offset, - section_header_string_table-> - sh_size); - } + unsigned int *load_state; + + metal_assert(noffset != NULL); + metal_assert(nlen != NULL); + /* Get ELF header */ + if (last_load_state == ELF_STATE_INIT) { + size_t tmpsize; + + metal_log(METAL_LOG_DEBUG, "Loading ELF headering\r\n"); + tmpsize = elf_ehdr_size(img_data); + if (len < tmpsize) { + *noffset = 0; + *nlen = tmpsize; + return ELF_STATE_INIT; + } else { + size_t infosize = elf_info_size(img_data); + + if (*img_info == NULL) { + *img_info = metal_allocate_memory(infosize); + if (*img_info == NULL) + return -ENOMEM; + memset(*img_info, 0, infosize); } + memcpy(*img_info, img_data, tmpsize); + load_state = elf_load_state(*img_info); + *load_state = ELF_STATE_WAIT_FOR_PHDRS; + last_load_state = ELF_STATE_WAIT_FOR_PHDRS; } } - - /* Return status to caller. */ - return (status); + metal_assert(*img_info != NULL); + load_state = elf_load_state(*img_info); + if (last_load_state != (int)*load_state) + return -RPROC_EINVAL; + /* Get ELF program headers */ + if (*load_state == ELF_STATE_WAIT_FOR_PHDRS) { + size_t phdrs_size; + size_t phdrs_offset; + char **phdrs; + const void *img_phdrs; + + metal_log(METAL_LOG_DEBUG, "Loading ELF program header.\r\n"); + phdrs_offset = elf_phoff(*img_info); + phdrs_size = elf_phnum(*img_info) * elf_phentsize(*img_info); + if (offset > phdrs_offset || + offset + len < phdrs_offset + phdrs_size) { + *noffset = phdrs_offset; + *nlen = phdrs_size; + return (int)*load_state; + } + /* caculate the programs headers offset to the image_data */ + phdrs_offset -= offset; + img_phdrs = (const void *) + ((const char *)img_data + phdrs_offset); + phdrs = (char **)elf_phtable_ptr(*img_info); + (*phdrs) = metal_allocate_memory(phdrs_size); + if (*phdrs == NULL) + return -ENOMEM; + memcpy((void *)(*phdrs), img_phdrs, phdrs_size); + *load_state = ELF_STATE_WAIT_FOR_SHDRS | + RPROC_LOADER_READY_TO_LOAD; + } + /* Get ELF Section Headers */ + if ((*load_state & ELF_STATE_WAIT_FOR_SHDRS) != 0) { + size_t shdrs_size; + size_t shdrs_offset; + char **shdrs; + const void *img_shdrs; + + metal_log(METAL_LOG_DEBUG, "Loading ELF section header.\r\n"); + shdrs_offset = elf_shoff(*img_info); + if (elf_shnum(*img_info) == 0) { + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_HDRS_COMPLETE; + *nlen = 0; + return (int)*load_state; + } + shdrs_size = elf_shnum(*img_info) * elf_shentsize(*img_info); + if (offset > shdrs_offset || + offset + len < shdrs_offset + shdrs_size) { + *noffset = shdrs_offset; + *nlen = shdrs_size; + return (int)*load_state; + } + /* caculate the sections headers offset to the image_data */ + shdrs_offset -= offset; + img_shdrs = (const void *) + ((const char *)img_data + shdrs_offset); + shdrs = (char **)elf_shtable_ptr(*img_info); + (*shdrs) = metal_allocate_memory(shdrs_size); + if (*shdrs == NULL) + return -ENOMEM; + memcpy((void *)*shdrs, img_shdrs, shdrs_size); + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_WAIT_FOR_SHSTRTAB; + metal_log(METAL_LOG_DEBUG, + "Loading ELF section header complete.\r\n"); + } + /* Get ELF SHSTRTAB section */ + if ((*load_state & ELF_STATE_WAIT_FOR_SHSTRTAB) != 0) { + size_t shstrtab_size; + size_t shstrtab_offset; + int shstrndx; + void *shdr; + void **shstrtab; + + metal_log(METAL_LOG_DEBUG, "Loading ELF shstrtab.\r\n"); + shstrndx = elf_shstrndx(*img_info); + shdr = elf_get_section_from_index(*img_info, shstrndx); + if (shdr == NULL) + return -RPROC_EINVAL; + elf_parse_section(*img_info, shdr, NULL, NULL, + NULL, &shstrtab_offset, + &shstrtab_size, NULL, NULL, + NULL, NULL); + if (offset > shstrtab_offset || + offset + len < shstrtab_offset + shstrtab_size) { + *noffset = shstrtab_offset; + *nlen = shstrtab_size; + return (int)*load_state; + } + /* Caculate shstrtab section offset to the input image data */ + shstrtab_offset -= offset; + shstrtab = elf_shstrtab_ptr(*img_info); + *shstrtab = metal_allocate_memory(shstrtab_size); + if (*shstrtab == NULL) + return -ENOMEM; + memcpy(*shstrtab, + (const void *)((const char *)img_data + shstrtab_offset), + shstrtab_size); + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_HDRS_COMPLETE; + *nlen = 0; + return *load_state; + } + return last_load_state; } -/** - * elf_loader_file_read_sections - * - * Reads the ELF section contents from the specified file containing - * the ELF object. - * - * @param firmware - firmware to read from. - * @param elf_info - ELF object decode info container. - * - * @return - 0 if success, error otherwise - */ -static int elf_loader_load_sections(void *firmware, - struct elf_decode_info *elf_info) +int elf_load(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize) { - int status = 0; - Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start); - - /* Traverse all sections except the reserved null section. */ - int section_count = elf_info->elf_header.e_shnum - 1; - while ((section_count > 0) && (status == 0)) { - /* Compute the pointer to section header. */ - current = (Elf32_Shdr *) (((unsigned char *)current) - + elf_info->elf_header.e_shentsize); - - /* Make sure the section can be allocated and is not empty. */ - if ((current->sh_flags & SHF_ALLOC) && (current->sh_size)) { - char *destination = NULL; - - /* Check if the section is part of runtime and is not section with - * no-load attributes such as BSS or heap. */ - if ((current->sh_type & SHT_NOBITS) == 0) { - /* Compute the destination address where the section should - * be copied. */ - destination = (char *)(current->sh_addr); - status = - elf_loader_seek_and_read(firmware, - destination, - current->sh_offset, - current->sh_size); + unsigned int *load_state; + const void *phdr; + + (void)rproc; + metal_assert(da != NULL); + metal_assert(noffset != NULL); + metal_assert(nlen != NULL); + if ((last_load_state & RPROC_LOADER_MASK) == RPROC_LOADER_NOT_READY) { + metal_log(METAL_LOG_DEBUG, + "%s, needs to load header first\r\n"); + last_load_state = elf_load_header(img_data, offset, len, + img_info, last_load_state, + noffset, nlen); + if ((last_load_state & RPROC_LOADER_MASK) == + RPROC_LOADER_NOT_READY) { + *da = RPROC_LOAD_ANYADDR; + return last_load_state; + } + } + metal_assert(img_info != NULL && *img_info != NULL); + load_state = elf_load_state(*img_info); + /* For ELF, segment padding value is 0 */ + if (padding != NULL) + *padding = 0; + if ((*load_state & RPROC_LOADER_READY_TO_LOAD) != 0) { + int nsegment; + size_t nsegmsize = 0; + size_t nsize = 0; + int phnums = 0; + + nsegment = (int)(*load_state & ELF_NEXT_SEGMENT_MASK); + phdr = elf_next_load_segment(*img_info, &nsegment, da, + noffset, &nsize, &nsegmsize); + if (phdr == NULL) { + metal_log(METAL_LOG_DEBUG, "cannot find more segement\r\n"); + *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | + (unsigned int)(nsegment & ELF_NEXT_SEGMENT_MASK); + return *load_state; + } + *nlen = nsize; + *nmemsize = nsegmsize; + phnums = elf_phnum(*img_info); + metal_log(METAL_LOG_DEBUG, "segment: %d, total segs %d\r\n", + nsegment, phnums); + if (nsegment == elf_phnum(*img_info)) { + *load_state = (*load_state & (~RPROC_LOADER_MASK)) | + RPROC_LOADER_POST_DATA_LOAD; + } + *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | + (unsigned int)(nsegment & ELF_NEXT_SEGMENT_MASK); + } else if ((*load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) { + if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) { + last_load_state = elf_load_header(img_data, offset, + len, img_info, + last_load_state, + noffset, nlen); + if (last_load_state < 0) + return last_load_state; + if ((last_load_state & ELF_STATE_HDRS_COMPLETE) != 0) { + *load_state = (*load_state & + (~RPROC_LOADER_MASK)) | + RPROC_LOADER_LOAD_COMPLETE; + *nlen = 0; } + *da = RPROC_LOAD_ANYADDR; + } else { + /* TODO: will handle relocate later */ + *nlen = 0; + *load_state = (*load_state & + (~RPROC_LOADER_MASK)) | + RPROC_LOADER_LOAD_COMPLETE; } - - /* Move to the next section. */ - section_count--; } + return *load_state; +} - /* Return status to caller. */ - return (status); +void elf_release(void *img_info) +{ + if (img_info == NULL) + return; + if (elf_is_64(img_info) == 0) { + struct elf32_info *elf_info = img_info; + + if (elf_info->phdrs != NULL) + metal_free_memory(elf_info->phdrs); + if (elf_info->shdrs != NULL) + metal_free_memory(elf_info->shdrs); + if (elf_info->shstrtab != NULL) + metal_free_memory(elf_info->shstrtab); + metal_free_memory(img_info); + + } else { + struct elf64_info *elf_info = img_info; + + if (elf_info->phdrs != NULL) + metal_free_memory(elf_info->phdrs); + if (elf_info->shdrs != NULL) + metal_free_memory(elf_info->shdrs); + if (elf_info->shstrtab != NULL) + metal_free_memory(elf_info->shstrtab); + metal_free_memory(img_info); + } } -/** - * elf_loader_get_decode_info - * - * Retrieves the information necessary to decode the ELF object for - * loading, relocating and linking. - * - * @param firmware - firmware to read from. - * @param elf_info - ELF object decode info container. - * - * @return - 0 if success, error otherwise - */ -static int elf_loader_get_decode_info(void *firmware, - struct elf_decode_info *elf_info) +metal_phys_addr_t elf_get_entry(void *elf_info) { - int status; + if (!elf_info) + return METAL_BAD_PHYS; - /* Read the ELF headers (ELF header and section headers including - * the section header string table). */ - status = elf_loader_read_headers(firmware, elf_info); + if (elf_is_64(elf_info) == 0) { + Elf32_Ehdr *elf_ehdr = (Elf32_Ehdr *)elf_info; + Elf32_Addr e_entry; - /* Ensure that ELF headers were read successfully. */ - if (!status) { - /* Retrieve the sections required for load. */ - elf_loader_get_needed_sections(elf_info); + e_entry = elf_ehdr->e_entry; + return (metal_phys_addr_t)e_entry; + } else { + Elf64_Ehdr *elf_ehdr = (Elf64_Ehdr *)elf_info; + Elf64_Addr e_entry; + e_entry = elf_ehdr->e_entry; + return (metal_phys_addr_t)(e_entry & (metal_phys_addr_t)(-1)); } - - /* Return status to caller. */ - return (status); } -/** - * elf_loader_get_dynamic_symbol_addr - * - * Retrieves the (relocatable) address of the symbol specified as - * index from the given ELF object. - * - * @param elf_info - ELF object decode info container. - * @param index - Index of the desired symbol in the dynamic symbol table. - * - * @return - Address of the specified symbol. - */ -static Elf32_Addr elf_loader_get_dynamic_symbol_addr(struct elf_decode_info - *elf_info, int index) +int elf_locate_rsc_table(void *elf_info, metal_phys_addr_t *da, + size_t *offset, size_t *size) { - Elf32_Sym *symbol_entry = (Elf32_Sym *) (elf_info->dynsym_addr - + - index * - elf_info->dynsym->sh_entsize); - - /* Return the symbol address. */ - return (symbol_entry->st_value); + char *sect_name = ".resource_table"; + void *shdr; + unsigned int *load_state; + + if (elf_info == NULL) + return -RPROC_EINVAL; + + load_state = elf_load_state(elf_info); + if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) + return -RPROC_ERR_LOADER_STATE; + shdr = elf_get_section_from_name(elf_info, sect_name); + if (shdr == NULL) { + metal_assert(size != NULL); + *size = 0; + return 0; + } + elf_parse_section(elf_info, shdr, NULL, NULL, + da, offset, size, + NULL, NULL, NULL, NULL); + return 0; } -/** - * elf_loader_reloc_entry - * - * Processes the specified relocation entry. It handles the relocation - * and linking both cases. - * - * - * @param elf_info - ELF object decode info container. - * - * @return - 0 if success, error otherwise - */ -static int elf_loader_reloc_entry(struct elf_decode_info *elf_info, - Elf32_Rel * rel_entry) +int elf_get_load_state(void *img_info) { - unsigned char rel_type = ELF32_R_TYPE(rel_entry->r_info); - int status = 0; - - switch (rel_type) { - case R_ARM_ABS32: /* 0x02 */ - { - Elf32_Addr sym_addr = - elf_loader_get_dynamic_symbol_addr(elf_info, - ELF32_R_SYM - (rel_entry-> - r_info)); - - if (sym_addr) { - *((unsigned int *)(rel_entry->r_offset)) = - (unsigned int)sym_addr; - break; - } - } + unsigned int *load_state; - break; - - default: - break; - } - - return status; + if (img_info == NULL) + return -RPROC_EINVAL; + load_state = elf_load_state(img_info); + return (int)(*load_state); } + +struct loader_ops elf_ops = { + .load_header = elf_load_header, + .load_data = elf_load, + .locate_rsc_table = elf_locate_rsc_table, + .release = elf_release, + .get_entry = elf_get_entry, + .get_load_state = elf_get_load_state, +}; diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc.c index 28337590c1165f..be9b86936208a0 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc.c +++ b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc.c @@ -6,330 +6,958 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include +#include +#include +#include +#include #include #include +#include #include -#include -#include -#include -#include -/** - * remoteproc_resource_init - * - * Initializes resources for remoteproc remote configuration. Only - * remoteproc remote applications are allowed to call this function. - * - * @param rsc_info - pointer to resource table info control - * block - * @param proc - pointer to the hil_proc - * @param channel_created - callback function for channel creation - * @param channel_destroyed - callback function for channel deletion - * @param default_cb - default callback for channel I/O - * @param rproc_handle - pointer to new remoteproc instance - * @param rpmsg_role - 1 for rpmsg master, or 0 for rpmsg slave - * - * @param returns - status of function execution - * - */ -int remoteproc_resource_init(struct rsc_table_info *rsc_info, - struct hil_proc *proc, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, - rpmsg_rx_cb_t default_cb, - struct remote_proc **rproc_handle, - int rpmsg_role) +/****************************************************************************** + * static functions + *****************************************************************************/ +static struct loader_ops * +remoteproc_check_fw_format(const void *img_data, size_t img_len) +{ + if (img_len <= 0) + return NULL; + else if (elf_identify(img_data, img_len) == 0) + return &elf_ops; + else + return NULL; +} + +static struct remoteproc_mem * +remoteproc_get_mem(struct remoteproc *rproc, const char *name, + metal_phys_addr_t pa, metal_phys_addr_t da, + void *va, size_t size) +{ + struct metal_list *node; + struct remoteproc_mem *mem; + + metal_list_for_each(&rproc->mems, node) { + mem = metal_container_of(node, struct remoteproc_mem, node); + if (name) { + if (!strncmp(name, mem->name, sizeof(mem->name))) + return mem; + } else if (pa != METAL_BAD_PHYS) { + metal_phys_addr_t pa_start, pa_end; + + pa_start = mem->pa; + pa_end = pa_start + mem->size; + if (pa >= pa_start && (pa + size) <= pa_end) + return mem; + } else if (da != METAL_BAD_PHYS) { + metal_phys_addr_t da_start, da_end; + + da_start = mem->da; + da_end = da_start + mem->size; + if (da >= da_start && (da + size) <= da_end) + return mem; + } else if (va) { + if (metal_io_virt_to_offset(mem->io, va) != + METAL_BAD_OFFSET) + return mem; + + } else { + return NULL; + } + } + return NULL; +} + +static metal_phys_addr_t +remoteproc_datopa(struct remoteproc_mem *mem, metal_phys_addr_t da) +{ + metal_phys_addr_t pa; + + pa = mem->pa + da - mem->da; + return pa; +} + +static metal_phys_addr_t +remoteproc_patoda(struct remoteproc_mem *mem, metal_phys_addr_t pa) +{ + metal_phys_addr_t da; + + da = mem->da + pa - mem->pa; + return da; +} + +static void *remoteproc_get_rsc_table(struct remoteproc *rproc, + void *store, + struct image_store_ops *store_ops, + size_t offset, + size_t len) +{ + int ret; + void *rsc_table = NULL; + const void *img_data; + + /* Copy the resource table to local memory, + * the caller should be responsible to release the memory + */ + rsc_table = metal_allocate_memory(len); + if (!rsc_table) { + return RPROC_ERR_PTR(-RPROC_ENOMEM); + } + ret = store_ops->load(store, offset, len, &img_data, RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < 0 || ret < (int)len || img_data == NULL) { + metal_log(METAL_LOG_ERROR, + "get rsc failed: 0x%llx, 0x%llx\r\n", offset, len); + rsc_table = RPROC_ERR_PTR(-RPROC_EINVAL); + goto error; + } + memcpy(rsc_table, img_data, len); + + ret = handle_rsc_table(rproc, rsc_table, len, NULL); + if (ret < 0) { + rsc_table = RPROC_ERR_PTR(ret); + goto error; + } + return rsc_table; + +error: + metal_free_memory(rsc_table); + return rsc_table; +} + +int remoteproc_parse_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size) { + struct metal_io_region *io; - struct remote_proc *rproc; - int status; - int remote_rpmsg_role; + io = remoteproc_get_io_with_va(rproc, (void *)rsc_table); + return handle_rsc_table(rproc, rsc_table, rsc_size, io); +} - if (!rsc_info || !proc) { - return RPROC_ERR_PARAM; +int remoteproc_set_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size) +{ + int ret; + struct metal_io_region *io; + + io = remoteproc_get_io_with_va(rproc, (void *)rsc_table); + if (!io) + return -EINVAL; + ret = remoteproc_parse_rsc_table(rproc, rsc_table, rsc_size); + if (!ret) { + rproc->rsc_table = rsc_table; + rproc->rsc_len = rsc_size; + rproc->rsc_io = io; } + return ret; + +} - rproc = metal_allocate_memory(sizeof(struct remote_proc)); +struct remoteproc *remoteproc_init(struct remoteproc *rproc, + struct remoteproc_ops *ops, void *priv) +{ if (rproc) { - memset(rproc, 0x00, sizeof(struct remote_proc)); - /* There can be only one master for remote configuration so use the - * rsvd cpu id for creating hil proc */ - rproc->proc = proc; - status = hil_init_proc(proc); - if (!status) { - /* Parse resource table */ - status = - handle_rsc_table(rproc, rsc_info->rsc_tab, - rsc_info->size); - if (status == RPROC_SUCCESS) { - /* Initialize RPMSG "messaging" component */ - *rproc_handle = rproc; - remote_rpmsg_role = (rpmsg_role == RPMSG_MASTER? - RPMSG_REMOTE : RPMSG_MASTER); - status = - rpmsg_init(proc, - &rproc->rdev, channel_created, - channel_destroyed, default_cb, - remote_rpmsg_role); - } else { - status = RPROC_ERR_NO_RSC_TABLE; - } - } else { - status = RPROC_ERR_CPU_INIT; - } + memset(rproc, 0, sizeof (*rproc)); + rproc->state = RPROC_OFFLINE; + metal_mutex_init(&rproc->lock); + metal_list_init(&rproc->mems); + metal_list_init(&rproc->vdevs); + } + rproc = ops->init(rproc, ops, priv); + return rproc; +} + +int remoteproc_remove(struct remoteproc *rproc) +{ + int ret; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_OFFLINE) + rproc->ops->remove(rproc); + else + ret = -EBUSY; + metal_mutex_release(&rproc->lock); } else { - status = RPROC_ERR_NO_MEM; + ret = -EINVAL; } + return ret; +} + +int remoteproc_config(struct remoteproc *rproc, void *data) +{ + int ret = -RPROC_ENODEV; - /* Cleanup in case of error */ - if (status != RPROC_SUCCESS) { - *rproc_handle = 0; - (void)remoteproc_resource_deinit(rproc); - return status; + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_OFFLINE) { + /* configure operation is allowed if the state is + * offline or ready. This function can be called + * mulitple times before start the remote. + */ + if (rproc->ops->config) + ret = rproc->ops->config(rproc, data); + rproc->state = RPROC_READY; + } else { + ret = -RPROC_EINVAL; + } + metal_mutex_release(&rproc->lock); } - return status; + return ret; } -/** - * remoteproc_resource_deinit - * - * Uninitializes resources for remoteproc "remote" configuration. - * - * @param rproc - pointer to rproc instance - * - * @param returns - status of function execution - * - */ +int remoteproc_start(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; -int remoteproc_resource_deinit(struct remote_proc *rproc) + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_READY) { + ret = rproc->ops->start(rproc); + rproc->state = RPROC_RUNNING; + } else { + ret = -RPROC_EINVAL; + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_stop(struct remoteproc *rproc) { + int ret = -RPROC_ENODEV; + if (rproc) { - if (rproc->rdev) { - rpmsg_deinit(rproc->rdev); + metal_mutex_acquire(&rproc->lock); + if (rproc->state != RPROC_STOPPED && + rproc->state != RPROC_OFFLINE) { + if (rproc->ops->stop) + ret = rproc->ops->stop(rproc); + rproc->state = RPROC_STOPPED; + } else { + ret = 0; } - if (rproc->proc) { - hil_delete_proc(rproc->proc); - rproc->proc = NULL; + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_shutdown(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + ret = 0; + metal_mutex_acquire(&rproc->lock); + if (rproc->state != RPROC_OFFLINE) { + if (rproc->state != RPROC_STOPPED) { + if (rproc->ops->stop) + ret = rproc->ops->stop(rproc); + } + if (!ret) { + if (rproc->ops->shutdown) + ret = rproc->ops->shutdown(rproc); + if (!ret) { + rproc->state = RPROC_OFFLINE; + } + } } - metal_free_memory(rproc); + metal_mutex_release(&rproc->lock); } + return ret; +} - return RPROC_SUCCESS; +struct metal_io_region * +remoteproc_get_io_with_name(struct remoteproc *rproc, + const char *name) +{ + struct remoteproc_mem *mem; + + mem = remoteproc_get_mem(rproc, name, + METAL_BAD_PHYS, METAL_BAD_PHYS, NULL, 0); + if (mem) + return mem->io; + else + return NULL; } -/** - * remoteproc_init - * - * Initializes resources for remoteproc master configuration. Only - * remoteproc master applications are allowed to call this function. - * - * @param fw_name - name of frimware - * @param proc - pointer to hil_proc - * @param channel_created - callback function for channel creation - * @param channel_destroyed - callback function for channel deletion - * @param default_cb - default callback for channel I/O - * @param rproc_handle - pointer to new remoteproc instance - * - * @param returns - status of function execution - * - */ -int remoteproc_init(char *fw_name, struct hil_proc *proc, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb, - struct remote_proc **rproc_handle) +struct metal_io_region * +remoteproc_get_io_with_pa(struct remoteproc *rproc, + metal_phys_addr_t pa) +{ + struct remoteproc_mem *mem; + + mem = remoteproc_get_mem(rproc, NULL, pa, METAL_BAD_PHYS, NULL, 0); + if (mem) + return mem->io; + else + return NULL; +} + +struct metal_io_region * +remoteproc_get_io_with_da(struct remoteproc *rproc, + metal_phys_addr_t da, + unsigned long *offset) { + struct remoteproc_mem *mem; - struct remote_proc *rproc; - struct resource_table *rsc_table; - unsigned int fw_size, rsc_size; - uintptr_t fw_addr; - int status; + mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, da, NULL, 0); + if (mem) { + struct metal_io_region *io; + metal_phys_addr_t pa; - if (!fw_name) { - return RPROC_ERR_PARAM; + io = mem->io; + pa = remoteproc_datopa(mem, da); + *offset = metal_io_phys_to_offset(io, pa); + return io; + } else { + return NULL; } +} - rproc = metal_allocate_memory(sizeof(struct remote_proc)); - if (rproc) { - memset((void *)rproc, 0x00, sizeof(struct remote_proc)); - /* Create proc instance */ - rproc->proc = proc; - status = hil_init_proc(proc); - if (!status) { - /* Retrieve firmware attributes */ - status = - hil_get_firmware(fw_name, &fw_addr, - &fw_size); - if (!status) { - /* Initialize ELF loader - currently only ELF format is supported */ - rproc->loader = - remoteproc_loader_init(ELF_LOADER); - if (rproc->loader) { - /* Attach the given firmware with the ELF parser/loader */ - status = - remoteproc_loader_attach_firmware - (rproc->loader, - (void *)fw_addr); - } else { - status = RPROC_ERR_LOADER; - } +struct metal_io_region * +remoteproc_get_io_with_va(struct remoteproc *rproc, void *va) +{ + struct remoteproc_mem *mem; + + mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, METAL_BAD_PHYS, + va, 0); + if (mem) + return mem->io; + else + return NULL; +} + +void *remoteproc_mmap(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io) +{ + void *va = NULL; + metal_phys_addr_t lpa, lda; + struct remoteproc_mem *mem; + + if (!rproc) + return NULL; + else if (!pa && !da) + return NULL; + if (pa) + lpa = *pa; + else + lpa = METAL_BAD_PHYS; + if (da) + lda = *da; + else + lda = METAL_BAD_PHYS; + mem = remoteproc_get_mem(rproc, NULL, lpa, lda, NULL, size); + if (mem) { + if (lpa != METAL_BAD_PHYS) + lda = remoteproc_patoda(mem, lpa); + else if (lda != METAL_BAD_PHYS) + lpa = remoteproc_datopa(mem, lda); + if (io) + *io = mem->io; + va = metal_io_phys_to_virt(mem->io, lpa); + } else if (rproc->ops->mmap) { + va = rproc->ops->mmap(rproc, &lpa, &lda, size, attribute, io); + } + + if (pa) + *pa = lpa; + if (da) + *da = lda; + return va; +} + +int remoteproc_load(struct remoteproc *rproc, const char *path, + void *store, struct image_store_ops *store_ops, + void **img_info) +{ + int ret; + struct loader_ops *loader; + const void *img_data; + void *limg_info = NULL; + size_t offset, noffset; + size_t len, nlen; + int last_load_state; + metal_phys_addr_t da, rsc_da; + int rsc_len; + size_t rsc_size; + void *rsc_table = NULL; + struct metal_io_region *io = NULL; + + if (!rproc) + return -RPROC_ENODEV; + + metal_mutex_acquire(&rproc->lock); + metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__); + /* If remoteproc is not in ready state, cannot load executable */ + if (rproc->state != RPROC_READY && rproc->state != RPROC_CONFIGURED) { + metal_log(METAL_LOG_ERROR, + "load failure: invalid rproc state %d.\r\n", + rproc->state); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + if (!store_ops) { + metal_log(METAL_LOG_ERROR, + "load failure: loader ops is not set.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + /* Open exectuable to get ready to parse */ + metal_log(METAL_LOG_DEBUG, "%s: open exectuable image\r\n", __func__); + ret = store_ops->open(store, path, &img_data); + if (ret <= 0) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to open firmware %d.\n", + ret); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + len = ret; + metal_assert(img_data != NULL); + + /* Check executable format to select a parser */ + loader = rproc->loader; + if (!loader) { + metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__); + loader = remoteproc_check_fw_format(img_data, len); + if (!loader) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to get store ops.\n"); + ret = -RPROC_EINVAL; + goto error1; + } + rproc->loader = loader; + } + + /* Load exectuable headers */ + metal_log(METAL_LOG_DEBUG, "%s: loading headers\r\n", __func__); + offset = 0; + last_load_state = RPROC_LOADER_NOT_READY; + while(1) { + ret = loader->load_header(img_data, offset, len, + &limg_info, last_load_state, + &noffset, &nlen); + last_load_state = (unsigned int)ret; + metal_log(METAL_LOG_DEBUG, + "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, noffset, nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load header failed 0x%lx,%d.\r\n", + offset, len); + + goto error2; + } else if ((ret & RPROC_LOADER_READY_TO_LOAD) != 0) { + if (nlen == 0) + break; + else if ((noffset > (offset + len)) && + (store_ops->features & SUPPORT_SEEK) == 0) { + /* Required data is not continued, however + * seek is not supported, stop to load + * headers such as ELF section headers which + * is usually located to the end of image. + * Continue to load binary data to target + * memory. + */ + break; } - } else { - status = RPROC_ERR_CPU_INIT; } + /* Continue to load headers image data */ + img_data = NULL; + ret = store_ops->load(store, noffset, nlen, + &img_data, + RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < (int)nlen) { + metal_log(METAL_LOG_ERROR, + "load image data failed 0x%x,%d\r\n", + noffset, nlen); + goto error2; + } + offset = noffset; + len = nlen; + } + ret = elf_locate_rsc_table(limg_info, &rsc_da, &offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + /* parse resource table */ + rsc_len = (int)rsc_size; + rsc_table = remoteproc_get_rsc_table(rproc, store, store_ops, + offset, rsc_len); } else { - status = RPROC_ERR_NO_MEM; + rsc_len = ret; } - if (!status) { - rproc->role = RPROC_MASTER; + /* load executable data */ + metal_log(METAL_LOG_DEBUG, "%s: load executable data\r\n", __func__); + offset = 0; + len = 0; + ret = -EINVAL; + while(1) { + unsigned char padding; + size_t nmemsize; + metal_phys_addr_t pa; + + da = RPROC_LOAD_ANYADDR; + nlen = 0; + nmemsize = 0; + noffset = 0; + ret = loader->load_data(rproc, img_data, offset, len, + &limg_info, last_load_state, &da, + &noffset, &nlen, &padding, &nmemsize); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load data failed,0x%lx,%d\r\n", + noffset, nlen); + goto error3; + } + metal_log(METAL_LOG_DEBUG, + "load data: da 0x%lx, offset 0x%lx, len = 0x%lx, memsize = 0x%lx, state 0x%x\r\n", + da, noffset, nlen, nmemsize, ret); + last_load_state = ret; + if (da != RPROC_LOAD_ANYADDR) { + /* Data is supposed to be loaded to target memory */ + img_data = NULL; + /* get the I/O region from remoteproc */ + pa = METAL_BAD_PHYS; + (void)remoteproc_mmap(rproc, &pa, &da, nmemsize, 0, &io); + if (pa == METAL_BAD_PHYS || io == NULL) { + metal_log(METAL_LOG_ERROR, + "load failed, no mapping for 0x%llx.\r\n", + da); + ret = -RPROC_EINVAL; + goto error3; + } + if (nlen > 0) { + ret = store_ops->load(store, noffset, nlen, + &img_data, pa, io, 1); + if (ret != (int)nlen) { + metal_log(METAL_LOG_ERROR, + "load data failed 0x%lx, 0x%lx, 0x%x\r\n", + pa, noffset, nlen); + ret = -RPROC_EINVAL; + goto error3; + } + } + if (nmemsize > nlen) { + size_t tmpoffset; - /* Get resource table from firmware */ - rsc_table = - remoteproc_loader_retrieve_resource_section(rproc->loader, - &rsc_size); - if (rsc_table) { - /* Parse resource table */ - status = handle_rsc_table(rproc, rsc_table, rsc_size); + tmpoffset = metal_io_phys_to_offset(io, + pa + nlen); + metal_io_block_set(io, tmpoffset, + padding, (nmemsize - nlen)); + } + } else if (nlen != 0) { + ret = store_ops->load(store, noffset, nlen, + &img_data, + RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < (int)nlen) { + if ((last_load_state & + RPROC_LOADER_POST_DATA_LOAD) != 0) { + metal_log(METAL_LOG_WARNING, + "not all the headers are loaded\r\n"); + break; + } + metal_log(METAL_LOG_ERROR, + "post-load image data failed 0x%x,%d\r\n", + noffset, nlen); + goto error3; + } + offset = noffset; + len = nlen; } else { - status = RPROC_ERR_NO_RSC_TABLE; + /* (last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0 */ + break; } } - /* Cleanup in case of error */ - if (status != RPROC_SUCCESS) { - (void)remoteproc_deinit(rproc); - return status; + if (rsc_len < 0) { + ret = elf_locate_rsc_table(limg_info, &rsc_da, + &offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + /* parse resource table */ + rsc_len = (int)rsc_size; + rsc_table = remoteproc_get_rsc_table(rproc, store, + store_ops, + offset, + rsc_len); + } } - rproc->channel_created = channel_created; - rproc->channel_destroyed = channel_destroyed; - rproc->default_cb = default_cb; + /* Update resource table */ + if (rsc_len && rsc_da != METAL_BAD_PHYS) { + void *rsc_table_cp = rsc_table; - *rproc_handle = rproc; + metal_log(METAL_LOG_DEBUG, + "%s, update resource table\r\n", __func__); + rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da, + rsc_len, 0, &io); + if (rsc_table) { + size_t rsc_io_offset; + + /* Update resource table */ + rsc_io_offset = metal_io_virt_to_offset(io, rsc_table); + ret = metal_io_block_write(io, rsc_io_offset, + rsc_table_cp, rsc_len); + if (ret != rsc_len) { + metal_log(METAL_LOG_WARNING, + "load: failed to update rsc\r\n"); + } + rproc->rsc_table = rsc_table; + rproc->rsc_len = rsc_len; + } else { + metal_log(METAL_LOG_WARNING, + "load: not able to update rsc table.\n"); + } + metal_free_memory(rsc_table_cp); + /* So that the rsc_table will not get released */ + rsc_table = NULL; + } - return status; + metal_log(METAL_LOG_DEBUG, "%s: successfully load firmware\r\n", + __func__); + /* get entry point from the firmware */ + rproc->bootaddr = loader->get_entry(limg_info); + rproc->state = RPROC_READY; + + metal_mutex_release(&rproc->lock); + if (img_info) + *img_info = limg_info; + else + loader->release(limg_info); + store_ops->close(store); + return 0; + +error3: + if (rsc_table) + metal_free_memory(rsc_table); +error2: + loader->release(limg_info); +error1: + store_ops->close(store); + metal_mutex_release(&rproc->lock); + return ret; } -/** - * remoteproc_deinit - * - * Uninitializes resources for remoteproc "master" configuration. - * - * @param rproc - pointer to remote proc instance - * - * @param returns - status of function execution - * - */ -int remoteproc_deinit(struct remote_proc *rproc) +int remoteproc_load_noblock(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, + metal_phys_addr_t *pa, struct metal_io_region **io, + size_t *noffset, size_t *nlen, + size_t *nmlen, unsigned char *padding) { + int ret; + struct loader_ops *loader; + void *limg_info = NULL; + int last_load_state; + metal_phys_addr_t da, rsc_da; + size_t rsc_size; + void *rsc_table = NULL, *lrsc_table = NULL; + + if (!rproc) + return -RPROC_ENODEV; + + metal_assert(pa != NULL); + metal_assert(io != NULL); + metal_assert(noffset != NULL); + metal_assert(nlen != NULL); + metal_assert(nmlen != NULL); + metal_assert(padding != NULL); + + metal_mutex_acquire(&rproc->lock); + metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__); + /* If remoteproc is not in ready state, cannot load executable */ + if (rproc->state != RPROC_READY) { + metal_log(METAL_LOG_ERROR, + "load failure: invalid rproc state %d.\r\n", + rproc->state); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } - if (rproc) { - if (rproc->loader) { - (void)remoteproc_loader_delete(rproc->loader); - rproc->loader = RPROC_NULL; + /* Check executable format to select a parser */ + loader = rproc->loader; + if (!loader) { + metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__); + if (img_data == NULL || offset != 0 || len == 0) { + metal_log(METAL_LOG_ERROR, + "load failure, invalid inputs, not able to identify image.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + loader = remoteproc_check_fw_format(img_data, len); + if (!loader) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to identify image.\n"); + ret = -RPROC_EINVAL; + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + rproc->loader = loader; + } + if (img_info == NULL || *img_info == NULL ) { + last_load_state = 0; + } else { + limg_info = *img_info; + last_load_state = loader->get_load_state(limg_info); + if (last_load_state < 0) { + metal_log(METAL_LOG_ERROR, + "load failure, not able get load state.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + } + da = RPROC_LOAD_ANYADDR; + *nlen = 0; + if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0 && + (last_load_state & RPROC_LOADER_LOAD_COMPLETE) == 0) { + /* Get the mandatory executable headers */ + ret = loader->load_header(img_data, offset, len, + &limg_info, last_load_state, + noffset, nlen); + last_load_state = (unsigned int)ret; + metal_log(METAL_LOG_DEBUG, + "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, *noffset, *nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load header failed 0x%lx,%d.\r\n", + offset, len); + + goto error1; + } + last_load_state = loader->get_load_state(limg_info); + if (*nlen != 0 && + (last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0) + goto out; + } + if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) != 0 || + (last_load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) { + /* Enough information to know which target memory for + * which data. + */ + ret = loader->load_data(rproc, img_data, offset, len, + &limg_info, last_load_state, &da, + noffset, nlen, padding, nmlen); + metal_log(METAL_LOG_DEBUG, + "%s, load data 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, *noffset, *nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load data failed,0x%lx,%d\r\n", + offset, len); + goto error1; + } + if (da != RPROC_LOAD_ANYADDR) { + /* get the I/O region from remoteproc */ + *pa = METAL_BAD_PHYS; + (void)remoteproc_mmap(rproc, pa, &da, *nmlen, 0, io); + if (*pa == METAL_BAD_PHYS || io == NULL) { + metal_log(METAL_LOG_ERROR, + "load failed, no mapping for 0x%llx.\r\n", + da); + ret = -RPROC_EINVAL; + goto error1; + } } - if (rproc->proc) { - hil_delete_proc(rproc->proc); - rproc->proc = RPROC_NULL; + if (*nlen != 0) + goto out; + else + last_load_state = loader->get_load_state(limg_info); + } + if ((last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0) { + /* Get resource table */ + size_t rsc_offset; + size_t rsc_io_offset; + + ret = elf_locate_rsc_table(limg_info, &rsc_da, + &rsc_offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + lrsc_table = metal_allocate_memory(rsc_size); + if (lrsc_table == NULL) { + ret = -RPROC_ENOMEM; + goto error1; + } + rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da, + rsc_size, 0, io); + if (*io == NULL) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to mmap rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + rsc_io_offset = metal_io_virt_to_offset(*io, rsc_table); + ret = metal_io_block_read(*io, rsc_io_offset, + lrsc_table, (int)rsc_size); + if (ret != (int)rsc_size) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to get rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + /* parse resource table */ + ret = remoteproc_parse_rsc_table(rproc, lrsc_table, + rsc_size); + if (ret == (int)rsc_size) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to parse rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + /* Update resource table */ + ret = metal_io_block_write(*io, rsc_io_offset, + lrsc_table, (int)rsc_size); + if (ret != (int)rsc_size) { + metal_log(METAL_LOG_WARNING, + "load exectuable, failed to update rsc\r\n"); + } + rproc->rsc_table = rsc_table; + rproc->rsc_len = (int)rsc_size; + metal_free_memory(lrsc_table); } - metal_free_memory(rproc); } +out: + if (img_info != NULL) + *img_info = limg_info; + else + loader->release(limg_info); + metal_mutex_release(&rproc->lock); + return 0; + +error1: + loader->release(limg_info); + metal_mutex_release(&rproc->lock); + return ret; +} - return RPROC_SUCCESS; +unsigned int remoteproc_allocate_id(struct remoteproc *rproc, + unsigned int start, + unsigned int end) +{ + unsigned int notifyid; + + if (start == RSC_NOTIFY_ID_ANY) + start = 0; + if (end == RSC_NOTIFY_ID_ANY) + end = METAL_BITS_PER_ULONG; + notifyid = metal_bitmap_next_set_bit(&rproc->bitmap, + start, end); + if (notifyid != end) + metal_bitmap_set_bit(&rproc->bitmap, notifyid); + return notifyid; } -/** - * remoteproc_boot - * - * This function loads the image on the remote processor and starts - * its execution from image load address. - * - * @param rproc - pointer to remoteproc instance to boot - * - * @param returns - status of function execution - */ -int remoteproc_boot(struct remote_proc *rproc) +static int remoteproc_virtio_notify(void *priv, uint32_t id) { + struct remoteproc *rproc = priv; - void *load_addr; - int status; - - if (!rproc) { - return RPROC_ERR_PARAM; - } - - /* Stop the remote CPU */ - hil_shutdown_cpu(rproc->proc); - - /* Load the firmware */ - status = remoteproc_loader_load_remote_firmware(rproc->loader); - if (status == RPROC_SUCCESS) { - load_addr = remoteproc_get_load_address(rproc->loader); - if (load_addr != RPROC_ERR_PTR) { - /* Start the remote cpu */ - status = hil_boot_cpu(rproc->proc, - (uintptr_t)load_addr); - if (status == RPROC_SUCCESS) { - /* Wait for remote side to come up. This delay is arbitrary and may - * need adjustment for different configuration of remote systems */ - metal_sleep_usec(RPROC_BOOT_DELAY); - - /* Initialize RPMSG "messaging" component */ - - /* It is a work-around to work with remote Linux context. - Since the upstream Linux rpmsg implementation always - assumes itself to be an rpmsg master, we initialize - the remote device as an rpmsg master for remote Linux - configuration only. */ -#if defined (OPENAMP_REMOTE_LINUX_ENABLE) - status = - rpmsg_init(rproc->proc, - &rproc->rdev, - rproc->channel_created, - rproc->channel_destroyed, - rproc->default_cb, RPMSG_MASTER); -#else - status = - rpmsg_init(rproc->proc, - &rproc->rdev, - rproc->channel_created, - rproc->channel_destroyed, - rproc->default_cb, RPMSG_REMOTE); -#endif - } - } else { - status = RPROC_ERR_LOADER; - } - } else { - status = RPROC_ERR_LOADER; + return rproc->ops->notify(rproc, id); +} + +struct virtio_device * +remoteproc_create_virtio(struct remoteproc *rproc, + int vdev_id, unsigned int role, + void (*rst_cb)(struct virtio_device *vdev)) +{ + char *rsc_table; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *vdev_rsc_io; + struct virtio_device *vdev; + struct remoteproc_virtio *rpvdev; + size_t vdev_rsc_offset; + unsigned int notifyid; + unsigned int num_vrings, i; + struct metal_list *node; + + metal_assert(rproc); + metal_mutex_acquire(&rproc->lock); + rsc_table = rproc->rsc_table; + vdev_rsc_io = rproc->rsc_io; + vdev_rsc_offset = find_rsc(rsc_table, RSC_VDEV, vdev_id); + if (!vdev_rsc_offset) { + metal_mutex_release(&rproc->lock); + return NULL; + } + vdev_rsc = (struct fw_rsc_vdev *)(rsc_table + vdev_rsc_offset); + notifyid = vdev_rsc->notifyid; + /* Check if the virtio device is already created */ + metal_list_for_each(&rproc->vdevs, node) { + rpvdev = metal_container_of(node, struct remoteproc_virtio, + node); + if (rpvdev->vdev.index == notifyid) + return &rpvdev->vdev; } + vdev = rproc_virtio_create_vdev(role, notifyid, + vdev_rsc, vdev_rsc_io, rproc, + remoteproc_virtio_notify, + rst_cb); + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_list_add_tail(&rproc->vdevs, &rpvdev->node); + num_vrings = vdev_rsc->num_of_vrings; + /* set the notification id for vrings */ + for (i = 0; i < num_vrings; i++) { + struct fw_rsc_vdev_vring *vring_rsc; + metal_phys_addr_t da; + unsigned int num_descs, align; + struct metal_io_region *io; + void *va; + size_t size; + int ret; + + vring_rsc = &vdev_rsc->vring[i]; + notifyid = vring_rsc->notifyid; + da = vring_rsc->da; + num_descs = vring_rsc->num; + align = vring_rsc->align; + size = vring_size(num_descs, align); + va = remoteproc_mmap(rproc, NULL, &da, size, 0, &io); + if (!va) + goto err1; + ret = rproc_virtio_init_vring(vdev, i, notifyid, + va, io, num_descs, align); + if (ret) + goto err1; + } + metal_mutex_release(&rproc->lock); + return vdev; - return status; +err1: + remoteproc_remove_virtio(rproc, vdev); + metal_mutex_release(&rproc->lock); + return NULL; } -/** - * remoteproc_shutdown - * - * This function shutdowns the remote execution context - * - * @param rproc - pointer to remote proc instance to shutdown - * - * @param returns - status of function execution - */ -int remoteproc_shutdown(struct remote_proc *rproc) +void remoteproc_remove_virtio(struct remoteproc *rproc, + struct virtio_device *vdev) { + struct remoteproc_virtio *rpvdev; - if (rproc) { - if (rproc->proc) { - hil_shutdown_cpu(rproc->proc); - } - if (rproc->rdev) { - rpmsg_deinit(rproc->rdev); - rproc->rdev = RPROC_NULL; - } - } + (void)rproc; + metal_assert(vdev); + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_list_del(&rpvdev->node); + rproc_virtio_remove_vdev(&rpvdev->vdev); +} - return RPROC_SUCCESS; +int remoteproc_get_notification(struct remoteproc *rproc, uint32_t notifyid) +{ + struct remoteproc_virtio *rpvdev; + struct metal_list *node; + int ret; + + metal_list_for_each(&rproc->vdevs, node) { + rpvdev = metal_container_of(node, struct remoteproc_virtio, + node); + ret = rproc_virtio_notified(&rpvdev->vdev, notifyid); + if (ret) + return ret; + } + return 0; } diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc_loader.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc_loader.c deleted file mode 100644 index f88dda387827ec..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc_loader.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include - -/** - * remoteproc_loader_init - * - * Initializes the remoteproc loader. - * - * @param type - loader type - * - * @return - remoteproc_loader - */ -struct remoteproc_loader *remoteproc_loader_init(enum loader_type type) -{ - - struct remoteproc_loader *loader; - - /* Check for valid loader type. */ - if (type >= LAST_LOADER) { - return RPROC_NULL; - } - - /* Allocate a loader handle. */ - loader = metal_allocate_memory(sizeof(struct remoteproc_loader)); - - if (!loader) { - return RPROC_NULL; - } - - /* Clear loader handle. */ - memset(loader, 0, sizeof(struct remoteproc_loader)); - - /* Save loader type. */ - loader->type = type; - - switch (type) { - - case ELF_LOADER: - elf_loader_init(loader); - break; - - default: - /* Loader not supported. */ - metal_free_memory(loader); - loader = RPROC_NULL; - break; - } - - return loader; -} - -/** - * remoteproc_loader_delete - * - * Deletes the remoteproc loader. - * - * @param loader - pointer to remoteproc loader - * - * @return - 0 if success, error otherwise - */ -int remoteproc_loader_delete(struct remoteproc_loader *loader) -{ - - int status = 0; - - if (!loader) { - return RPROC_ERR_PARAM; - } - - /* Check if a firmware is attached. */ - if (loader->remote_firmware) { - - /* Detach firmware first. */ - status = loader->detach_firmware(loader); - } - - /* Recover the allocated memory. */ - metal_free_memory(loader); - - return status; -} - -/** - * remoteproc_loader_attach_firmware - * - * Attaches an ELF firmware to the loader - * - * @param loader - pointer to remoteproc loader - * @param firmware - pointer to the firmware start location - * - * @return - 0 if success, error otherwise - */ -int remoteproc_loader_attach_firmware(struct remoteproc_loader *loader, - void *firmware_image) -{ - - int status = RPROC_SUCCESS; - - if (!loader || !firmware_image) { - return RPROC_ERR_PARAM; - } - - if (loader->attach_firmware) { - - /* Check if a firmware is already attached. */ - if (loader->remote_firmware) { - - /* Detach firmware first. */ - status = loader->detach_firmware(loader); - } - - /* Attach firmware. */ - if (!status) { - status = - loader->attach_firmware(loader, firmware_image); - - /* Save firmware address. */ - if (!status) { - loader->remote_firmware = firmware_image; - } - } - } else { - status = RPROC_ERR_LOADER; - } - - return status; -} - -/** - * remoteproc_loader_retrieve_entry_point - * - * Provides entry point address. - * - * @param loader - pointer to remoteproc loader - * - * @return - entrypoint - */ -void *remoteproc_loader_retrieve_entry_point(struct remoteproc_loader *loader) -{ - - if (!loader) { - return RPROC_NULL; - } - - if (loader->retrieve_entry) { - return loader->retrieve_entry(loader); - } else { - return RPROC_NULL; - } -} - -/** - * remoteproc_loader_retrieve_resource_section - * - * Provides resource section address. - * - * @param loader - pointer to remoteproc loader - * @param size - pointer to hold size of resource section - * - * @return - pointer to resource section - */ -void *remoteproc_loader_retrieve_resource_section(struct remoteproc_loader - *loader, unsigned int *size) -{ - - if (!loader) { - return RPROC_NULL; - } - - if (loader->retrieve_rsc) { - return loader->retrieve_rsc(loader, size); - } else { - return RPROC_NULL; - } -} - -/** - * remoteproc_loader_load_remote_firmware - * - * Loads the firmware in memory - * - * @param loader - pointer to remoteproc loader - * - * @return - 0 if success, error otherwise - */ -int remoteproc_loader_load_remote_firmware(struct remoteproc_loader *loader) -{ - - if (!loader) { - return RPROC_ERR_PARAM; - } - - if (loader->load_firmware) { - return loader->load_firmware(loader); - } else { - return RPROC_ERR_LOADER; - } -} - -/** - * remoteproc_get_load_address - * - * Provides firmware load address. - * - * @param loader - pointer to remoteproc loader - * - * @return - load address pointer - */ -void *remoteproc_get_load_address(struct remoteproc_loader *loader) -{ - - if (!loader) { - return RPROC_ERR_PTR; - } - - if (loader->retrieve_load_addr) { - return loader->retrieve_load_addr(loader); - } else { - return RPROC_ERR_PTR; - } -} diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc_virtio.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc_virtio.c new file mode 100644 index 00000000000000..0059718dc1c968 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/remoteproc_virtio.c @@ -0,0 +1,330 @@ +/* + * Remoteproc Virtio Framework Implementation + * + * Copyright(c) 2018 Xilinx Ltd. + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name Texas Instruments 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 + * OWNER 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. + */ + +#include +#include +#include +#include +#include + +static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) +{ + struct remoteproc_virtio *rpvdev; + struct virtio_vring_info *vring_info; + struct virtio_device *vdev; + unsigned int vq_id = vq->vq_queue_index; + + vdev = vq->vq_dev; + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_assert(vq_id <= vdev->vrings_num); + vring_info = &vdev->vrings_info[vq_id]; + rpvdev->notify(rpvdev->priv, vring_info->notifyid); +} + +static unsigned char rproc_virtio_get_status(struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + char status; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + status = metal_io_read8(io, + metal_io_virt_to_offset(io, &vdev_rsc->status)); + return status; +} + +#ifndef VIRTIO_SLAVE_ONLY +static void rproc_virtio_set_status(struct virtio_device *vdev, + unsigned char status) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + metal_io_write8(io, + metal_io_virt_to_offset(io, &vdev_rsc->status), + status); + rpvdev->notify(rpvdev->priv, vdev->index); +} +#endif + +static uint32_t rproc_virtio_get_features(struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + uint32_t features; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + /* TODO: shall we get features based on the role ? */ + features = metal_io_read32(io, + metal_io_virt_to_offset(io, &vdev_rsc->dfeatures)); + + return features; +} + +#ifndef VIRTIO_SLAVE_ONLY +static void rproc_virtio_set_features(struct virtio_device *vdev, + uint32_t features) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + /* TODO: shall we set features based on the role ? */ + metal_io_write32(io, + metal_io_virt_to_offset(io, &vdev_rsc->dfeatures), + features); + rpvdev->notify(rpvdev->priv, vdev->index); +} +#endif + +static uint32_t rproc_virtio_negotiate_features(struct virtio_device *vdev, + uint32_t features) +{ + (void)vdev; + (void)features; + + return 0; +} + +static void rproc_virtio_read_config(struct virtio_device *vdev, + uint32_t offset, void *dst, int length) +{ + (void)vdev; + (void)offset; + (void)dst; + (void)length; +} + +#ifndef VIRTIO_SLAVE_ONLY +static void rproc_virtio_write_config(struct virtio_device *vdev, + uint32_t offset, void *src, int length) +{ + (void)vdev; + (void)offset; + (void)src; + (void)length; +} + +static void rproc_virtio_reset_device(struct virtio_device *vdev) +{ + if (vdev->role == VIRTIO_DEV_MASTER) + rproc_virtio_set_status(vdev, + VIRTIO_CONFIG_STATUS_NEEDS_RESET); +} +#endif + +const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { + .get_status = rproc_virtio_get_status, + .get_features = rproc_virtio_get_features, + .read_config = rproc_virtio_read_config, + .notify = rproc_virtio_virtqueue_notify, + .negotiate_features = rproc_virtio_negotiate_features, +#ifndef VIRTIO_SLAVE_ONLY + /* + * We suppose here that the vdev is in a shared memory so that can + * be access only by one core: the master. In this case salve core has + * only read access right. + */ + .set_status = rproc_virtio_set_status, + .set_features = rproc_virtio_set_features, + .write_config = rproc_virtio_write_config, + .reset_device = rproc_virtio_reset_device, +#endif +}; + +struct virtio_device * +rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, + void *rsc, struct metal_io_region *rsc_io, + void *priv, + rpvdev_notify_func notify, + virtio_dev_reset_cb rst_cb) +{ + struct remoteproc_virtio *rpvdev; + struct virtio_vring_info *vrings_info; + struct fw_rsc_vdev *vdev_rsc = rsc; + struct virtio_device *vdev; + unsigned int num_vrings = vdev_rsc->num_of_vrings; + unsigned int i; + + rpvdev = metal_allocate_memory(sizeof(*rpvdev)); + if (!rpvdev) + return NULL; + vrings_info = metal_allocate_memory(sizeof(*vrings_info) * num_vrings); + if (!vrings_info) + goto err0; + memset(rpvdev, 0, sizeof(*rpvdev)); + memset(vrings_info, 0, sizeof(*vrings_info)); + vdev = &rpvdev->vdev; + + for (i = 0; i < num_vrings; i++) { + struct virtqueue *vq; + struct fw_rsc_vdev_vring *vring_rsc; + unsigned int num_extra_desc = 0; + + vring_rsc = &vdev_rsc->vring[i]; + if (role == VIRTIO_DEV_MASTER) { + num_extra_desc = vring_rsc->num; + } + vq = virtqueue_allocate(num_extra_desc); + if (!vq) + goto err1; + vrings_info[i].vq = vq; + } + + /* FIXME commended as seems not nedded, already stored in vdev */ + //rpvdev->notifyid = notifyid; + rpvdev->notify = notify; + rpvdev->priv = priv; + vdev->vrings_info = vrings_info; + /* Assuming the shared memory has been mapped and registered if + * necessary + */ + rpvdev->vdev_rsc = vdev_rsc; + rpvdev->vdev_rsc_io = rsc_io; + + vdev->index = notifyid; + vdev->role = role; + vdev->reset_cb = rst_cb; + vdev->vrings_num = num_vrings; + vdev->func = &remoteproc_virtio_dispatch_funcs; + /* TODO: Shall we set features here ? */ + + return &rpvdev->vdev; + +err1: + for (i = 0; i < num_vrings; i++) { + if (vrings_info[i].vq) + metal_free_memory(vrings_info[i].vq); + } + metal_free_memory(vrings_info); +err0: + metal_free_memory(rpvdev); + return NULL; +} + +void rproc_virtio_remove_vdev(struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + unsigned int i; + + if (!vdev) + return; + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + for (i = 0; i < vdev->vrings_num; i++) { + struct virtqueue *vq; + + vq = vdev->vrings_info[i].vq; + if (vq) + metal_free_memory(vq); + } + metal_free_memory(vdev->vrings_info); + metal_free_memory(rpvdev); +} + +int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, + unsigned int notifyid, void *va, + struct metal_io_region *io, + unsigned int num_descs, unsigned int align) +{ + struct virtio_vring_info *vring_info; + unsigned int num_vrings; + + num_vrings = vdev->vrings_num; + if (index >= num_vrings) + return -RPROC_EINVAL; + vring_info = &vdev->vrings_info[index]; + vring_info->io = io; + vring_info->notifyid = notifyid; + vring_info->info.vaddr = va; + vring_info->info.num_descs = num_descs; + vring_info->info.align = align; + + return 0; +} + +int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid) +{ + unsigned int num_vrings, i; + struct virtio_vring_info *vring_info; + struct virtqueue *vq; + + if (!vdev) + return -EINVAL; + /* We do nothing for vdev notification in this implementation */ + if (vdev->index == notifyid) + return 0; + num_vrings = vdev->vrings_num; + for (i = 0; i < num_vrings; i++) { + vring_info = &vdev->vrings_info[i]; + if (vring_info->notifyid == notifyid || + notifyid == RSC_NOTIFY_ID_ANY) { + vq = vring_info->vq; + virtqueue_notification(vq); + } + } + return 0; +} + +void rproc_virtio_wait_remote_ready(struct virtio_device *vdev) +{ + uint8_t status; + + /* + * No status available for slave. As Master has not to wait + * slave action, we can return. Behavior should be updated + * in future if a slave status is added. + */ + if (vdev->role == VIRTIO_DEV_MASTER) + return; + + while (1) { + status = rproc_virtio_get_status(vdev); + if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) + return; + } +} diff --git a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/rsc_table_parser.c b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/rsc_table_parser.c index e9cf454452af1a..37c6478011f0a8 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/rsc_table_parser.c +++ b/ext/lib/ipc/open-amp/open-amp/lib/remoteproc/rsc_table_parser.c @@ -1,88 +1,80 @@ /* * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2018, Xilinx Inc. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#include #include +#include + +static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc); /* Resources handler */ rsc_handler rsc_handler_table[] = { - handle_carve_out_rsc, - handle_dev_mem_rsc, - handle_trace_rsc, - handle_vdev_rsc, - handle_rproc_mem_rsc, - handle_fw_chksum_rsc, - handle_mmu_rsc + handle_carve_out_rsc, /**< carved out resource */ + handle_dummy_rsc, /**< IOMMU dev mem resource */ + handle_trace_rsc, /**< trace buffer resource */ + handle_vdev_rsc, /**< virtio resource */ + handle_dummy_rsc, /**< rproc shared memory resource */ + handle_dummy_rsc, /**< firmware checksum resource */ }; -/** - * handle_rsc_table - * - * This function parses resource table. - * - * @param rproc - pointer to remote remote_proc - * @param rsc_table - resource table to parse - * @param size - size of rsc table - * - * @returns - execution status - * - */ -int handle_rsc_table(struct remote_proc *rproc, - struct resource_table *rsc_table, int size) +int handle_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, int size, + struct metal_io_region *io) { - - unsigned char *rsc_start; - unsigned int *rsc_offset; + char *rsc_start; unsigned int rsc_type; - unsigned int idx; + unsigned int idx, offset; int status = 0; /* Validate rsc table header fields */ /* Minimum rsc table size */ if (sizeof(struct resource_table) > (unsigned int)size) { - return (RPROC_ERR_RSC_TAB_TRUNC); + return -RPROC_ERR_RSC_TAB_TRUNC; } /* Supported version */ if (rsc_table->ver != RSC_TAB_SUPPORTED_VERSION) { - return (RPROC_ERR_RSC_TAB_VER); + return -RPROC_ERR_RSC_TAB_VER; } /* Offset array */ - if (sizeof(struct resource_table) - + rsc_table->num * sizeof(rsc_table->offset[0]) > (unsigned int)size) { - return (RPROC_ERR_RSC_TAB_TRUNC); + offset = sizeof(struct resource_table) + + rsc_table->num * sizeof(rsc_table->offset[0]); + + if (offset > (unsigned int)size) { + return -RPROC_ERR_RSC_TAB_TRUNC; } /* Reserved fields - must be zero */ if ((rsc_table->reserved[0] != 0 || rsc_table->reserved[1]) != 0) { - return RPROC_ERR_RSC_TAB_RSVD; + return -RPROC_ERR_RSC_TAB_RSVD; } - rsc_start = (unsigned char *)rsc_table; - - /* FIX ME: need a clearer solution to set the I/O region for - * resource table */ - status = hil_set_rsc(rproc->proc, NULL, NULL, - (metal_phys_addr_t)((uintptr_t)rsc_table), size); - if (status) - return status; - /* Loop through the offset array and parse each resource entry */ for (idx = 0; idx < rsc_table->num; idx++) { - rsc_offset = - (unsigned int *)(rsc_start + rsc_table->offset[idx]); - rsc_type = *rsc_offset; - status = - rsc_handler_table[rsc_type] (rproc, (void *)rsc_offset); - if (status != RPROC_SUCCESS) { - break; + rsc_start = (char *)rsc_table; + rsc_start += rsc_table->offset[idx]; + if (io && + metal_io_virt_to_offset(io, rsc_start) == METAL_BAD_OFFSET) + return -RPROC_ERR_RSC_TAB_TRUNC; + rsc_type = *((uint32_t *)rsc_start); + if (rsc_type < RSC_LAST) + status = rsc_handler_table[rsc_type](rproc, + rsc_start); + else if (rsc_type >= RSC_VENDOR_START && + rsc_type <= RSC_VENDOR_END) + status = handle_vendor_rsc(rproc, rsc_start); + if (status == -RPROC_ERR_RSC_TAB_NS) { + status = 0; + continue; } + else if (status) + break; } return status; @@ -93,174 +85,139 @@ int handle_rsc_table(struct remote_proc *rproc, * * Carveout resource handler. * - * @param rproc - pointer to remote remote_proc + * @param rproc - pointer to remote remoteproc * @param rsc - pointer to carveout resource * - * @returns - execution status + * @returns - 0 for success, or negative value for failure * */ -int handle_carve_out_rsc(struct remote_proc *rproc, void *rsc) +int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc) { struct fw_rsc_carveout *carve_rsc = (struct fw_rsc_carveout *)rsc; + metal_phys_addr_t da; + metal_phys_addr_t pa; + size_t size; + unsigned int attribute; /* Validate resource fields */ if (!carve_rsc) { - return RPROC_ERR_RSC_TAB_NP; + return -RPROC_ERR_RSC_TAB_NP; } if (carve_rsc->reserved) { - return RPROC_ERR_RSC_TAB_RSVD; + return -RPROC_ERR_RSC_TAB_RSVD; } - - if (rproc->role == RPROC_MASTER) { - /* FIX ME: TO DO */ - return RPROC_SUCCESS; - } - - return RPROC_SUCCESS; + pa = carve_rsc->pa; + da = carve_rsc->da; + size = carve_rsc->len; + attribute = carve_rsc->flags; + if (remoteproc_mmap(rproc, &pa, &da, size, attribute, NULL)) + return 0; + else + return -RPROC_EINVAL; } -/** - * handle_trace_rsc - * - * Trace resource handler. - * - * @param rproc - pointer to remote remote_proc - * @param rsc - pointer to trace resource - * - * @returns - execution status - * - */ -int handle_trace_rsc(struct remote_proc *rproc, void *rsc) +int handle_vendor_rsc(struct remoteproc *rproc, void *rsc) { - (void)rproc; - (void)rsc; + if (rproc && rproc->ops->handle_rsc) { + struct fw_rsc_vendor *vend_rsc = rsc; + size_t len = vend_rsc->len; - return RPROC_ERR_RSC_TAB_NS; -} - -/** - * handle_dev_mem_rsc - * - * Device memory resource handler. - * - * @param rproc - pointer to remote remote_proc - * @param rsc - pointer to device memory resource - * - * @returns - execution status - * - */ -int handle_dev_mem_rsc(struct remote_proc *rproc, void *rsc) -{ - (void)rproc; - (void)rsc; - - return RPROC_ERR_RSC_TAB_NS; + return rproc->ops->handle_rsc(rproc, rsc, len); + } + return -RPROC_ERR_RSC_TAB_NS; } -/** - * handle_vdev_rsc - * - * Virtio device resource handler - * - * @param rproc - pointer to remote remote_proc - * @param rsc - pointer to virtio device resource - * - * @returns - execution status - * - */ -int handle_vdev_rsc(struct remote_proc *rproc, void *rsc) +int handle_vdev_rsc(struct remoteproc *rproc, void *rsc) { - struct fw_rsc_vdev *vdev_rsc = (struct fw_rsc_vdev *)rsc; - struct proc_vdev *vdev; - - if (!vdev_rsc) { - return RPROC_ERR_RSC_TAB_NP; - } - - /* Maximum supported vrings per Virtio device */ - if (vdev_rsc->num_of_vrings > RSC_TAB_MAX_VRINGS) { - return RPROC_ERR_RSC_TAB_VDEV_NRINGS; + unsigned int notifyid, i, num_vrings; + + /* only assign notification IDs but do not initialize vdev */ + notifyid = vdev_rsc->notifyid; + if (notifyid == RSC_NOTIFY_ID_ANY) { + notifyid = remoteproc_allocate_id(rproc, + notifyid, notifyid + 1); + vdev_rsc->notifyid = notifyid; } - /* Reserved fields - must be zero */ - if (vdev_rsc->reserved[0] || vdev_rsc->reserved[1]) { - return RPROC_ERR_RSC_TAB_RSVD; + num_vrings = vdev_rsc->num_of_vrings; + for (i = 0; i < num_vrings; i++) { + struct fw_rsc_vdev_vring *vring_rsc; + + vring_rsc = &vdev_rsc->vring[i]; + notifyid = vring_rsc->notifyid; + if (notifyid == RSC_NOTIFY_ID_ANY) { + notifyid = remoteproc_allocate_id(rproc, + notifyid, + notifyid + 1); + vdev_rsc->notifyid = notifyid; + } } - /* Get the Virtio device from HIL proc */ - vdev = hil_get_vdev_info(rproc->proc); - - /* Initialize HIL Virtio device resources */ - vdev->num_vrings = vdev_rsc->num_of_vrings; - vdev->dfeatures = vdev_rsc->dfeatures; - vdev->gfeatures = vdev_rsc->gfeatures; - vdev->vdev_info = vdev_rsc; - - return RPROC_SUCCESS; + return 0; } /** - * handle_rproc_mem_rsc + * handle_trace_rsc * - * This function parses rproc_mem resource. - * This is the resource for the remote processor - * to tell the host the memory can be used as - * shared memory. + * trace resource handler. * - * @param rproc - pointer to remote remote_proc - * @param rsc - pointer to mmu resource + * @param rproc - pointer to remote remoteproc + * @param rsc - pointer to trace resource * - * @returns - execution status + * @returns - no service error * */ -int handle_rproc_mem_rsc(struct remote_proc *rproc, void *rsc) +int handle_trace_rsc(struct remoteproc *rproc, void *rsc) { + struct fw_rsc_trace *vdev_rsc = (struct fw_rsc_trace *)rsc; (void)rproc; - (void)rsc; - /* TODO: the firmware side should handle this resource properly - * when it is the master or when it is the remote. */ - return RPROC_SUCCESS; + if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0) + return 0; + /* FIXME: master should allocated a memory used by slave */ + + return -RPROC_ERR_RSC_TAB_NS; } -/* - * handle_fw_chksum_rsc +/** + * handle_dummy_rsc * - * This function parses firmware checksum resource. + * dummy resource handler. * - * @param rproc - pointer to remote remote_proc - * @param rsc - pointer to mmu resource + * @param rproc - pointer to remote remoteproc + * @param rsc - pointer to trace resource * - * @returns - execution status + * @returns - no service error * */ -int handle_fw_chksum_rsc(struct remote_proc *rproc, void *rsc) +static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc) { (void)rproc; (void)rsc; - /* TODO: the firmware side should handle this resource properly - * when it is the master or when it is the remote. */ - return RPROC_SUCCESS; + return -RPROC_ERR_RSC_TAB_NS; } -/** - * handle_mmu_rsc - * - * This function parses mmu resource , requested by the peripheral. - * - * @param rproc - pointer to remote remote_proc - * @param rsc - pointer to mmu resource - * - * @returns - execution status - * - */ -int handle_mmu_rsc(struct remote_proc *rproc, void *rsc) +size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index) { - (void)rproc; - (void)rsc; + struct resource_table *r_table = rsc_table; + unsigned int i, rsc_index; + unsigned int lrsc_type; + char *rsc_start; - return RPROC_ERR_RSC_TAB_NS; + metal_assert(r_table); + /* Loop through the offset array and parse each resource entry */ + rsc_index = 0; + for (i = 0; i < r_table->num; i++) { + rsc_start = (char *)r_table; + rsc_start += r_table->offset[i]; + lrsc_type = *((uint32_t *)rsc_start); + if (lrsc_type == rsc_type) { + if (rsc_index++ == index) + return r_table->offset[i]; + } + } + return 0; } diff --git a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/CMakeLists.txt b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/CMakeLists.txt index 64e59614ce37e6..e2bd8d8051fb1d 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/CMakeLists.txt +++ b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/CMakeLists.txt @@ -1,3 +1,2 @@ -collect (PROJECT_LIB_SOURCES remote_device.c) collect (PROJECT_LIB_SOURCES rpmsg.c) -collect (PROJECT_LIB_SOURCES rpmsg_core.c) +collect (PROJECT_LIB_SOURCES rpmsg_virtio.c) diff --git a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/remote_device.c b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/remote_device.c deleted file mode 100644 index fa30afa4162499..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/remote_device.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * Copyright (c) 2015 Xilinx, Inc. All rights reserved. - * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * remote_device.c - * - * COMPONENT - * - * OpenAMP Stack - * - * DESCRIPTION - * - * This file provides services to manage the remote devices.It also implements - * the interface defined by the virtio and provides few other utility functions. - * - * - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -/* Macro to initialize vring HW info */ -#define INIT_VRING_ALLOC_INFO(ring_info,vring_hw) \ - (ring_info).vaddr = (vring_hw).vaddr; \ - (ring_info).align = (vring_hw).align; \ - (ring_info).num_descs = (vring_hw).num_descs - -/* Local functions */ -static int rpmsg_rdev_init_channels(struct remote_device *rdev); - -/* Ops table for virtio device */ -virtio_dispatch rpmsg_rdev_config_ops = { - rpmsg_rdev_create_virtqueues, - rpmsg_rdev_get_status, - rpmsg_rdev_set_status, - rpmsg_rdev_get_feature, - rpmsg_rdev_set_feature, - rpmsg_rdev_negotiate_feature, - rpmsg_rdev_read_config, - rpmsg_rdev_write_config, - rpmsg_rdev_reset -}; - -/** - * rpmsg_memb_match - * - * This internal function checks if the contents in two memories matches byte - * by byte. This function is needed because memcmp() or strcmp() does not - * always work across different memories. - * - * @param ptr1 - pointer to memory - * @param ptr2 - pointer to memory - * @param n - number of bytes to compare - * - * @return 0 if the contents in the two memories matches, otherwise -1. - */ -static int rpmsg_memb_match(const void *ptr1, const void *ptr2, size_t n) -{ - size_t i; - const unsigned char *tmp1, *tmp2; - - tmp1 = ptr1; - tmp2 = ptr2; - for (i = 0; i < n; i++, tmp1++, tmp2++) { - if (*tmp1 != *tmp2) - return -1; - } - - return 0; -} - -/** - * rpmsg_rdev_init - * - * This function creates and initializes the remote device. The remote device - * encapsulates virtio device. - * - * @param proc - pointer to hil_proc - * @param rdev - pointer to newly created remote device - * @param role - role of the other device, Master or Remote - * @param channel_created - callback function for channel creation - * @param channel_destroyed - callback function for channel deletion - * @param default_cb - default callback for channel - * - * @return - status of function execution - * - */ -int rpmsg_rdev_init(struct hil_proc *proc, - struct remote_device **rdev, int role, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb) -{ - - struct remote_device *rdev_loc; - struct virtio_device *virt_dev; - struct proc_shm *shm; - int status; - - if (!proc) - return RPMSG_ERR_PARAM; - /* Initialize HIL data structures for given device */ - if (hil_init_proc(proc)) - return RPMSG_ERR_DEV_INIT; - - /* Create software representation of remote processor. */ - rdev_loc = (struct remote_device *)metal_allocate_memory(sizeof(struct remote_device)); - - if (!rdev_loc) { - return RPMSG_ERR_NO_MEM; - } - - memset(rdev_loc, 0x00, sizeof(struct remote_device)); - metal_mutex_init(&rdev_loc->lock); - - rdev_loc->proc = proc; - rdev_loc->role = role; - rdev_loc->channel_created = channel_created; - rdev_loc->channel_destroyed = channel_destroyed; - rdev_loc->default_cb = default_cb; - - /* Restrict the ept address - zero address can't be assigned */ - rdev_loc->bitmap[0] = 1; - - /* Initialize the virtio device */ - virt_dev = &rdev_loc->virt_dev; - virt_dev->device = proc; - virt_dev->func = &rpmsg_rdev_config_ops; - if (virt_dev->func->set_features != RPMSG_NULL) { - virt_dev->func->set_features(virt_dev, proc->vdev.dfeatures); - } - - if (rdev_loc->role == RPMSG_REMOTE) { - /* - * Since device is RPMSG Remote so we need to manage the - * shared buffers. Create shared memory pool to handle buffers. - */ - shm = hil_get_shm_info(proc); - rdev_loc->mem_pool = - sh_mem_create_pool(shm->start_addr, shm->size, - RPMSG_BUFFER_SIZE); - - if (!rdev_loc->mem_pool) { - return RPMSG_ERR_NO_MEM; - } - } - - if (!rpmsg_rdev_remote_ready(rdev_loc)) - return RPMSG_ERR_DEV_INIT; - - /* Initialize endpoints list */ - metal_list_init(&rdev_loc->rp_endpoints); - - /* Initialize channels for RPMSG Remote */ - status = rpmsg_rdev_init_channels(rdev_loc); - - if (status != RPMSG_SUCCESS) { - return status; - } - - *rdev = rdev_loc; - - return RPMSG_SUCCESS; -} - -/** - * rpmsg_rdev_deinit - * - * This function un-initializes the remote device. - * - * @param rdev - pointer to remote device to deinit. - * - * @return - none - * - */ -void rpmsg_rdev_deinit(struct remote_device *rdev) -{ - struct metal_list *node; - struct rpmsg_channel *rp_chnl; - struct rpmsg_endpoint *rp_ept; - - - while(!metal_list_is_empty(&rdev->rp_channels)) { - node = rdev->rp_channels.next; - rp_chnl = metal_container_of(node, struct rpmsg_channel, node); - - if (rdev->channel_destroyed) { - rdev->channel_destroyed(rp_chnl); - } - - if ((rdev->support_ns) && (rdev->role == RPMSG_MASTER)) { - rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY); - } - - /* Delete default endpoint for channel */ - if (rp_chnl->rp_ept) { - rpmsg_destroy_ept(rp_chnl->rp_ept); - } - - _rpmsg_delete_channel(rp_chnl); - } - - /* Delete name service endpoint */ - metal_mutex_acquire(&rdev->lock); - rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, RPMSG_NS_EPT_ADDR); - metal_mutex_release(&rdev->lock); - if (rp_ept) { - _destroy_endpoint(rdev, rp_ept); - } - - metal_mutex_acquire(&rdev->lock); - rdev->rvq = 0; - rdev->tvq = 0; - if (rdev->mem_pool) { - sh_mem_delete_pool(rdev->mem_pool); - rdev->mem_pool = 0; - } - metal_mutex_release(&rdev->lock); - hil_free_vqs(&rdev->virt_dev); - - metal_mutex_deinit(&rdev->lock); - - metal_free_memory(rdev); -} - -/** - * rpmsg_rdev_get_chnl_from_id - * - * This function returns channel node based on channel name. It must be called - * with mutex locked. - * - * @param stack - pointer to remote device - * @param rp_chnl_id - rpmsg channel name - * - * @return - rpmsg channel - * - */ -struct rpmsg_channel *rpmsg_rdev_get_chnl_from_id(struct remote_device *rdev, - char *rp_chnl_id) -{ - struct rpmsg_channel *rp_chnl; - struct metal_list *node; - - metal_list_for_each(&rdev->rp_channels, node) { - rp_chnl = metal_container_of(node, struct rpmsg_channel, node); - if (!rpmsg_memb_match(rp_chnl->name, rp_chnl_id, - sizeof(rp_chnl->name))) { - return rp_chnl; - } - } - - return RPMSG_NULL; -} - -/** - * rpmsg_rdev_get_endpoint_from_addr - * - * This function returns endpoint node based on src address. It must be called - * with mutex locked. - * - * @param rdev - pointer remote device control block - * @param addr - src address - * - * @return - rpmsg endpoint - * - */ -struct rpmsg_endpoint *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev, - unsigned long addr) -{ - struct rpmsg_endpoint *rp_ept; - struct metal_list *node; - - metal_list_for_each(&rdev->rp_endpoints, node) { - rp_ept = metal_container_of(node, - struct rpmsg_endpoint, node); - if (rp_ept->addr == addr) { - return rp_ept; - } - } - - return RPMSG_NULL; -} - -/* - * rpmsg_rdev_notify - * - * This function checks whether remote device is up or not. If it is up then - * notification is sent based on device role to start IPC. - * - * @param rdev - pointer to remote device - * - * @return - status of function execution - * - */ -int rpmsg_rdev_notify(struct remote_device *rdev) -{ - struct virtio_device *vdev = &rdev->virt_dev; - - hil_vdev_notify(vdev); - - return RPMSG_SUCCESS; -} - -/** - * rpmsg_rdev_init_channels - * - * This function is only applicable to RPMSG remote. It obtains channel IDs - * from the HIL and creates RPMSG channels corresponding to each ID. - * - * @param rdev - pointer to remote device - * - * @return - status of function execution - * - */ -int rpmsg_rdev_init_channels(struct remote_device *rdev) -{ - struct rpmsg_channel *rp_chnl; - struct proc_chnl *chnl_info; - int num_chnls, idx; - - metal_list_init(&rdev->rp_channels); - if (rdev->role == RPMSG_MASTER) { - - chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls); - for (idx = 0; idx < num_chnls; idx++) { - - rp_chnl = - _rpmsg_create_channel(rdev, chnl_info[idx].name, - 0x00, RPMSG_NS_EPT_ADDR); - if (!rp_chnl) { - return RPMSG_ERR_NO_MEM; - } - - rp_chnl->rp_ept = - rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev, - RPMSG_ADDR_ANY); - - if (!rp_chnl->rp_ept) { - return RPMSG_ERR_NO_MEM; - } - - rp_chnl->src = rp_chnl->rp_ept->addr; - } - } - - return RPMSG_SUCCESS; -} - -/** - * check if the remote is ready to start RPMsg communication - */ -int rpmsg_rdev_remote_ready(struct remote_device *rdev) -{ - struct virtio_device *vdev = &rdev->virt_dev; - uint8_t status; - if (rdev->role == RPMSG_MASTER) { - while (1) { - status = vdev->func->get_status(vdev); - /* Busy wait until the remote is ready */ - if (status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) { - rpmsg_rdev_set_status(vdev, 0); - hil_vdev_notify(vdev); - } else if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) { - return true; - } - metal_cpu_yield(); - } - } else { - return true; - } - /* Never come here */ - return false; -} - -/** - *------------------------------------------------------------------------ - * The rest of the file implements the virtio device interface as defined - * by the virtio.h file. - *------------------------------------------------------------------------ - */ -int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs, - const char *names[], vq_callback * callbacks[], - struct virtqueue *vqs_[]) -{ - struct remote_device *rdev; - struct vring_alloc_info ring_info; - struct virtqueue *vqs[RPMSG_MAX_VQ_PER_RDEV]; - struct proc_vring *vring_table; - void *buffer; - struct metal_sg sg; - int idx, num_vrings, status; - - (void)flags; - (void)vqs_; - - rdev = (struct remote_device *)dev; - - /* Get the vring HW info for the given virtio device */ - vring_table = hil_get_vring_info(&rdev->proc->vdev, &num_vrings); - - if (num_vrings > nvqs) { - return RPMSG_ERR_MAX_VQ; - } - - /* Create virtqueue for each vring. */ - for (idx = 0; idx < num_vrings; idx++) { - - INIT_VRING_ALLOC_INFO(ring_info, vring_table[idx]); - - if (rdev->role == RPMSG_REMOTE) { - metal_io_block_set(vring_table[idx].io, - metal_io_virt_to_offset(vring_table[idx].io, - ring_info.vaddr), - 0x00, - vring_size(vring_table[idx].num_descs, - vring_table[idx].align)); - } - - status = - virtqueue_create(dev, idx, (char *)names[idx], &ring_info, - callbacks[idx], hil_vring_notify, - rdev->proc->sh_buff.io, - &vqs[idx]); - - if (status != RPMSG_SUCCESS) { - return status; - } - } - - //FIXME - a better way to handle this , tx for master is rx for remote and vice versa. - if (rdev->role == RPMSG_MASTER) { - rdev->tvq = vqs[0]; - rdev->rvq = vqs[1]; - } else { - rdev->tvq = vqs[1]; - rdev->rvq = vqs[0]; - } - - if (rdev->role == RPMSG_REMOTE) { - sg.io = rdev->proc->sh_buff.io; - sg.len = RPMSG_BUFFER_SIZE; - for (idx = 0; ((idx < rdev->rvq->vq_nentries) - && ((unsigned)idx < rdev->mem_pool->total_buffs / 2)); - idx++) { - - /* Initialize TX virtqueue buffers for remote device */ - buffer = sh_mem_get_buffer(rdev->mem_pool); - - if (!buffer) { - return RPMSG_ERR_NO_BUFF; - } - - sg.virt = buffer; - - metal_io_block_set(sg.io, - metal_io_virt_to_offset(sg.io, buffer), - 0x00, - RPMSG_BUFFER_SIZE); - status = - virtqueue_add_buffer(rdev->rvq, &sg, 0, 1, - buffer); - - if (status != RPMSG_SUCCESS) { - return status; - } - } - } - - return RPMSG_SUCCESS; -} - -unsigned char rpmsg_rdev_get_status(struct virtio_device *dev) -{ - struct hil_proc *proc = dev->device; - struct proc_vdev *pvdev = &proc->vdev; - struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info; - - if (!vdev_rsc) - return -1; - - atomic_thread_fence(memory_order_seq_cst); - return vdev_rsc->status; -} - -void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status) -{ - struct hil_proc *proc = dev->device; - struct proc_vdev *pvdev = &proc->vdev; - struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info; - - if (!vdev_rsc) - return; - - vdev_rsc->status = status; - - atomic_thread_fence(memory_order_seq_cst); -} - -uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev) -{ - return dev->features; -} - -void rpmsg_rdev_set_feature(struct virtio_device *dev, uint32_t feature) -{ - dev->features |= feature; -} - -uint32_t rpmsg_rdev_negotiate_feature(struct virtio_device *dev, - uint32_t features) -{ - (void)dev; - (void)features; - - return 0; -} - -/* - * Read/write a variable amount from the device specific (ie, network) - * configuration region. This region is encoded in the same endian as - * the guest. - */ -void rpmsg_rdev_read_config(struct virtio_device *dev, uint32_t offset, - void *dst, int length) -{ - (void)dev; - (void)offset; - (void)dst; - (void)length; - - return; -} - -void rpmsg_rdev_write_config(struct virtio_device *dev, uint32_t offset, - void *src, int length) -{ - (void)dev; - (void)offset; - (void)src; - (void)length; - - return; -} - -void rpmsg_rdev_reset(struct virtio_device *dev) -{ - (void)dev; - - return; -} - diff --git a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg.c b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg.c index 0671cc76d89d68..9268889e07bdc0 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg.c +++ b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg.c @@ -2,106 +2,101 @@ * Copyright (c) 2014, Mentor Graphics Corporation * All rights reserved. * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (c) 2018 Linaro, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -/************************************************************************** - * FILE NAME - * - * rpmsg.c - * - * COMPONENT - * - * OpenAMP stack. - * - * DESCRIPTION - * - * Main file for the RPMSG driver. This file implements APIs as defined by - * RPMSG documentation(Linux docs) and also provides some utility functions. - * - * RPMSG driver represents each processor/core to which it communicates with - * remote_device control block. - * Each remote device(processor) defines its role in the communication i.e - * whether it is RPMSG Master or Remote. If the device(processor) to which - * driver is talking is RPMSG master then RPMSG driver implicitly behaves as - * Remote and vice versa. - * RPMSG Master is responsible for initiating communications with the Remote - * and shared buffers management. Terms remote device/core/proc are used - * interchangeably for the processor to which RPMSG driver is communicating - * irrespective of the fact whether it is RPMSG Remote or Master. - * - **************************************************************************/ -#include #include -#include -#include -#include -#include +#include +#include + +#include "rpmsg_internal.h" /** - * rpmsg_init + * rpmsg_get_address * - * Thus function allocates and initializes the rpmsg driver resources for - * given hil_proc. The successful return from this function leaves - * fully enabled IPC link. + * This function provides unique 32 bit address. * - * @param proc - pointer to hil_proc - * @param rdev - pointer to newly created remote device - * @param channel_created - callback function for channel creation - * @param channel_destroyed - callback function for channel deletion - * @param default_cb - default callback for channel I/O - * @param role - role of the other device, Master or Remote - * - * @return - status of function execution + * @param bitmap - bit map for addresses + * @param size - size of bitmap * + * return - a unique address */ - -int rpmsg_init(struct hil_proc *proc, - struct remote_device **rdev, - rpmsg_chnl_cb_t channel_created, - rpmsg_chnl_cb_t channel_destroyed, - rpmsg_rx_cb_t default_cb, int role) +static uint32_t rpmsg_get_address(unsigned long *bitmap, int size) { - int status; + unsigned int addr = RPMSG_ADDR_ANY; + unsigned int nextbit; - /* Initialize the remote device for given cpu id */ - status = rpmsg_rdev_init(proc, rdev, role, - channel_created, - channel_destroyed, default_cb); - if (status == RPMSG_SUCCESS) { - /* Kick off IPC with the remote device */ - status = rpmsg_start_ipc(*rdev); + nextbit = metal_bitmap_next_clear_bit(bitmap, 0, size); + if (nextbit < (uint32_t)size) { + addr = nextbit; + metal_bitmap_set_bit(bitmap, nextbit); } - /* Deinit system in case of error */ - if (status != RPMSG_SUCCESS) { - rpmsg_deinit(*rdev); - } + return addr; +} - return status; +/** + * rpmsg_release_address + * + * Frees the given address. + * + * @param bitmap - bit map for addresses + * @param size - size of bitmap + * @param addr - address to free + */ +static void rpmsg_release_address(unsigned long *bitmap, int size, + int addr) +{ + if (addr < size) + metal_bitmap_clear_bit(bitmap, addr); } /** - * rpmsg_deinit + * rpmsg_is_address_set * - * Thus function frees rpmsg driver resources for given remote device. + * Checks whether address is used or free. * - * @param rdev - pointer to device to de-init + * @param bitmap - bit map for addresses + * @param size - size of bitmap + * @param addr - address to free * + * return - TRUE/FALSE */ +static int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr) +{ + if (addr < size) + return metal_bitmap_is_bit_set(bitmap, addr); + else + return RPMSG_ERR_PARAM; +} -void rpmsg_deinit(struct remote_device *rdev) +/** + * rpmsg_set_address + * + * Marks the address as consumed. + * + * @param bitmap - bit map for addresses + * @param size - size of bitmap + * @param addr - address to free + * + * return - none + */ +static int rpmsg_set_address(unsigned long *bitmap, int size, int addr) { - if (rdev) { - rpmsg_rdev_deinit(rdev); + if (addr < size) { + metal_bitmap_set_bit(bitmap, addr); + return RPMSG_SUCCESS; + } else { + return RPMSG_ERR_PARAM; } } /** * This function sends rpmsg "message" to remote device. * - * @param rp_chnl - pointer to rpmsg channel + * @param ept - pointer to end point * @param src - source address of channel * @param dst - destination address of channel * @param data - data to transmit @@ -112,306 +107,144 @@ void rpmsg_deinit(struct remote_device *rdev) * @return - size of data sent or negative value for failure. * */ - -int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, uint32_t src, - uint32_t dst, const void *data, - int size, int wait) +int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, + uint32_t dst, const void *data, int size, + int wait) { - struct remote_device *rdev; - struct rpmsg_hdr rp_hdr; - void *buffer; - unsigned short idx; - int tick_count = 0; - unsigned long buff_len; - int ret; - struct metal_io_region *io; + struct rpmsg_device *rdev; - if (!rp_chnl || !data) { + if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY) return RPMSG_ERR_PARAM; - } - - /* Get the associated remote device for channel. */ - rdev = rp_chnl->rdev; - - /* Validate device state */ - if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE - || rdev->state != RPMSG_DEV_STATE_ACTIVE) { - return RPMSG_ERR_DEV_STATE; - } - - if (size > (rpmsg_get_buffer_size(rp_chnl))) { - return RPMSG_ERR_BUFF_SIZE; - } - - /* Lock the device to enable exclusive access to virtqueues */ - metal_mutex_acquire(&rdev->lock); - /* Get rpmsg buffer for sending message. */ - buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx); - /* Unlock the device */ - metal_mutex_release(&rdev->lock); - if (!buffer && !wait) { - return RPMSG_ERR_NO_BUFF; - } - - while (!buffer) { - /* - * Wait parameter is true - pool the buffer for - * 15 secs as defined by the APIs. - */ - metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); - metal_mutex_acquire(&rdev->lock); - buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx); - metal_mutex_release(&rdev->lock); - tick_count += RPMSG_TICKS_PER_INTERVAL; - if (!buffer && (tick_count >= - (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL))) { - return RPMSG_ERR_NO_BUFF; - } - } - - /* Initialize RPMSG header. */ - rp_hdr.dst = dst; - rp_hdr.src = src; - rp_hdr.len = size; - rp_hdr.reserved = 0; - - /* Copy data to rpmsg buffer. */ - io = rdev->proc->sh_buff.io; - metal_io_block_write(io, - metal_io_virt_to_offset(io, buffer), - &rp_hdr, sizeof(rp_hdr)); - metal_io_block_write(io, - metal_io_virt_to_offset(io, RPMSG_LOCATE_DATA(buffer)), - data, size); - metal_mutex_acquire(&rdev->lock); + rdev = ept->rdev; - /* Enqueue buffer on virtqueue. */ - ret = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx); - metal_assert(ret == VQUEUE_SUCCESS); - /* Let the other side know that there is a job to process. */ - virtqueue_kick(rdev->tvq); - - metal_mutex_release(&rdev->lock); + if (rdev->ops.send_offchannel_raw) + return rdev->ops.send_offchannel_raw(rdev, src, dst, data, + size, wait); - return size; + return RPMSG_ERR_PARAM; } -/** - * rpmsg_get_buffer_size - * - * Returns buffer size available for sending messages. - * - * @param channel - pointer to rpmsg channel - * - * @return - buffer size - * - */ -int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl) +int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags) { - struct remote_device *rdev; - int length; - - /* Get associated remote device for channel. */ - rdev = rp_chnl->rdev; - - metal_mutex_acquire(&rdev->lock); - - if (rdev->role == RPMSG_REMOTE) { - /* - * If device role is Remote then buffers are provided by us - * (RPMSG Master), so just provide the macro. - */ - length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr); - } else { - /* - * If other core is Master then buffers are provided by it, - * so get the buffer size from the virtqueue. - */ - length = - (int)virtqueue_get_desc_size(rdev->tvq) - - sizeof(struct rpmsg_hdr); - } - - metal_mutex_release(&rdev->lock); + struct rpmsg_ns_msg ns_msg; + int ret; - return length; + ns_msg.flags = flags; + ns_msg.addr = ept->addr; + strncpy(ns_msg.name, ept->name, sizeof(ns_msg.name)); + ret = rpmsg_send_offchannel_raw(ept, ept->addr, + RPMSG_NS_EPT_ADDR, + &ns_msg, sizeof(ns_msg), true); + if (ret < 0) + return ret; + else + return RPMSG_SUCCESS; } -void rpmsg_hold_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf) +struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev, + const char *name, uint32_t addr, + uint32_t dest_addr) { - struct rpmsg_hdr *rp_hdr = NULL; - if (!rpdev || !rxbuf) - return; - - rp_hdr = RPMSG_HDR_FROM_BUF(rxbuf); - - /* set held status to keep buffer */ - rp_hdr->reserved |= RPMSG_BUF_HELD; + struct metal_list *node; + struct rpmsg_endpoint *ept; + + metal_list_for_each(&rdev->endpoints, node) { + int name_match = 0; + + ept = metal_container_of(node, struct rpmsg_endpoint, node); + /* try to get by local address only */ + if (addr != RPMSG_ADDR_ANY && ept->addr == addr) + return ept; + /* try to find match on local end remote address */ + if (addr == ept->addr && dest_addr == ept->dest_addr) + return ept; + /* else use name service and destination address */ + if (name) + name_match = !strncmp(ept->name, name, + sizeof(ept->name)); + if (!name || !name_match) + continue; + /* destination address is known, equal to ept remote address*/ + if (dest_addr != RPMSG_ADDR_ANY && ept->dest_addr == dest_addr) + return ept; + /* ept is registered but not associated to remote ept*/ + if (addr == RPMSG_ADDR_ANY && ept->dest_addr == RPMSG_ADDR_ANY) + return ept; + } + return NULL; } -void rpmsg_release_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf) +static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept) { - struct rpmsg_hdr *hdr; - struct remote_device *rdev; - struct rpmsg_hdr_reserved * reserved = NULL; - unsigned int len; - - if (!rpdev || !rxbuf) - return; - - rdev = rpdev->rdev; - hdr = RPMSG_HDR_FROM_BUF(rxbuf); + struct rpmsg_device *rdev; - /* Get the pointer to the reserved field that contains buffer size - * and the index */ - reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved; - hdr->reserved &= (~RPMSG_BUF_HELD); - len = (unsigned int)virtqueue_get_buffer_length(rdev->rvq, - reserved->idx); - - metal_mutex_acquire(&rdev->lock); + if (!ept) + return; - /* Return used buffer, with total length - (header length + buffer size). */ - rpmsg_return_buffer(rdev, hdr, (unsigned long)len, reserved->idx); + rdev = ept->rdev; - metal_mutex_release(&rdev->lock); + if (ept->addr != RPMSG_ADDR_ANY) + rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, + ept->addr); + metal_list_del(&ept->node); } -void *rpmsg_get_tx_payload_buffer(struct rpmsg_channel *rpdev, uint32_t *size, - int wait) +int rpmsg_register_endpoint(struct rpmsg_device *rdev, + struct rpmsg_endpoint *ept) { - struct rpmsg_hdr *hdr; - struct remote_device *rdev; - struct rpmsg_hdr_reserved *reserved; - unsigned short idx; - unsigned long buff_len, tick_count = 0; - - if (!rpdev || !size) - return NULL; - - rdev = rpdev->rdev; - - metal_mutex_acquire(&rdev->lock); - - /* Get tx buffer from vring */ - hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx); - - metal_mutex_release(&rdev->lock); - - if (!hdr && !wait) { - return NULL; - } else { - while (!hdr) { - /* - * Wait parameter is true - pool the buffer for - * 15 secs as defined by the APIs. - */ - metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); - metal_mutex_acquire(&rdev->lock); - hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx); - metal_mutex_release(&rdev->lock); - tick_count += RPMSG_TICKS_PER_INTERVAL; - if (tick_count >= (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL)) { - return NULL; - } - } - - /* Store the index into the reserved field to be used when sending */ - reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved; - reserved->idx = (uint16_t)idx; + ept->rdev = rdev; - /* Actual data buffer size is vring buffer size minus rpmsg header length */ - *size = (uint32_t)(buff_len - sizeof(struct rpmsg_hdr)); - return (void *)RPMSG_LOCATE_DATA(hdr); - } + metal_list_add_tail(&rdev->endpoints, &ept->node); + return RPMSG_SUCCESS; } -int rpmsg_send_offchannel_nocopy(struct rpmsg_channel *rpdev, uint32_t src, - uint32_t dst, void *txbuf, int len) +int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, + const char *name, uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb) { - struct rpmsg_hdr *hdr; - struct remote_device *rdev; - struct rpmsg_hdr_reserved * reserved = NULL; int status; + uint32_t addr = src; - if (!rpdev || !txbuf) - return RPMSG_ERR_PARAM; - - rdev = rpdev->rdev; - hdr = RPMSG_HDR_FROM_BUF(txbuf); - - /* Initialize RPMSG header. */ - hdr->dst = dst; - hdr->src = src; - hdr->len = len; - hdr->flags = 0; - hdr->reserved &= (~RPMSG_BUF_HELD); - - /* Get the pointer to the reserved field that contains buffer size and - * the index */ - reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved; + if (!ept) + return RPMSG_ERR_PARAM; metal_mutex_acquire(&rdev->lock); - - status = rpmsg_enqueue_buffer(rdev, hdr, - (unsigned long)virtqueue_get_buffer_length( - rdev->tvq, reserved->idx), - reserved->idx); - if (status == RPMSG_SUCCESS) { - /* Let the other side know that there is a job to process. */ - virtqueue_kick(rdev->tvq); - /* Return size of data sent */ - status = len; + if (src != RPMSG_ADDR_ANY) { + status = rpmsg_is_address_set(rdev->bitmap, + RPMSG_ADDR_BMP_SIZE, src); + if (!status) { + /* Mark the address as used in the address bitmap. */ + rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, + src); + } else if (status > 0) { + status = RPMSG_SUCCESS; + goto ret_status; + } else { + goto ret_status; + } + } else { + addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE); } - metal_mutex_release(&rdev->lock); - - return status; -} - -/** - * rpmsg_create_ept - * - * This function creates rpmsg endpoint for the rpmsg channel. - * - * @param channel - pointer to rpmsg channel - * @param cb - Rx completion call back - * @param priv - private data - * @param addr - endpoint src address - * - * @return - pointer to endpoint control block - * - */ -struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl, - rpmsg_rx_cb_t cb, void *priv, - uint32_t addr) -{ + rpmsg_init_ept(ept, name, addr, dest, cb, unbind_cb); - struct remote_device *rdev = RPMSG_NULL; - struct rpmsg_endpoint *rp_ept = RPMSG_NULL; + status = rpmsg_register_endpoint(rdev, ept); + if (status < 0) + rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr); - if (!rp_chnl || !cb) { - return RPMSG_NULL; + if (!status && ept->dest_addr == RPMSG_ADDR_ANY) { + /* Send NS announcement to remote processor */ + metal_mutex_release(&rdev->lock); + status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE); + metal_mutex_acquire(&rdev->lock); + if (status) + rpmsg_unregister_endpoint(ept); } - rdev = rp_chnl->rdev; - - metal_mutex_acquire(&rdev->lock); - rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, addr); +ret_status: metal_mutex_release(&rdev->lock); - if (!rp_ept) { - rp_ept = _create_endpoint(rdev, cb, priv, addr); - - if (rp_ept) { - rp_ept->rp_chnl = rp_chnl; - } - } else { - return RPMSG_NULL; - } - - return rp_ept; + return status; } /** @@ -419,113 +252,20 @@ struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl, * * This function deletes rpmsg endpoint and performs cleanup. * - * @param rp_ept - pointer to endpoint to destroy - * - */ -void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept) -{ - - struct remote_device *rdev; - struct rpmsg_channel *rp_chnl; - - if (!rp_ept) - return; - - rp_chnl = rp_ept->rp_chnl; - rdev = rp_chnl->rdev; - - _destroy_endpoint(rdev, rp_ept); -} - -/** - * rpmsg_create_channel - * - * This function provides facility to create channel dynamically. It sends - * Name Service announcement to remote device to let it know about the channel - * creation. There must be an active communication among the cores (or atleast - * one rpmsg channel must already exist) before using this API to create new - * channels. - * - * @param rdev - pointer to remote device - * @param name - channel name - * - * @return - pointer to new rpmsg channel - * - */ -struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev, - char *name) -{ - - struct rpmsg_channel *rp_chnl; - struct rpmsg_endpoint *rp_ept; - - if (!rdev || !name) { - return RPMSG_NULL; - } - - /* Create channel instance */ - rp_chnl = _rpmsg_create_channel(rdev, name, RPMSG_NS_EPT_ADDR, - RPMSG_NS_EPT_ADDR); - if (!rp_chnl) { - return RPMSG_NULL; - } - - /* Create default endpoint for the channel */ - rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev, - RPMSG_ADDR_ANY); - - if (!rp_ept) { - _rpmsg_delete_channel(rp_chnl); - return RPMSG_NULL; - } - - rp_chnl->rp_ept = rp_ept; - rp_chnl->src = rp_ept->addr; - rp_chnl->state = RPMSG_CHNL_STATE_NS; - - /* Notify the application of channel creation event */ - if (rdev->channel_created) { - rdev->channel_created(rp_chnl); - } - - /* Send NS announcement to remote processor */ - rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE); - - return rp_chnl; -} - -/** - * rpmsg_delete_channel - * - * Deletes the given RPMSG channel. The channel must first be created with the - * rpmsg_create_channel API. - * - * @param rp_chnl - pointer to rpmsg channel to delete + * @param ept - pointer to endpoint to destroy * */ -void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl) +void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { + struct rpmsg_device *rdev; - struct remote_device *rdev; - - if (!rp_chnl) { + if (!ept) return; - } - - rdev = rp_chnl->rdev; - - if (rp_chnl->state > RPMSG_CHNL_STATE_IDLE) { - /* Notify the other processor that channel no longer exists */ - rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY); - } - /* Notify channel deletion to application */ - if (rdev->channel_destroyed) { - rdev->channel_destroyed(rp_chnl); - } - - rpmsg_destroy_ept(rp_chnl->rp_ept); - _rpmsg_delete_channel(rp_chnl); - - return; + rdev = ept->rdev; + if (ept->addr != RPMSG_NS_EPT_ADDR) + (void)rpmsg_send_ns_message(ept, RPMSG_NS_DESTROY); + metal_mutex_acquire(&rdev->lock); + rpmsg_unregister_endpoint(ept); + metal_mutex_release(&rdev->lock); } diff --git a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_core.c b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_core.c deleted file mode 100644 index 46bdb6b4922d94..00000000000000 --- a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_core.c +++ /dev/null @@ -1,821 +0,0 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * Copyright (c) 2015 Xilinx, Inc. All rights reserved. - * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * FILE NAME - * - * rpmsg_core.c - * - * COMPONENT - * - * OpenAMP - * - * DESCRIPTION - * - * This file provides the core functionality of RPMSG messaging part like - * message parsing ,Rx/Tx callbacks handling , channel creation/deletion - * and address management. - * - * - **************************************************************************/ -#include -#include -#include -#include -#include -#include -#include - -/* Internal functions */ -static void rpmsg_rx_callback(struct virtqueue *vq); -static void rpmsg_tx_callback(struct virtqueue *vq); - -/** - * rpmsg_memb_cpy - * - * This function copies contents from one memory to the other byte by byte. - * - * RPMsg can be used across different memories. - * memcpy/strncpy doesn't always work. - * - * @param src - pointer to source memory - * @param dest - pointer to target memory - * @param n - number of bytes to copy - * - * @return pointer to dest - */ -static void *rpmsg_memb_cpy(void *dest, const void *src, size_t n) -{ - size_t i; - unsigned char *tmp_dest; - const unsigned char *tmp_src; - - tmp_dest = dest; - tmp_src = src; - - for (i = 0; i < n; i++, tmp_dest++, tmp_src++) - *tmp_dest = *tmp_src; - - return dest; -} - -/** - * rpmsg_start_ipc - * - * This function creates communication links(virtqueues) for remote device - * and notifies it to start IPC. - * - * @param rdev - remote device handle - * - * @return - status of function execution - * - */ -int rpmsg_start_ipc(struct remote_device *rdev) -{ - struct virtio_device *virt_dev; - struct rpmsg_endpoint *ns_ept; - void (*callback[2]) (struct virtqueue * vq); - const char *vq_names[2]; - unsigned long dev_features; - int status; - struct virtqueue *vqs[2]; - int i; - - virt_dev = &rdev->virt_dev; - - /* Initialize names and callbacks based on the device role */ - if (rdev->role == RPMSG_MASTER) { - vq_names[0] = "tx_vq"; - vq_names[1] = "rx_vq"; - callback[0] = rpmsg_tx_callback; - callback[1] = rpmsg_rx_callback; - } else { - vq_names[0] = "rx_vq"; - vq_names[1] = "tx_vq"; - callback[0] = rpmsg_rx_callback; - callback[1] = rpmsg_tx_callback; - } - - /* Create virtqueues for remote device */ - status = virt_dev->func->create_virtqueues(virt_dev, 0, - RPMSG_MAX_VQ_PER_RDEV, - vq_names, callback, - RPMSG_NULL); - if (status != RPMSG_SUCCESS) - return status; - - dev_features = virt_dev->func->get_features(virt_dev); - - /* - * Create name service announcement endpoint if device supports name - * service announcement feature. - */ - if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) { - rdev->support_ns = RPMSG_TRUE; - ns_ept = _create_endpoint(rdev, rpmsg_ns_callback, rdev, - RPMSG_NS_EPT_ADDR); - if (!ns_ept) { - return RPMSG_ERR_NO_MEM; - } - } - - /* Initialize notifications for vring. */ - if (rdev->role == RPMSG_MASTER) { - vqs[0] = rdev->tvq; - vqs[1] = rdev->rvq; - } else { - vqs[0] = rdev->rvq; - vqs[1] = rdev->tvq; - } - for (i = 0; i <= 1; i++) { - status = hil_enable_vring_notifications(i, vqs[i]); - if (status != RPMSG_SUCCESS) { - return status; - } - } - - if (rdev->role == RPMSG_REMOTE) { - virt_dev->func->set_status(virt_dev, - VIRTIO_CONFIG_STATUS_DRIVER_OK); - status = rpmsg_rdev_notify(rdev); - } - if (status == RPMSG_SUCCESS) - rdev->state = RPMSG_DEV_STATE_ACTIVE; - - return status; -} - -/** - * _rpmsg_create_channel - * - * Creates new rpmsg channel with the given parameters. - * - * @param rdev - pointer to remote device which contains the channel - * @param name - name of the device - * @param src - source address for the rpmsg channel - * @param dst - destination address for the rpmsg channel - * - * @return - pointer to new rpmsg channel - * - */ -struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev, - char *name, unsigned long src, - unsigned long dst) -{ - struct rpmsg_channel *rp_chnl; - - rp_chnl = metal_allocate_memory(sizeof(struct rpmsg_channel)); - if (rp_chnl) { - memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel)); - rpmsg_memb_cpy(rp_chnl->name, name, sizeof(rp_chnl->name)-1); - rp_chnl->src = src; - rp_chnl->dst = dst; - rp_chnl->rdev = rdev; - /* Place channel on channels list */ - metal_mutex_acquire(&rdev->lock); - metal_list_add_tail(&rdev->rp_channels, &rp_chnl->node); - metal_mutex_release(&rdev->lock); - } - - return rp_chnl; -} - -/** - * _rpmsg_delete_channel - * - * Deletes given rpmsg channel. - * - * @param rp_chnl - pointer to rpmsg channel to delete - * - * return - none - */ -void _rpmsg_delete_channel(struct rpmsg_channel *rp_chnl) -{ - if (rp_chnl) { - metal_mutex_acquire(&rp_chnl->rdev->lock); - metal_list_del(&rp_chnl->node); - metal_mutex_release(&rp_chnl->rdev->lock); - metal_free_memory(rp_chnl); - } -} - -/** - * _create_endpoint - * - * This function creates rpmsg endpoint. - * - * @param rdev - pointer to remote device - * @param cb - Rx completion call back - * @param priv - private data - * @param addr - endpoint src address - * - * @return - pointer to endpoint control block - * - */ -struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev, - rpmsg_rx_cb_t cb, void *priv, - unsigned long addr) -{ - - struct rpmsg_endpoint *rp_ept; - int status = RPMSG_SUCCESS; - - rp_ept = metal_allocate_memory(sizeof(struct rpmsg_endpoint)); - if (!rp_ept) { - return RPMSG_NULL; - } - memset(rp_ept, 0x00, sizeof(struct rpmsg_endpoint)); - - metal_mutex_acquire(&rdev->lock); - - if (addr != RPMSG_ADDR_ANY) { - /* - * Application has requested a particular src address for endpoint, - * first check if address is available. - */ - if (!rpmsg_is_address_set - (rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr)) { - /* Mark the address as used in the address bitmap. */ - rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, - addr); - - } else { - status = RPMSG_ERR_DEV_ADDR; - } - } else { - addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE); - if ((int)addr < 0) { - status = RPMSG_ERR_DEV_ADDR; - } - } - - /* Do cleanup in case of error and return */ - if (RPMSG_SUCCESS != status) { - metal_free_memory(rp_ept); - metal_mutex_release(&rdev->lock); - return RPMSG_NULL; - } - - rp_ept->addr = addr; - rp_ept->cb = cb; - rp_ept->priv = priv; - - metal_list_add_tail(&rdev->rp_endpoints, &rp_ept->node); - - metal_mutex_release(&rdev->lock); - - return rp_ept; -} - -/** - * rpmsg_destroy_ept - * - * This function deletes rpmsg endpoint and performs cleanup. - * - * @param rdev - pointer to remote device - * @param rp_ept - pointer to endpoint to destroy - * - */ -void _destroy_endpoint(struct remote_device *rdev, - struct rpmsg_endpoint *rp_ept) -{ - metal_mutex_acquire(&rdev->lock); - rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, - rp_ept->addr); - metal_list_del(&rp_ept->node); - metal_mutex_release(&rdev->lock); - /* free node and rp_ept */ - metal_free_memory(rp_ept); -} - -/** - * rpmsg_send_ns_message - * - * Sends name service announcement to remote device - * - * @param rdev - pointer to remote device - * @param rp_chnl - pointer to rpmsg channel - * @param flags - Channel creation/deletion flags - * - */ -int rpmsg_send_ns_message(struct remote_device *rdev, - struct rpmsg_channel *rp_chnl, unsigned long flags) -{ - - struct rpmsg_hdr rp_hdr; - struct rpmsg_ns_msg ns_msg; - unsigned short idx; - unsigned long len; - struct metal_io_region *io; - void *shbuf; - - metal_mutex_acquire(&rdev->lock); - - /* Get Tx buffer. */ - shbuf = rpmsg_get_tx_buffer(rdev, &len, &idx); - if (!shbuf) { - metal_mutex_release(&rdev->lock); - return -RPMSG_ERR_NO_BUFF; - } - - /* Fill out name service data. */ - rp_hdr.dst = RPMSG_NS_EPT_ADDR; - rp_hdr.len = sizeof(ns_msg); - ns_msg.flags = flags; - ns_msg.addr = rp_chnl->src; - strncpy(ns_msg.name, rp_chnl->name, sizeof(ns_msg.name)); - - io = rdev->proc->sh_buff.io; - metal_io_block_write(io, metal_io_virt_to_offset(io, shbuf), - &rp_hdr, sizeof(rp_hdr)); - metal_io_block_write(io, - metal_io_virt_to_offset(io, RPMSG_LOCATE_DATA(shbuf)), - &ns_msg, rp_hdr.len); - - /* Place the buffer on virtqueue. */ - rpmsg_enqueue_buffer(rdev, shbuf, len, idx); - - /* Notify the other side that it has data to process. */ - virtqueue_kick(rdev->tvq); - - metal_mutex_release(&rdev->lock); - return RPMSG_SUCCESS; -} - -/** - * rpmsg_enqueue_buffers - * - * Places buffer on the virtqueue for consumption by the other side. - * - * @param rdev - pointer to remote core - * @param buffer - buffer pointer - * @param len - buffer length - * @idx - buffer index - * - * @return - status of function execution - * - */ -int rpmsg_enqueue_buffer(struct remote_device *rdev, void *buffer, - unsigned long len, unsigned short idx) -{ - int status; - struct metal_sg sg; - struct metal_io_region *io; - - io = rdev->proc->sh_buff.io; - if (rdev->role == RPMSG_REMOTE) { - /* Initialize buffer node */ - sg.virt = buffer; - sg.len = len; - sg.io = io; - status = virtqueue_add_buffer(rdev->tvq, &sg, 0, 1, buffer); - } else { - (void)sg; - status = virtqueue_add_consumed_buffer(rdev->tvq, idx, len); - } - - return status; -} - -/** - * rpmsg_return_buffer - * - * Places the used buffer back on the virtqueue. - * - * @param rdev - pointer to remote core - * @param buffer - buffer pointer - * @param len - buffer length - * @param idx - buffer index - * - */ -void rpmsg_return_buffer(struct remote_device *rdev, void *buffer, - unsigned long len, unsigned short idx) -{ - struct metal_sg sg; - - if (rdev->role == RPMSG_REMOTE) { - /* Initialize buffer node */ - sg.virt = buffer; - sg.len = len; - sg.io = rdev->proc->sh_buff.io; - virtqueue_add_buffer(rdev->rvq, &sg, 0, 1, buffer); - } else { - (void)sg; - virtqueue_add_consumed_buffer(rdev->rvq, idx, len); - } -} - -/** - * rpmsg_get_tx_buffer - * - * Provides buffer to transmit messages. - * - * @param rdev - pointer to remote device - * @param len - length of returned buffer - * @param idx - buffer index - * - * return - pointer to buffer. - */ -void *rpmsg_get_tx_buffer(struct remote_device *rdev, unsigned long *len, - unsigned short *idx) -{ - void *data; - - if (rdev->role == RPMSG_REMOTE) { - data = virtqueue_get_buffer(rdev->tvq, (uint32_t *) len, idx); - if (data == RPMSG_NULL) { - data = sh_mem_get_buffer(rdev->mem_pool); - *len = RPMSG_BUFFER_SIZE; - } - } else { - data = - virtqueue_get_available_buffer(rdev->tvq, idx, - (uint32_t *) len); - } - return data; -} - -/** - * rpmsg_get_rx_buffer - * - * Retrieves the received buffer from the virtqueue. - * - * @param rdev - pointer to remote device - * @param len - size of received buffer - * @param idx - index of buffer - * - * @return - pointer to received buffer - * - */ -void *rpmsg_get_rx_buffer(struct remote_device *rdev, unsigned long *len, - unsigned short *idx) -{ - - void *data; - if (rdev->role == RPMSG_REMOTE) { - data = virtqueue_get_buffer(rdev->rvq, (uint32_t *) len, idx); - } else { - data = - virtqueue_get_available_buffer(rdev->rvq, idx, - (uint32_t *) len); - } - if (data) { - /* FIX ME: library should not worry about if it needs - * to flush/invalidate cache, it is shared memory. - * The shared memory should be mapped properly before - * using it. - */ - metal_cache_invalidate(data, (unsigned int)(*len)); - } - - return data; -} - -/** - * rpmsg_free_buffer - * - * Frees the allocated buffers. - * - * @param rdev - pointer to remote device - * @param buffer - pointer to buffer to free - * - */ -void rpmsg_free_buffer(struct remote_device *rdev, void *buffer) -{ - if (rdev->role == RPMSG_REMOTE) { - sh_mem_free_buffer(buffer, rdev->mem_pool); - } -} - -/** - * rpmsg_tx_callback - * - * Tx callback function. - * - * @param vq - pointer to virtqueue on which Tx is has been - * completed. - * - */ -static void rpmsg_tx_callback(struct virtqueue *vq) -{ - struct remote_device *rdev; - struct virtio_device *vdev; - struct rpmsg_channel *rp_chnl; - struct metal_list *node; - - vdev = (struct virtio_device *)vq->vq_dev; - rdev = (struct remote_device *)vdev; - - /* Check if the remote device is master. */ - if (rdev->role == RPMSG_MASTER) { - - /* Notification is received from the master. Now the remote(us) can - * performs one of two operations; - * - * a. If name service announcement is supported then it will send NS message. - * else - * b. It will update the channel state to active so that further communication - * can take place. - */ - metal_list_for_each(&rdev->rp_channels, node) { - rp_chnl = metal_container_of(node, - struct rpmsg_channel, node); - - if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) { - - if (rdev->support_ns) { - if (rpmsg_send_ns_message(rdev, rp_chnl, - RPMSG_NS_CREATE) == - RPMSG_SUCCESS) - rp_chnl->state = - RPMSG_CHNL_STATE_NS; - } else { - rp_chnl->state = - RPMSG_CHNL_STATE_ACTIVE; - } - - } - - } - } -} - -/** - * rpmsg_rx_callback - * - * Rx callback function. - * - * @param vq - pointer to virtqueue on which messages is received - * - */ -void rpmsg_rx_callback(struct virtqueue *vq) -{ - struct remote_device *rdev; - struct virtio_device *vdev; - struct rpmsg_channel *rp_chnl; - struct rpmsg_endpoint *rp_ept; - struct rpmsg_hdr *rp_hdr; - struct rpmsg_hdr_reserved *reserved; - unsigned long len; - unsigned short idx; - - vdev = (struct virtio_device *)vq->vq_dev; - rdev = (struct remote_device *)vdev; - - metal_mutex_acquire(&rdev->lock); - - /* Process the received data from remote node */ - rp_hdr = (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx); - - metal_mutex_release(&rdev->lock); - - while (rp_hdr) { - /* Get the channel node from the remote device channels list. */ - metal_mutex_acquire(&rdev->lock); - rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst); - metal_mutex_release(&rdev->lock); - - if (!rp_ept) { - /* Fatal error no endpoint for the given dst addr. */ - return; - } - - rp_chnl = rp_ept->rp_chnl; - - if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) { - /* First message from RPMSG Master, update channel - * destination address and state */ - if (rp_ept->addr == RPMSG_NS_EPT_ADDR) { - rp_ept->cb(rp_chnl, - (void *)RPMSG_LOCATE_DATA(rp_hdr), - rp_hdr->len, rdev, - rp_hdr->src); - } else { - rp_chnl->dst = rp_hdr->src; - rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE; - - /* Notify channel creation to application */ - if (rdev->channel_created) { - rdev->channel_created(rp_chnl); - } - } - } else { - rp_ept->cb(rp_chnl, (void *)RPMSG_LOCATE_DATA(rp_hdr), rp_hdr->len, - rp_ept->priv, rp_hdr->src); - } - - metal_mutex_acquire(&rdev->lock); - - /* Check whether callback wants to hold buffer */ - if (rp_hdr->reserved & RPMSG_BUF_HELD) - { - /* 'rp_hdr->reserved' field is now used as storage for - * 'idx' to release buffer later */ - reserved = (struct rpmsg_hdr_reserved*)&rp_hdr->reserved; - reserved->idx = (uint16_t)idx; - } else { - /* Return used buffers. */ - rpmsg_return_buffer(rdev, rp_hdr, len, idx); - } - - rp_hdr = - (struct rpmsg_hdr *)rpmsg_get_rx_buffer(rdev, &len, &idx); - metal_mutex_release(&rdev->lock); - } -} - -/** - * rpmsg_ns_callback - * - * This callback handles name service announcement from the remote device - * and creates/deletes rpmsg channels. - * - * @param server_chnl - pointer to server channel control block. - * @param data - pointer to received messages - * @param len - length of received data - * @param priv - any private data - * @param src - source address - * - * @return - none - */ -void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len, - void *priv, unsigned long src) -{ - struct remote_device *rdev; - struct rpmsg_channel *rp_chnl; - struct rpmsg_ns_msg *ns_msg; - - (void)server_chnl; - (void)src; - (void)len; - - rdev = (struct remote_device *)priv; - - //FIXME: This assumes same name string size for channel name both on master - //and remote. If this is not the case then we will have to parse the - //message contents. - - ns_msg = (struct rpmsg_ns_msg *)data; - - if (ns_msg->flags & RPMSG_NS_DESTROY) { - metal_mutex_acquire(&rdev->lock); - rp_chnl = rpmsg_rdev_get_chnl_from_id(rdev, ns_msg->name); - metal_mutex_release(&rdev->lock); - if (rp_chnl) { - if (rdev->channel_destroyed) { - rdev->channel_destroyed(rp_chnl); - } - rpmsg_destroy_ept(rp_chnl->rp_ept); - _rpmsg_delete_channel(rp_chnl); - } - } else { - metal_mutex_acquire(&rdev->lock); - rp_chnl = rpmsg_rdev_get_chnl_from_id(rdev, ns_msg->name); - metal_mutex_release(&rdev->lock); - if (!rp_chnl) { - rp_chnl = _rpmsg_create_channel(rdev, ns_msg->name, - 0x00, - ns_msg->addr); - } - if (rp_chnl) { - metal_mutex_acquire(&rdev->lock); - rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE; - rp_chnl->dst = ns_msg->addr; - metal_mutex_release(&rdev->lock); - /* Create default endpoint for channel */ - if (!rp_chnl->rp_ept) { - rp_chnl->rp_ept = - rpmsg_create_ept(rp_chnl, - rdev->default_cb, rdev, - RPMSG_ADDR_ANY); - if (rp_chnl->rp_ept) { - rp_chnl->src = rp_chnl->rp_ept->addr; - rpmsg_send_ns_message(rdev, - rp_chnl, - RPMSG_NS_CREATE); - } - } - if (rdev->channel_created) - rdev->channel_created(rp_chnl); - } - } -} - -/** - * rpmsg_get_address - * - * This function provides unique 32 bit address. - * - * @param bitmap - bit map for addresses - * @param size - size of bitmap - * - * return - a unique address - */ -int rpmsg_get_address(unsigned long *bitmap, int size) -{ - int addr = -1; - int i, tmp32; - - /* Find first available buffer */ - for (i = 0; i < size; i++) { - tmp32 = get_first_zero_bit(bitmap[i]); - - if (tmp32 < 32) { - addr = tmp32 + (i*32); - bitmap[i] |= (1 << tmp32); - break; - } - } - - return addr; -} - -/** - * rpmsg_release_address - * - * Frees the given address. - * - * @param bitmap - bit map for addresses - * @param size - size of bitmap - * @param addr - address to free - * - * return - none - */ -int rpmsg_release_address(unsigned long *bitmap, int size, int addr) -{ - unsigned int i, j; - unsigned long mask = 1; - - if (addr >= size * 32) - return -1; - - /* Mark the addr as available */ - i = addr / 32; - j = addr % 32; - - mask = mask << j; - bitmap[i] = bitmap[i] & (~mask); - - return RPMSG_SUCCESS; -} - -/** - * rpmsg_is_address_set - * - * Checks whether address is used or free. - * - * @param bitmap - bit map for addresses - * @param size - size of bitmap - * @param addr - address to free - * - * return - TRUE/FALSE - */ -int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr) -{ - int i, j; - unsigned long mask = 1; - - if (addr >= size * 32) - return -1; - - /* Mark the id as available */ - i = addr / 32; - j = addr % 32; - mask = mask << j; - - return (bitmap[i] & mask); -} - -/** - * rpmsg_set_address - * - * Marks the address as consumed. - * - * @param bitmap - bit map for addresses - * @param size - size of bitmap - * @param addr - address to free - * - * return - none - */ -int rpmsg_set_address(unsigned long *bitmap, int size, int addr) -{ - int i, j; - unsigned long mask = 1; - - if (addr >= size * 32) - return -1; - - /* Mark the id as available */ - i = addr / 32; - j = addr % 32; - mask = mask << j; - bitmap[i] |= mask; - - return RPMSG_SUCCESS; -} diff --git a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_internal.h b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_internal.h new file mode 100644 index 00000000000000..e1b82086c919c6 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_internal.h @@ -0,0 +1,105 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * $FreeBSD$ + */ + +#ifndef _RPMSG_INTERNAL_H_ +#define _RPMSG_INTERNAL_H_ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#ifdef RPMSG_DEBUG +#define RPMSG_ASSERT(_exp, _msg) do { \ + if (!(_exp)) { \ + openamp_print("FATAL: %s - _msg", __func__); \ + while (1) { \ + ; \ + } \ + } \ + } while (0) +#else +#define RPMSG_ASSERT(_exp, _msg) do { \ + if (!(_exp)) \ + while (1) { \ + ; \ + } \ + } while (0) +#endif + +#define RPMSG_LOCATE_DATA(p) ((unsigned char *)(p) + sizeof(struct rpmsg_hdr)) +/** + * enum rpmsg_ns_flags - dynamic name service announcement flags + * + * @RPMSG_NS_CREATE: a new remote service was just created + * @RPMSG_NS_DESTROY: a known remote service was just destroyed + * @RPMSG_NS_CREATE_WITH_ACK: a new remote service was just created waiting + * acknowledgment. + */ +enum rpmsg_ns_flags { + RPMSG_NS_CREATE = 0, + RPMSG_NS_DESTROY = 1, +}; + +/** + * struct rpmsg_hdr - common header for all rpmsg messages + * @src: source address + * @dst: destination address + * @reserved: reserved for future use + * @len: length of payload (in bytes) + * @flags: message flags + * + * Every message sent(/received) on the rpmsg bus begins with this header. + */ +OPENAMP_PACKED_BEGIN +struct rpmsg_hdr { + uint32_t src; + uint32_t dst; + uint32_t reserved; + uint16_t len; + uint16_t flags; +} OPENAMP_PACKED_END; + +/** + * struct rpmsg_ns_msg - dynamic name service announcement message + * @name: name of remote service that is published + * @addr: address of remote service that is published + * @flags: indicates whether service is created or destroyed + * + * This message is sent across to publish a new service, or announce + * about its removal. When we receive these messages, an appropriate + * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe() + * or ->remove() handler of the appropriate rpmsg driver will be invoked + * (if/as-soon-as one is registered). + */ +OPENAMP_PACKED_BEGIN +struct rpmsg_ns_msg { + char name[RPMSG_NAME_SIZE]; + uint32_t addr; + uint32_t flags; +} OPENAMP_PACKED_END; + +int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags); + +struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rvdev, + const char *name, uint32_t addr, + uint32_t dest_addr); +int rpmsg_register_endpoint(struct rpmsg_device *rdev, + struct rpmsg_endpoint *ept); + +static inline struct rpmsg_endpoint * +rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr) +{ + return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY); +} + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_INTERNAL_H_ */ diff --git a/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_virtio.c b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_virtio.c new file mode 100644 index 00000000000000..c7ef1b5a057485 --- /dev/null +++ b/ext/lib/ipc/open-amp/open-amp/lib/rpmsg/rpmsg_virtio.c @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (c) 2018 Linaro, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "rpmsg_internal.h" + +#define RPMSG_NUM_VRINGS (2) + +/* Total tick count for 15secs - 1msec tick. */ +#define RPMSG_TICK_COUNT 15000 + +/* Time to wait - In multiple of 10 msecs. */ +#define RPMSG_TICKS_PER_INTERVAL 10 + +#define WORD_SIZE sizeof(unsigned long) +#define WORD_ALIGN(a) ((((a) & (WORD_SIZE - 1)) != 0) ? \ + (((a) & (~(WORD_SIZE - 1))) + WORD_SIZE) : (a)) + +#ifndef VIRTIO_SLAVE_ONLY +metal_weak void * +rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, + size_t size) +{ + void *buffer; + + if (shpool->avail < size) + return NULL; + buffer = (void *)((char *)shpool->base + shpool->size - shpool->avail); + shpool->avail -= size; + + return buffer; +} +#endif /*!VIRTIO_SLAVE_ONLY*/ + +void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, + void *shb, size_t size) +{ + if (!shpool) + return; + shpool->base = shb; + shpool->size = WORD_ALIGN(size); + shpool->avail = WORD_ALIGN(size); +} + +/** + * rpmsg_virtio_return_buffer + * + * Places the used buffer back on the virtqueue. + * + * @param rvdev - pointer to remote core + * @param buffer - buffer pointer + * @param len - buffer length + * @param idx - buffer index + * + */ +static void rpmsg_virtio_return_buffer(struct rpmsg_virtio_device *rvdev, + void *buffer, unsigned long len, + unsigned short idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + struct virtqueue_buf vqbuf; + + (void)idx; + /* Initialize buffer node */ + vqbuf.buf = buffer; + vqbuf.len = len; + virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, buffer); + } +#endif /*VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + (void)buffer; + virtqueue_add_consumed_buffer(rvdev->rvq, idx, len); + } +#endif /*VIRTIO_MASTER_ONLY*/ +} + +/** + * rpmsg_virtio_enqueue_buffer + * + * Places buffer on the virtqueue for consumption by the other side. + * + * @param rvdev - pointer to rpmsg virtio + * @param buffer - buffer pointer + * @param len - buffer length + * @param idx - buffer index + * + * @return - status of function execution + */ +static int rpmsg_virtio_enqueue_buffer(struct rpmsg_virtio_device *rvdev, + void *buffer, unsigned long len, + unsigned short idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + struct virtqueue_buf vqbuf; + (void)idx; + + /* Initialize buffer node */ + vqbuf.buf = buffer; + vqbuf.len = len; + return virtqueue_add_buffer(rvdev->svq, &vqbuf, 0, 1, buffer); + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + (void)buffer; + return virtqueue_add_consumed_buffer(rvdev->svq, idx, len); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + return 0; +} + +/** + * rpmsg_virtio_get_tx_buffer + * + * Provides buffer to transmit messages. + * + * @param rvdev - pointer to rpmsg device + * @param len - length of returned buffer + * @param idx - buffer index + * + * return - pointer to buffer. + */ +static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev, + unsigned long *len, + unsigned short *idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); + void *data = NULL; + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + data = virtqueue_get_buffer(rvdev->svq, (uint32_t *)len, idx); + if (data == NULL) { + data = rpmsg_virtio_shm_pool_get_buffer(rvdev->shpool, + RPMSG_BUFFER_SIZE); + *len = RPMSG_BUFFER_SIZE; + } + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + data = virtqueue_get_available_buffer(rvdev->svq, idx, + (uint32_t *)len); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + return data; +} + +/** + * rpmsg_virtio_get_rx_buffer + * + * Retrieves the received buffer from the virtqueue. + * + * @param rvdev - pointer to rpmsg device + * @param len - size of received buffer + * @param idx - index of buffer + * + * @return - pointer to received buffer + * + */ +static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev, + unsigned long *len, + unsigned short *idx) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); + void *data = NULL; + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + data = virtqueue_get_buffer(rvdev->rvq, (uint32_t *)len, idx); + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + data = + virtqueue_get_available_buffer(rvdev->rvq, idx, + (uint32_t *)len); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + if (data) { + /* FIX ME: library should not worry about if it needs + * to flush/invalidate cache, it is shared memory. + * The shared memory should be mapped properly before + * using it. + */ + metal_cache_invalidate(data, (unsigned int)(*len)); + } + + return data; +} + +#ifndef VIRTIO_MASTER_ONLY +/** + * check if the remote is ready to start RPMsg communication + */ +static int rpmsg_virtio_wait_remote_ready(struct rpmsg_virtio_device *rvdev) +{ + uint8_t status; + + while (1) { + status = rpmsg_virtio_get_status(rvdev); + /* Busy wait until the remote is ready */ + if (status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) { + rpmsg_virtio_set_status(rvdev, 0); + /* TODO notify remote processor */ + } else if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) { + return true; + } + /* TODO: clarify metal_cpu_yield usage*/ + metal_cpu_yield(); + } + + return false; +} +#endif /*!VIRTIO_MASTER_ONLY*/ + +/** + * _rpmsg_virtio_get_buffer_size + * + * Returns buffer size available for sending messages. + * + * @param channel - pointer to rpmsg channel + * + * @return - buffer size + * + */ +static int _rpmsg_virtio_get_buffer_size(struct rpmsg_virtio_device *rvdev) +{ + unsigned int role = rpmsg_virtio_get_role(rvdev); + int length = 0; + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + /* + * If device role is Remote then buffers are provided by us + * (RPMSG Master), so just provide the macro. + */ + length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr); + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + /* + * If other core is Master then buffers are provided by it, + * so get the buffer size from the virtqueue. + */ + length = + (int)virtqueue_get_desc_size(rvdev->svq) - + sizeof(struct rpmsg_hdr); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + return length; +} + +/** + * This function sends rpmsg "message" to remote device. + * + * @param rdev - pointer to rpmsg device + * @param src - source address of channel + * @param dst - destination address of channel + * @param data - data to transmit + * @param size - size of data + * @param wait - boolean, wait or not for buffer to become + * available + * + * @return - size of data sent or negative value for failure. + * + */ +static int rpmsg_virtio_send_offchannel_raw(struct rpmsg_device *rdev, + uint32_t src, uint32_t dst, + const void *data, + int size, int wait) +{ + struct rpmsg_virtio_device *rvdev; + struct rpmsg_hdr rp_hdr; + void *buffer = NULL; + unsigned short idx; + int tick_count = 0; + unsigned long buff_len; + int status; + struct metal_io_region *io; + + /* Get the associated remote device for channel. */ + rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); + + status = rpmsg_virtio_get_status(rvdev); + /* Validate device state */ + if (!(status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) { + return RPMSG_ERR_DEV_STATE; + } + + if (wait) + tick_count = RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL; + else + tick_count = 0; + + while (1) { + int avail_size; + + /* Lock the device to enable exclusive access to virtqueues */ + metal_mutex_acquire(&rdev->lock); + avail_size = _rpmsg_virtio_get_buffer_size(rvdev); + if (size <= avail_size) + buffer = rpmsg_virtio_get_tx_buffer(rvdev, &buff_len, + &idx); + metal_mutex_release(&rdev->lock); + if (buffer || !tick_count) + break; + if (avail_size != 0) + return RPMSG_ERR_BUFF_SIZE; + metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); + tick_count--; + } + if (!buffer) + return RPMSG_ERR_NO_BUFF; + + /* Initialize RPMSG header. */ + rp_hdr.dst = dst; + rp_hdr.src = src; + rp_hdr.len = size; + rp_hdr.reserved = 0; + + /* Copy data to rpmsg buffer. */ + io = rvdev->shbuf_io; + status = metal_io_block_write(io, metal_io_virt_to_offset(io, buffer), + &rp_hdr, sizeof(rp_hdr)); + RPMSG_ASSERT(status == sizeof(rp_hdr), "failed to write header\n"); + + status = metal_io_block_write(io, + metal_io_virt_to_offset(io, + RPMSG_LOCATE_DATA(buffer)), + data, size); + RPMSG_ASSERT(status == size, "failed to write buffer\n"); + metal_mutex_acquire(&rdev->lock); + + /* Enqueue buffer on virtqueue. */ + status = rpmsg_virtio_enqueue_buffer(rvdev, buffer, buff_len, idx); + RPMSG_ASSERT(status == VQUEUE_SUCCESS, "failed to enqueue buffer\n"); + /* Let the other side know that there is a job to process. */ + virtqueue_kick(rvdev->svq); + + metal_mutex_release(&rdev->lock); + + return size; +} + +/** + * rpmsg_virtio_tx_callback + * + * Tx callback function. + * + * @param vq - pointer to virtqueue on which Tx is has been + * completed. + * + */ +static void rpmsg_virtio_tx_callback(struct virtqueue *vq) +{ + (void)vq; +} + +/** + * rpmsg_virtio_rx_callback + * + * Rx callback function. + * + * @param vq - pointer to virtqueue on which messages is received + * + */ +static void rpmsg_virtio_rx_callback(struct virtqueue *vq) +{ + struct virtio_device *vdev = vq->vq_dev; + struct rpmsg_virtio_device *rvdev = vdev->priv; + struct rpmsg_device *rdev = &rvdev->rdev; + struct rpmsg_endpoint *ept; + struct rpmsg_hdr *rp_hdr; + unsigned long len; + unsigned short idx; + int status; + + metal_mutex_acquire(&rdev->lock); + + /* Process the received data from remote node */ + rp_hdr = (struct rpmsg_hdr *)rpmsg_virtio_get_rx_buffer(rvdev, + &len, &idx); + + metal_mutex_release(&rdev->lock); + + while (rp_hdr) { + /* Get the channel node from the remote device channels list. */ + metal_mutex_acquire(&rdev->lock); + ept = rpmsg_get_ept_from_addr(rdev, rp_hdr->dst); + metal_mutex_release(&rdev->lock); + + if (!ept) + /* Fatal error no endpoint for the given dst addr. */ + return; + + if (ept->dest_addr == RPMSG_ADDR_ANY) { + /* + * First message received from the remote side, + * update channel destination address + */ + ept->dest_addr = rp_hdr->src; + } + status = ept->cb(ept, (void *)RPMSG_LOCATE_DATA(rp_hdr), + rp_hdr->len, ept->addr, ept->priv); + + RPMSG_ASSERT(status == RPMSG_SUCCESS, + "unexpected callback status\n"); + metal_mutex_acquire(&rdev->lock); + + /* Return used buffers. */ + rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); + + rp_hdr = (struct rpmsg_hdr *) + rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); + metal_mutex_release(&rdev->lock); + } +} + +/** + * rpmsg_virtio_ns_callback + * + * This callback handles name service announcement from the remote device + * and creates/deletes rpmsg channels. + * + * @param server_chnl - pointer to server channel control block. + * @param data - pointer to received messages + * @param len - length of received data + * @param priv - any private data + * @param src - source address + * + * @return - rpmag endpoint callback handled + */ +static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, + size_t len, uint32_t src, void *priv) +{ + struct rpmsg_device *rdev = ept->rdev; + struct rpmsg_virtio_device *rvdev = (struct rpmsg_virtio_device *)rdev; + struct metal_io_region *io = rvdev->shbuf_io; + struct rpmsg_endpoint *_ept; + struct rpmsg_ns_msg *ns_msg; + uint32_t dest; + char name[RPMSG_NAME_SIZE]; + + (void)priv; + (void)src; + + ns_msg = (struct rpmsg_ns_msg *)data; + if (len != sizeof(*ns_msg)) + /* Returns as the message is corrupted */ + return RPMSG_SUCCESS; + metal_io_block_read(io, + metal_io_virt_to_offset(io, ns_msg->name), + &name, sizeof(name)); + dest = ns_msg->addr; + + /* check if a Ept has been locally registered */ + metal_mutex_acquire(&rdev->lock); + _ept = rpmsg_get_endpoint(rdev, name, RPMSG_ADDR_ANY, dest); + + if (ns_msg->flags & RPMSG_NS_DESTROY) { + if (_ept) + _ept->dest_addr = RPMSG_ADDR_ANY; + metal_mutex_release(&rdev->lock); + if (_ept && _ept->ns_unbind_cb) + _ept->ns_unbind_cb(ept); + } else { + if (!_ept) { + /* + * send callback to application, that can + * - create the associated endpoints. + * - store information for future use. + * - just ignore the request as service not supported. + */ + metal_mutex_release(&rdev->lock); + if (rdev->ns_bind_cb) + rdev->ns_bind_cb(rdev, name, dest); + } else { + _ept->dest_addr = dest; + metal_mutex_release(&rdev->lock); + } + } + + return RPMSG_SUCCESS; +} + +int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev) +{ + int size; + struct rpmsg_virtio_device *rvdev; + + if (!rdev) + return RPMSG_ERR_PARAM; + metal_mutex_acquire(&rdev->lock); + rvdev = (struct rpmsg_virtio_device *)rdev; + size = _rpmsg_virtio_get_buffer_size(rvdev); + metal_mutex_release(&rdev->lock); + return size; +} + +int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool) +{ + struct rpmsg_device *rdev; + const char *vq_names[RPMSG_NUM_VRINGS]; + typedef void (*vqcallback)(struct virtqueue *vq); + vqcallback callback[RPMSG_NUM_VRINGS]; + unsigned long dev_features; + int status; + unsigned int i, role; + + rdev = &rvdev->rdev; + memset(rdev, 0, sizeof(*rdev)); + metal_mutex_init(&rdev->lock); + rvdev->vdev = vdev; + rdev->ns_bind_cb = ns_bind_cb; + vdev->priv = rvdev; + rdev->ops.send_offchannel_raw = rpmsg_virtio_send_offchannel_raw; + role = rpmsg_virtio_get_role(rvdev); + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + /* + * Since device is RPMSG Remote so we need to manage the + * shared buffers. Create shared memory pool to handle buffers. + */ + if (!shpool) + return RPMSG_ERR_PARAM; + if (!shpool->size) + return RPMSG_ERR_NO_BUFF; + rvdev->shpool = shpool; + + vq_names[0] = "rx_vq"; + vq_names[1] = "tx_vq"; + callback[0] = rpmsg_virtio_rx_callback; + callback[1] = rpmsg_virtio_tx_callback; + rvdev->rvq = vdev->vrings_info[0].vq; + rvdev->svq = vdev->vrings_info[1].vq; + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + +#ifndef VIRTIO_MASTER_ONLY + (void)shpool; + if (role == RPMSG_REMOTE) { + vq_names[0] = "tx_vq"; + vq_names[1] = "rx_vq"; + callback[0] = rpmsg_virtio_tx_callback; + callback[1] = rpmsg_virtio_rx_callback; + rvdev->rvq = vdev->vrings_info[1].vq; + rvdev->svq = vdev->vrings_info[0].vq; + } +#endif /*!VIRTIO_MASTER_ONLY*/ + rvdev->shbuf_io = shm_io; + +#ifndef VIRTIO_MASTER_ONLY + if (role == RPMSG_REMOTE) { + /* wait synchro with the master */ + rpmsg_virtio_wait_remote_ready(rvdev); + } +#endif /*!VIRTIO_MASTER_ONLY*/ + + /* Create virtqueues for remote device */ + status = rpmsg_virtio_create_virtqueues(rvdev, 0, RPMSG_NUM_VRINGS, + vq_names, callback); + if (status != RPMSG_SUCCESS) + return status; + + /* TODO: can have a virtio function to set the shared memory I/O */ + for (i = 0; i < RPMSG_NUM_VRINGS; i++) { + struct virtqueue *vq; + + vq = vdev->vrings_info[i].vq; + vq->shm_io = shm_io; + } + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) { + struct virtqueue_buf vqbuf; + unsigned int idx; + void *buffer; + + vqbuf.len = RPMSG_BUFFER_SIZE; + for (idx = 0; idx < rvdev->rvq->vq_nentries; idx++) { + /* Initialize TX virtqueue buffers for remote device */ + buffer = rpmsg_virtio_shm_pool_get_buffer(shpool, + RPMSG_BUFFER_SIZE); + + if (!buffer) { + return RPMSG_ERR_NO_BUFF; + } + + vqbuf.buf = buffer; + + metal_io_block_set(shm_io, + metal_io_virt_to_offset(shm_io, + buffer), + 0x00, RPMSG_BUFFER_SIZE); + status = + virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, + buffer); + + if (status != RPMSG_SUCCESS) { + return status; + } + } + } +#endif /*!VIRTIO_SLAVE_ONLY*/ + + /* Initialize channels and endpoints list */ + metal_list_init(&rdev->endpoints); + + dev_features = rpmsg_virtio_get_features(rvdev); + + /* + * Create name service announcement endpoint if device supports name + * service announcement feature. + */ + if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) { + rpmsg_init_ept(&rdev->ns_ept, "NS", + RPMSG_NS_EPT_ADDR, RPMSG_NS_EPT_ADDR, + rpmsg_virtio_ns_callback, NULL); + (void)rpmsg_register_endpoint(rdev, &rdev->ns_ept); + } + +#ifndef VIRTIO_SLAVE_ONLY + if (role == RPMSG_MASTER) + rpmsg_virtio_set_status(rvdev, VIRTIO_CONFIG_STATUS_DRIVER_OK); +#endif /*!VIRTIO_SLAVE_ONLY*/ + + return status; +} + +void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev) +{ + struct metal_list *node; + struct rpmsg_device *rdev; + struct rpmsg_endpoint *ept; + + rdev = &rvdev->rdev; + while (!metal_list_is_empty(&rdev->endpoints)) { + node = rdev->endpoints.next; + ept = metal_container_of(node, struct rpmsg_endpoint, node); + rpmsg_destroy_ept(ept); + } + + rvdev->rvq = 0; + rvdev->svq = 0; + + metal_mutex_deinit(&rdev->lock); +} diff --git a/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtio.c b/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtio.c index 3afb54e07b7e45..5cf87222b6bb44 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtio.c +++ b/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtio.c @@ -57,7 +57,7 @@ static const char *virtio_feature_name(unsigned long val, }; for (i = 0; i < 2; i++) { - if (descs[i] == NULL) + if (!descs[i]) continue; for (j = 0; descs[i][j].vfd_val != 0; j++) { @@ -79,3 +79,43 @@ void virtio_describe(struct virtio_device *dev, const char *msg, // TODO: Not used currently - keeping it for future use virtio_feature_name(0, desc); } + +int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback *callbacks[]) +{ + struct virtio_vring_info *vring_info; + struct vring_alloc_info *vring_alloc; + unsigned int num_vrings, i; + int ret; + (void)flags; + + num_vrings = vdev->vrings_num; + if (nvqs > num_vrings) + return -ERROR_VQUEUE_INVLD_PARAM; + /* Initialize virtqueue for each vring */ + for (i = 0; i < nvqs; i++) { + vring_info = &vdev->vrings_info[i]; + + vring_alloc = &vring_info->info; +#ifndef VIRTIO_SLAVE_ONLY + if (vdev->role == VIRTIO_DEV_MASTER) { + size_t offset; + struct metal_io_region *io = vring_info->io; + + offset = metal_io_virt_to_offset(io, + vring_alloc->vaddr); + metal_io_block_set(io, offset, 0, + vring_size(vring_alloc->num_descs, + vring_alloc->align)); + } +#endif + ret = virtqueue_create(vdev, i, names[i], vring_alloc, + callbacks[i], vdev->func->notify, + vring_info->vq); + if (ret) + return ret; + } + return 0; +} + diff --git a/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtqueue.c b/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtqueue.c index e12b0c4cd0a350..e90a6940b04ec6 100644 --- a/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtqueue.c +++ b/ext/lib/ipc/open-amp/open-amp/lib/virtio/virtqueue.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include @@ -17,13 +15,31 @@ static void vq_ring_init(struct virtqueue *, void *, int); static void vq_ring_update_avail(struct virtqueue *, uint16_t); static uint16_t vq_ring_add_buffer(struct virtqueue *, struct vring_desc *, - uint16_t, struct metal_sg *, int, int); + uint16_t, struct virtqueue_buf *, int, int); static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t); static void vq_ring_free_chain(struct virtqueue *, uint16_t); static int vq_ring_must_notify_host(struct virtqueue *vq); static void vq_ring_notify_host(struct virtqueue *vq); static int virtqueue_nused(struct virtqueue *vq); +/* Default implementation of P2V based on libmetal */ +static inline void *virtqueue_phys_to_virt(struct virtqueue *vq, + metal_phys_addr_t phys) +{ + struct metal_io_region *io = vq->shm_io; + + return metal_io_phys_to_virt(io, phys); +} + +/* Default implementation of V2P based on libmetal */ +static inline metal_phys_addr_t virtqueue_virt_to_phys(struct virtqueue *vq, + void *buf) +{ + struct metal_io_region *io = vq->shm_io; + + return metal_io_virt_to_phys(io, buf); +} + /** * virtqueue_create - Creates new VirtIO queue * @@ -35,46 +51,32 @@ static int virtqueue_nused(struct virtqueue *vq); * when message is available on VirtIO queue * @param notify - Pointer to notify function, used to notify * other side that there is job available for it - * @param shm_io - shared memory I/O region of the virtqueue - * @param v_queue - Created VirtIO queue. + * @param vq - Created VirtIO queue. * * @return - Function status */ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, const char *name, struct vring_alloc_info *ring, - void (*callback) (struct virtqueue * vq), - void (*notify) (struct virtqueue * vq), - struct metal_io_region *shm_io, - struct virtqueue **v_queue) + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue *vq) { - struct virtqueue *vq = NULL; int status = VQUEUE_SUCCESS; - uint32_t vq_size = 0; VQ_PARAM_CHK(ring == NULL, status, ERROR_VQUEUE_INVLD_PARAM); VQ_PARAM_CHK(ring->num_descs == 0, status, ERROR_VQUEUE_INVLD_PARAM); VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1), status, ERROR_VRING_ALIGN); + VQ_PARAM_CHK(vq == NULL, status, ERROR_NO_MEM); if (status == VQUEUE_SUCCESS) { - vq_size = sizeof(struct virtqueue) - + (ring->num_descs) * sizeof(struct vq_desc_extra); - vq = (struct virtqueue *)metal_allocate_memory(vq_size); - - if (vq == NULL) { - return (ERROR_NO_MEM); - } - - memset(vq, 0x00, vq_size); - vq->vq_dev = virt_dev; - strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ); + vq->vq_name = name; vq->vq_queue_index = id; vq->vq_nentries = ring->num_descs; vq->vq_free_cnt = vq->vq_nentries; vq->callback = callback; vq->notify = notify; - vq->shm_io = shm_io; /* Initialize vring control block in virtqueue. */ vq_ring_init(vq, (void *)ring->vaddr, ring->align); @@ -83,8 +85,6 @@ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, * once initialization is completed. */ virtqueue_disable_cb(vq); - - *v_queue = vq; } return (status); @@ -96,14 +96,14 @@ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, * inserted before writable buffers * * @param vq - Pointer to VirtIO queue control block. - * @param sg - Pointer to buffer scatter/gather list + * @param buf_list - Pointer to a list of virtqueue buffers. * @param readable - Number of readable buffers * @param writable - Number of writable buffers * @param cookie - Pointer to hold call back data * * @return - Function status */ -int virtqueue_add_buffer(struct virtqueue *vq, struct metal_sg *sg, +int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, int readable, int writable, void *cookie) { struct vq_desc_extra *dxp = NULL; @@ -121,22 +121,21 @@ int virtqueue_add_buffer(struct virtqueue *vq, struct metal_sg *sg, VQUEUE_BUSY(vq); if (status == VQUEUE_SUCCESS) { - VQASSERT(vq, cookie != NULL, "enqueuing with no cookie"); head_idx = vq->vq_desc_head_idx; VQ_RING_ASSERT_VALID_IDX(vq, head_idx); dxp = &vq->vq_descx[head_idx]; - VQASSERT(vq, (dxp->cookie == NULL), + VQASSERT(vq, dxp->cookie == NULL, "cookie already exists for index"); dxp->cookie = cookie; dxp->ndescs = needed; /* Enqueue buffer onto the ring. */ - idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx, sg, - readable, writable); + idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx, + buf_list, readable, writable); vq->vq_desc_head_idx = idx; vq->vq_free_cnt -= needed; @@ -156,74 +155,7 @@ int virtqueue_add_buffer(struct virtqueue *vq, struct metal_sg *sg, VQUEUE_IDLE(vq); - return (status); -} - -/** - * virtqueue_add_single_buffer - Enqueues single buffer in vring - * - * @param vq - Pointer to VirtIO queue control block - * @param cookie - Pointer to hold call back data - * @param sg - metal_scatter/gather struct element - * @param writable - If buffer writable - * @param has_next - If buffers for subsequent call are - * to be chained - * - * @return - Function status - */ -int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie, - struct metal_sg *sg, int writable, - boolean has_next) -{ - - struct vq_desc_extra *dxp; - struct vring_desc *dp; - uint16_t head_idx; - uint16_t idx; - int status = VQUEUE_SUCCESS; - - VQ_PARAM_CHK(vq == NULL, status, ERROR_VQUEUE_INVLD_PARAM); - VQ_PARAM_CHK(vq->vq_free_cnt == 0, status, ERROR_VRING_FULL); - - VQUEUE_BUSY(vq); - - if (status == VQUEUE_SUCCESS) { - - VQASSERT(vq, cookie != NULL, "enqueuing with no cookie"); - - head_idx = vq->vq_desc_head_idx; - dxp = &vq->vq_descx[head_idx]; - - dxp->cookie = cookie; - dxp->ndescs = 1; - idx = head_idx; - - dp = &vq->vq_ring.desc[idx]; - dp->addr = metal_io_virt_to_phys(sg->io, sg->virt); - dp->len = sg->len; - dp->flags = 0; - idx = dp->next; - - if (has_next) - dp->flags |= VRING_DESC_F_NEXT; - if (writable) - dp->flags |= VRING_DESC_F_WRITE; - - vq->vq_desc_head_idx = idx; - vq->vq_free_cnt--; - - if (vq->vq_free_cnt == 0) { - VQ_RING_ASSERT_CHAIN_TERM(vq); - } else { - VQ_RING_ASSERT_VALID_IDX(vq, idx); - } - - vq_ring_update_avail(vq, head_idx); - } - - VQUEUE_IDLE(vq); - - return (status); + return status; } /** @@ -235,13 +167,13 @@ int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie, * * @return - Pointer to used buffer */ -void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len, uint16_t * idx) +void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx) { struct vring_used_elem *uep; void *cookie; uint16_t used_idx, desc_idx; - if ((vq == NULL) || (vq->vq_used_cons_idx == vq->vq_ring.used->idx)) + if (!vq || vq->vq_used_cons_idx == vq->vq_ring.used->idx) return (NULL); VQUEUE_BUSY(vq); @@ -251,8 +183,8 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len, uint16_t * idx) atomic_thread_fence(memory_order_seq_cst); - desc_idx = (uint16_t) uep->id; - if (len != NULL) + desc_idx = (uint16_t)uep->id; + if (len) *len = uep->len; vq_ring_free_chain(vq, desc_idx); @@ -260,11 +192,11 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len, uint16_t * idx) cookie = vq->vq_descx[desc_idx].cookie; vq->vq_descx[desc_idx].cookie = NULL; - if (idx != NULL) + if (idx) *idx = used_idx; VQUEUE_IDLE(vq); - return (cookie); + return cookie; } uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx) @@ -280,8 +212,7 @@ uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx) */ void virtqueue_free(struct virtqueue *vq) { - if (vq != NULL) { - + if (vq) { if (vq->vq_free_cnt != vq->vq_nentries) { metal_log(METAL_LOG_WARNING, "%s: freeing non-empty virtqueue\r\n", @@ -302,15 +233,15 @@ void virtqueue_free(struct virtqueue *vq) * * @return - Pointer to available buffer */ -void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t * avail_idx, - uint32_t * len) +void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, + uint32_t *len) { uint16_t head_idx = 0; void *buffer; atomic_thread_fence(memory_order_seq_cst); if (vq->vq_available_idx == vq->vq_ring.avail->idx) { - return (NULL); + return NULL; } VQUEUE_BUSY(vq); @@ -318,12 +249,12 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t * avail_idx, head_idx = vq->vq_available_idx++ & (vq->vq_nentries - 1); *avail_idx = vq->vq_ring.avail->ring[head_idx]; - buffer = metal_io_phys_to_virt(vq->shm_io, vq->vq_ring.desc[*avail_idx].addr); + buffer = virtqueue_phys_to_virt(vq, vq->vq_ring.desc[*avail_idx].addr); *len = vq->vq_ring.desc[*avail_idx].len; VQUEUE_IDLE(vq); - return (buffer); + return buffer; } /** @@ -342,13 +273,13 @@ int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint16_t used_idx; if (head_idx > vq->vq_nentries) { - return (ERROR_VRING_NO_BUFF); + return ERROR_VRING_NO_BUFF; } VQUEUE_BUSY(vq); used_idx = vq->vq_ring.used->idx & (vq->vq_nentries - 1); - used_desc = &(vq->vq_ring.used->ring[used_idx]); + used_desc = &vq->vq_ring.used->ring[used_idx]; used_desc->id = head_idx; used_desc->len = len; @@ -358,7 +289,7 @@ int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, VQUEUE_IDLE(vq); - return (VQUEUE_SUCCESS); + return VQUEUE_SUCCESS; } /** @@ -370,7 +301,7 @@ int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, */ int virtqueue_enable_cb(struct virtqueue *vq) { - return (vq_ring_enable_interrupt(vq, 0)); + return vq_ring_enable_interrupt(vq, 0); } /** @@ -420,7 +351,7 @@ void virtqueue_kick(struct virtqueue *vq) */ void virtqueue_dump(struct virtqueue *vq) { - if (vq == NULL) + if (!vq) return; metal_log(METAL_LOG_DEBUG, @@ -441,7 +372,7 @@ void virtqueue_dump(struct virtqueue *vq) * * @return - Descriptor length */ -uint32_t virtqueue_get_desc_size(struct virtqueue * vq) +uint32_t virtqueue_get_desc_size(struct virtqueue *vq) { uint16_t head_idx = 0; uint16_t avail_idx = 0; @@ -459,7 +390,7 @@ uint32_t virtqueue_get_desc_size(struct virtqueue * vq) VQUEUE_IDLE(vq); - return (len); + return len; } /************************************************************************** @@ -473,7 +404,7 @@ uint32_t virtqueue_get_desc_size(struct virtqueue * vq) */ static uint16_t vq_ring_add_buffer(struct virtqueue *vq, struct vring_desc *desc, uint16_t head_idx, - struct metal_sg *sg, int readable, + struct virtqueue_buf *buf_list, int readable, int writable) { struct vring_desc *dp; @@ -485,19 +416,21 @@ static uint16_t vq_ring_add_buffer(struct virtqueue *vq, needed = readable + writable; for (i = 0, idx = head_idx; i < needed; i++, idx = dp->next) { - VQASSERT(vq, idx != VQ_RING_DESC_CHAIN_END, "premature end of free desc chain"); dp = &desc[idx]; - dp->addr = metal_io_virt_to_phys(sg[i].io, sg[i].virt); - dp->len = sg[i].len; + dp->addr = virtqueue_virt_to_phys(vq, buf_list[i].buf); + dp->len = buf_list[i].len; dp->flags = 0; if (i < needed - 1) dp->flags |= VRING_DESC_F_NEXT; - /* Readable buffers are inserted into vring before the writable buffers. */ + /* + * Readable buffers are inserted into vring before the + * writable buffers. + */ if (i >= readable) dp->flags |= VRING_DESC_F_WRITE; } @@ -618,10 +551,10 @@ static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) * entries. */ if (virtqueue_nused(vq) > ndesc) { - return (1); + return 1; } - return (0); + return 0; } /** @@ -632,7 +565,7 @@ static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) void virtqueue_notification(struct virtqueue *vq) { atomic_thread_fence(memory_order_seq_cst); - if (vq->callback != NULL) + if (vq->callback) vq->callback(vq); } @@ -663,7 +596,7 @@ static int vq_ring_must_notify_host(struct virtqueue *vq) */ static void vq_ring_notify_host(struct virtqueue *vq) { - if (vq->notify != NULL) + if (vq->notify) vq->notify(vq); } @@ -678,8 +611,8 @@ static int virtqueue_nused(struct virtqueue *vq) used_idx = vq->vq_ring.used->idx; - nused = (uint16_t) (used_idx - vq->vq_used_cons_idx); + nused = (uint16_t)(used_idx - vq->vq_used_cons_idx); VQASSERT(vq, nused <= vq->vq_nentries, "used more than available"); - return (nused); + return nused; } diff --git a/samples/subsys/ipc/openamp/CMakeLists.txt b/samples/subsys/ipc/openamp/CMakeLists.txt index aa29865873cbfb..7e4cde69bccbff 100644 --- a/samples/subsys/ipc/openamp/CMakeLists.txt +++ b/samples/subsys/ipc/openamp/CMakeLists.txt @@ -14,13 +14,7 @@ endif() enable_language(C ASM) -# Location of external dependencies: -set(PLATFORM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/platform") - -target_sources(app PRIVATE src/main_master.c - ${PLATFORM_DIR}/platform.c - ${PLATFORM_DIR}/platform_ops.c - ${PLATFORM_DIR}/resource_table.c) +target_sources(app PRIVATE src/main.c) include(ExternalProject) @@ -33,4 +27,4 @@ ExternalProject_Add( ) add_dependencies(core_m0_inc_target openamp_remote) -target_include_directories(app PRIVATE ${PLATFORM_DIR}) +target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/samples/subsys/ipc/openamp/common.h b/samples/subsys/ipc/openamp/common.h new file mode 100644 index 00000000000000..65ace6f12b8929 --- /dev/null +++ b/samples/subsys/ipc/openamp/common.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2018 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef COMMON_H__ +#define COMMON_H__ + +#define SHM_START_ADDR 0x04000400 +#define SHM_SIZE 0x7c00 +#define SHM_DEVICE_NAME "sramx.shm" + +#define VRING_COUNT 2 +#define VRING_RX_ADDRESS 0x04007800 +#define VRING_TX_ADDRESS 0x04007C00 +#define VRING_ALIGNMENT 4 +#define VRING_SIZE 16 + +#define OPENAMP_STATUS_ADDR 0x04000000 + +#endif diff --git a/samples/subsys/ipc/openamp/platform/platform.c b/samples/subsys/ipc/openamp/platform/platform.c deleted file mode 100644 index ba2833e6c4a5c9..00000000000000 --- a/samples/subsys/ipc/openamp/platform/platform.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include "platform.h" -#include "resource_table.h" - -extern struct hil_platform_ops platform_ops; - -static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDRESS }; -static struct metal_device shm_device = { - .name = SHM_DEVICE_NAME, - .bus = NULL, - .num_regions = 1, - { - { - .virt = (void *) SHM_START_ADDRESS, - .physmap = shm_physmap, - .size = SHM_SIZE, - .page_shift = 0xffffffff, - .page_mask = 0xffffffff, - .mem_flags = 0, - .ops = { NULL }, - }, - }, - .node = { NULL }, - .irq_num = 0, - .irq_info = NULL -}; - -struct hil_proc *platform_init(int role) -{ - int status; - - status = metal_register_generic_device(&shm_device); - if (status != 0) { - printk("metal_register_generic_device(): could not register " - "shared memory device: error code %d\n", status); - return NULL; - } - - struct hil_proc *proc = hil_create_proc(&platform_ops, - role != RPMSG_MASTER, NULL); - if (proc == NULL) { - printk("platform_create(): could not allocate hil_proc\n"); - return NULL; - } - - hil_set_shm(proc, "generic", SHM_DEVICE_NAME, SHM_START_ADDRESS, - SHM_SIZE); - return proc; -} diff --git a/samples/subsys/ipc/openamp/platform/platform.h b/samples/subsys/ipc/openamp/platform/platform.h deleted file mode 100644 index f1f25e1d34a334..00000000000000 --- a/samples/subsys/ipc/openamp/platform/platform.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef PLATFORM_H__ -#define PLATFORM_H__ - -#include - -#define SHM_START_ADDRESS 0x04000400 -#define SHM_SIZE 0x7c00 -#define SHM_DEVICE_NAME "sramx.shm" - -#define VRING_COUNT 2 -#define VRING_RX_ADDRESS 0x04007800 -#define VRING_TX_ADDRESS 0x04007C00 -#define VRING_ALIGNMENT 4 -#define VRING_SIZE 16 - -struct hil_proc *platform_init(int role); - -#endif - diff --git a/samples/subsys/ipc/openamp/platform/platform_ops.c b/samples/subsys/ipc/openamp/platform/platform_ops.c deleted file mode 100644 index da0afb3d18da8c..00000000000000 --- a/samples/subsys/ipc/openamp/platform/platform_ops.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - * - * Implement the HIL layer required by OpenAMP - */ - -#include -#include - -#include -#include "platform.h" - -static K_SEM_DEFINE(data_sem, 0, 1); -static struct device *ipm_handle; - -static void platform_ipm_callback(void *context, u32_t id, volatile void *data) -{ - k_sem_give(&data_sem); -} - -static int enable_interrupt(struct proc_intr *intr) -{ - return ipm_set_enabled(ipm_handle, 1); -} - -static void notify(struct hil_proc *proc, struct proc_intr *intr_info) -{ - u32_t dummy_data = 0x12345678; /* Some data must be provided */ - - ipm_send(ipm_handle, 0, 0, &dummy_data, sizeof(dummy_data)); -} - -static int boot_cpu(struct hil_proc *proc, unsigned int load_addr) -{ - return -1; -} - -static void shutdown_cpu(struct hil_proc *proc) -{ -} - -static int poll(struct hil_proc *proc, int nonblock) -{ - int status = k_sem_take(&data_sem, nonblock ? K_NO_WAIT : K_FOREVER); - - if (status == 0) { - hil_notified(proc, 0xffffffff); - } - - return status; -} - -static struct metal_io_region *alloc_shm(struct hil_proc *proc, - metal_phys_addr_t physical, - size_t size, - struct metal_device **device) -{ - int status = metal_device_open("generic", SHM_DEVICE_NAME, device); - - if (status != 0) { - return NULL; - } - - return metal_device_io_region(*device, 0); -} - -static void release_shm(struct hil_proc *proc, struct metal_device *device, - struct metal_io_region *io) -{ - metal_device_close(device); -} - -static int initialize(struct hil_proc *proc) -{ - ipm_handle = device_get_binding("MAILBOX_0"); - if (!ipm_handle) { - return -1; - } - - ipm_register_callback(ipm_handle, platform_ipm_callback, NULL); - return 0; -} - -static void release(struct hil_proc *proc) -{ - ipm_set_enabled(ipm_handle, 0); -} - -struct hil_platform_ops platform_ops = { - .enable_interrupt = enable_interrupt, - .notify = notify, - .boot_cpu = boot_cpu, - .shutdown_cpu = shutdown_cpu, - .poll = poll, - .alloc_shm = alloc_shm, - .release_shm = release_shm, - .initialize = initialize, - .release = release -}; diff --git a/samples/subsys/ipc/openamp/platform/resource_table.c b/samples/subsys/ipc/openamp/platform/resource_table.c deleted file mode 100644 index dbc14d68e06c4e..00000000000000 --- a/samples/subsys/ipc/openamp/platform/resource_table.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - * - * Implement the resource table that will get parsed by OpenAMP to convey - * the shared memory region used for message passing and ring setup. - */ - -#include "platform.h" -#include "resource_table.h" - -struct lpc_resource_table *rsc_table_ptr = (void *) RSC_TABLE_ADDRESS; - -#if defined(CPU_LPC54114J256BD64_cm4) -static const struct lpc_resource_table rsc_table = { - .ver = 1, - .num = 2, - .offset = { - offsetof(struct lpc_resource_table, mem), - offsetof(struct lpc_resource_table, vdev), - }, - .mem = { - RSC_RPROC_MEM, SHM_START_ADDRESS, SHM_START_ADDRESS, SHM_SIZE, - 0, - }, - - .vdev = { - RSC_VDEV, VIRTIO_ID_RPMSG, 0, 1 << VIRTIO_RPMSG_F_NS, 0, 0, 0, - VRING_COUNT, { 0, 0 }, - }, - - .vring0 = { VRING_TX_ADDRESS, VRING_ALIGNMENT, VRING_SIZE, 1, 0 }, - .vring1 = { VRING_RX_ADDRESS, VRING_ALIGNMENT, VRING_SIZE, 2, 0 }, -}; -#endif - -void resource_table_init(void **table_ptr, int *length) -{ -#if defined(CPU_LPC54114J256BD64_cm4) - /* Master: copy the resource table to shared memory. */ - memcpy(rsc_table_ptr, &rsc_table, sizeof(struct lpc_resource_table)); -#endif - - *length = sizeof(struct lpc_resource_table); - *table_ptr = rsc_table_ptr; -} diff --git a/samples/subsys/ipc/openamp/platform/resource_table.h b/samples/subsys/ipc/openamp/platform/resource_table.h deleted file mode 100644 index c647bb06dfbd4c..00000000000000 --- a/samples/subsys/ipc/openamp/platform/resource_table.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef RESOURCE_TABLE_H__ -#define RESOURCE_TABLE_H__ - -#include - -#define RSC_TABLE_ADDRESS 0x04000000 - -OPENAMP_PACKED_BEGIN -struct lpc_resource_table { - uint32_t ver; - uint32_t num; - uint32_t reserved[2]; - uint32_t offset[2]; - struct fw_rsc_rproc_mem mem; - struct fw_rsc_vdev vdev; - struct fw_rsc_vdev_vring vring0, vring1; -} OPENAMP_PACKED_END; - -void resource_table_init(void **table_ptr, int *length); - -#endif - diff --git a/samples/subsys/ipc/openamp/remote/CMakeLists.txt b/samples/subsys/ipc/openamp/remote/CMakeLists.txt index 7c8be92f778ecb..9482cff9d961a7 100644 --- a/samples/subsys/ipc/openamp/remote/CMakeLists.txt +++ b/samples/subsys/ipc/openamp/remote/CMakeLists.txt @@ -5,8 +5,6 @@ cmake_minimum_required(VERSION 3.8.2) # set(BOARD lpcxpresso54114_m0) -set(PLATFORM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../platform") - include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) project(openamp_remote) @@ -14,9 +12,5 @@ if(NOT ("${BOARD}" STREQUAL "lpcxpresso54114_m0")) message(FATAL_ERROR "${BOARD} was specified, but this sample only supports lpcxpresso54114_m0") endif() -target_sources(app PRIVATE src/main_remote.c - ${PLATFORM_DIR}/platform.c - ${PLATFORM_DIR}/resource_table.c - ${PLATFORM_DIR}/platform_ops.c) - -target_include_directories(app PRIVATE ${PLATFORM_DIR}) +target_sources(app PRIVATE src/main.c) +target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) diff --git a/samples/subsys/ipc/openamp/remote/prj.conf b/samples/subsys/ipc/openamp/remote/prj.conf index 164a38f92ecae6..7a08439febe6dc 100644 --- a/samples/subsys/ipc/openamp/remote/prj.conf +++ b/samples/subsys/ipc/openamp/remote/prj.conf @@ -5,3 +5,4 @@ CONFIG_IPM_MCUX=y CONFIG_PLATFORM_SPECIFIC_INIT=n CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_OPENAMP=y +CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096 diff --git a/samples/subsys/ipc/openamp/remote/src/main.c b/samples/subsys/ipc/openamp/remote/src/main.c new file mode 100644 index 00000000000000..b7d2397dbd003d --- /dev/null +++ b/samples/subsys/ipc/openamp/remote/src/main.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2018, NXP + * Copyright (c) 2018, Nordic Semiconductor ASA + * Copyright (c) 2018, Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +#define APP_TASK_STACK_SIZE (1024) +K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); +static struct k_thread thread_data; + +static struct device *ipm_handle; + +static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR }; +static struct metal_device shm_device = { + .name = SHM_DEVICE_NAME, + .bus = NULL, + .num_regions = 1, + { + { + .virt = (void *) SHM_START_ADDR, + .physmap = shm_physmap, + .size = SHM_SIZE, + .page_shift = 0xffffffff, + .page_mask = 0xffffffff, + .mem_flags = 0, + .ops = { NULL }, + }, + }, + .node = { NULL }, + .irq_num = 0, + .irq_info = NULL +}; + +static volatile unsigned int received_data; + +static struct virtio_vring_info rvrings[2] = { + [0] = { + .info.align = VRING_ALIGNMENT, + }, + [1] = { + .info.align = VRING_ALIGNMENT, + }, +}; +static struct virtio_device vdev; +static struct rpmsg_virtio_device rvdev; +static struct metal_io_region *io; +static struct virtqueue *vq[2]; + +static unsigned char virtio_get_status(struct virtio_device *vdev) +{ + return sys_read8(OPENAMP_STATUS_ADDR); +} + +static u32_t virtio_get_features(struct virtio_device *vdev) +{ + return 1 << VIRTIO_RPMSG_F_NS; +} + +static void virtio_notify(struct virtqueue *vq) +{ + u32_t dummy_data = 0x00110011; /* Some data must be provided */ + + ipm_send(ipm_handle, 0, 0, &dummy_data, sizeof(dummy_data)); +} + +struct virtio_dispatch dispatch = { + .get_status = virtio_get_status, + .get_features = virtio_get_features, + .notify = virtio_notify, +}; + +static K_SEM_DEFINE(data_sem, 0, 1); +static K_SEM_DEFINE(data_rx_sem, 0, 1); + +static void platform_ipm_callback(void *context, u32_t id, volatile void *data) +{ + k_sem_give(&data_sem); +} + +int endpoint_cb(struct rpmsg_endpoint *ept, void *data, + size_t len, u32_t src, void *priv) +{ + received_data = *((unsigned int *) data); + + k_sem_give(&data_rx_sem); + + return RPMSG_SUCCESS; +} + +static K_SEM_DEFINE(ept_sem, 0, 1); + +struct rpmsg_endpoint my_ept; +struct rpmsg_endpoint *ep = &my_ept; + +static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) +{ + (void)ept; + rpmsg_destroy_ept(ep); +} + +static unsigned int receive_message(void) +{ + while (k_sem_take(&data_rx_sem, K_NO_WAIT) != 0) { + int status = k_sem_take(&data_sem, K_FOREVER); + + if (status == 0) { + virtqueue_notification(vq[1]); + } + } + return received_data; +} + +static int send_message(unsigned int message) +{ + return rpmsg_send(ep, &message, sizeof(message)); +} + +void app_task(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + int status = 0; + unsigned int message = 0; + struct metal_device *device; + struct rpmsg_device *rdev; + struct metal_init_params metal_params = METAL_INIT_DEFAULTS; + + printk("\r\nOpenAMP[remote] demo started\r\n"); + + status = metal_init(&metal_params); + if (status != 0) { + printk("metal_init: failed - error code %d\n", status); + return; + } + + status = metal_register_generic_device(&shm_device); + if (status != 0) { + printk("Couldn't register shared memory device: %d\n", status); + return; + } + + status = metal_device_open("generic", SHM_DEVICE_NAME, &device); + if (status != 0) { + printk("metal_device_open failed: %d\n", status); + return; + } + + io = metal_device_io_region(device, 0); + if (io == NULL) { + printk("metal_device_io_region failed to get region\n"); + return; + } + + /* setup IPM */ + ipm_handle = device_get_binding("MAILBOX_0"); + if (ipm_handle == NULL) { + printk("device_get_binding failed to find device\n"); + return; + } + + ipm_register_callback(ipm_handle, platform_ipm_callback, NULL); + + status = ipm_set_enabled(ipm_handle, 1); + if (status != 0) { + printk("ipm_set_enabled failed\n"); + return; + } + + /* setup vdev */ + vq[0] = virtqueue_allocate(VRING_SIZE); + if (vq[0] == NULL) { + printk("virtqueue_allocate failed to alloc vq[0]\n"); + return; + } + vq[1] = virtqueue_allocate(VRING_SIZE); + if (vq[1] == NULL) { + printk("virtqueue_allocate failed to alloc vq[1]\n"); + return; + } + + vdev.role = RPMSG_REMOTE; + vdev.vrings_num = VRING_COUNT; + vdev.func = &dispatch; + rvrings[0].io = io; + rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS; + rvrings[0].info.num_descs = VRING_SIZE; + rvrings[0].info.align = VRING_ALIGNMENT; + rvrings[0].vq = vq[0]; + + rvrings[1].io = io; + rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS; + rvrings[1].info.num_descs = VRING_SIZE; + rvrings[1].info.align = VRING_ALIGNMENT; + rvrings[1].vq = vq[1]; + + vdev.vrings_info = &rvrings[0]; + + /* setup rvdev */ + status = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL); + if (status != 0) { + printk("rpmsg_init_vdev failed %d\n", status); + return; + } + + rdev = rpmsg_virtio_get_rpmsg_device(&rvdev); + + status = rpmsg_create_ept(ep, rdev, "k", RPMSG_ADDR_ANY, + RPMSG_ADDR_ANY, endpoint_cb, rpmsg_service_unbind); + if (status != 0) { + printk("rpmsg_create_ept failed %d\n", status); + return; + } + + while (message < 99) { + message = receive_message(); + printk("Remote core received a message: %d\n", message); + + message++; + status = send_message(message); + if (status < 0) { + printk("send_message(%d) failed with status %d\n", + message, status); + goto _cleanup; + } + } + +_cleanup: + rpmsg_deinit_vdev(&rvdev); + metal_finish(); + + printk("OpenAMP demo ended.\n"); +} + +void main(void) +{ + printk("Starting application thread!\n"); + k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, + (k_thread_entry_t)app_task, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); +} diff --git a/samples/subsys/ipc/openamp/remote/src/main_remote.c b/samples/subsys/ipc/openamp/remote/src/main_remote.c deleted file mode 100644 index a7a4b06f19ee87..00000000000000 --- a/samples/subsys/ipc/openamp/remote/src/main_remote.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2018, NXP - * Copyright (c) 2018 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - * - * This implements the remote side of an OpenAMP system. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "platform.h" -#include "resource_table.h" - -#define APP_TASK_STACK_SIZE (512) -K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); -static struct k_thread thread_data; - -static K_SEM_DEFINE(channel_created, 0, 1); - -static K_SEM_DEFINE(message_received, 0, 1); -static volatile unsigned int received_data; - -static struct rsc_table_info rsc_info; -static struct hil_proc *proc; - -static struct rpmsg_channel *rp_channel; -static struct rpmsg_endpoint *rp_endpoint; - -static void rpmsg_recv_callback(struct rpmsg_channel *channel, void *data, - int data_length, void *private, - unsigned long src) -{ - received_data = *((unsigned int *) data); - k_sem_give(&message_received); -} - -static void rpmsg_channel_created(struct rpmsg_channel *channel) -{ - rp_channel = channel; - rp_endpoint = rpmsg_create_ept(rp_channel, rpmsg_recv_callback, - RPMSG_NULL, RPMSG_ADDR_ANY); - k_sem_give(&channel_created); -} - -static void rpmsg_channel_deleted(struct rpmsg_channel *channel) -{ - rpmsg_destroy_ept(rp_endpoint); -} - -static unsigned int receive_message(void) -{ - while (k_sem_take(&message_received, K_NO_WAIT) != 0) - hil_poll(proc, 0); - return received_data; -} - -static int send_message(unsigned int message) -{ - return rpmsg_send(rp_channel, &message, sizeof(message)); -} - -void app_task(void *arg1, void *arg2, void *arg3) -{ - ARG_UNUSED(arg1); - ARG_UNUSED(arg2); - ARG_UNUSED(arg3); - - struct metal_init_params metal_params = METAL_INIT_DEFAULTS; - - metal_init(&metal_params); - - proc = platform_init(RPMSG_REMOTE); - if (proc == NULL) { - goto _cleanup; - } - - resource_table_init((void **) &rsc_info.rsc_tab, &rsc_info.size); - - struct remote_proc *rproc_ptr = NULL; - int status = remoteproc_resource_init(&rsc_info, proc, - rpmsg_channel_created, - rpmsg_channel_deleted, - rpmsg_recv_callback, - &rproc_ptr, RPMSG_REMOTE); - if (status != 0) { - goto _cleanup; - } - - while (k_sem_take(&channel_created, K_NO_WAIT) != 0) - hil_poll(proc, 0); - - unsigned int message = 0U; - - while (message <= 100) { - message = receive_message(); - message++; - status = send_message(message); - if (status <= 0) { - goto _cleanup; - } - } - -_cleanup: - if (rproc_ptr) { - remoteproc_resource_deinit(rproc_ptr); - } -} - -void main(void) -{ - k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)app_task, - NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); -} diff --git a/samples/subsys/ipc/openamp/remote_echo/CMakeLists.txt b/samples/subsys/ipc/openamp/remote_echo/CMakeLists.txt new file mode 100644 index 00000000000000..306821803ccfce --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.8.2) +# Copyright (c) 2018 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +macro(set_conf_file) + if(EXISTS ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf) + set(CONF_FILE "prj.conf ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf") + else() + set(CONF_FILE "prj.conf") + endif() +endmacro() + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(openamp_remote_echo) + +target_sources(app PRIVATE src/main.c) +target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/samples/subsys/ipc/openamp/remote_echo/README.rst b/samples/subsys/ipc/openamp/remote_echo/README.rst new file mode 100644 index 00000000000000..09b54006ddba7d --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/README.rst @@ -0,0 +1,142 @@ +.. _openAMP_remote_echo_sample: + +OpenAMP Remote Echo Sample Application +###################################### + +Overview +******** + +This sample application demonstrates how to integrate coding and building of +OpenAMP with Zephyr. Currently this integration is specific to the i.MX7 and +i.MX6 SoCs and the Master side (Cortex-A) should be running Linux with the i.MX +RPMsg and mailbox driver. + + +Building the application +************************* + +.. zephyr-app-commands:: + :zephyr-app: samples/subsys/ipc/openamp/remote_echo + :board: colibri_imx7d_m4 warp7_m4 udoo_neo_full_m4 + :goals: build flash + + +On the Linux side (Master) make sure you have the following Linux kernel config +options enabled: + +.. code-block:: none + + CONFIG_HAVE_IMX_MU=y + CONFIG_HAVE_IMX_RPMSG=y + CONFIG_RPMSG=y + CONFIG_RPMSG_VIRTIO=y + CONFIG_IMX_RPMSG_TTY=m + + +And make sure that you have the following Linux devitree nodes: + +.. code-block:: none + + i.MX7 - arch/arm/boot/dts/imx7s.dtsi: + mu: mu@30aa0000 { + compatible = "fsl,imx7d-mu", "fsl,imx6sx-mu"; + reg = <0x30aa0000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_MU_ROOT_CLK>; + clock-names = "mu"; + status = "okay"; + }; + + rpmsg: rpmsg{ + compatible = "fsl,imx7d-rpmsg"; + status = "disabled"; + }; + + + i.MX6SX - arch/arm/boot/dts/imx6sx.dtsi: + mu: mu@02294000 { + compatible = "fsl,imx6sx-mu"; + reg = <0x02294000 0x4000>; + interrupts = <0 90 0x04>; + status = "okay"; + }; + + rpmsg: rpmsg{ + compatible = "fsl,imx6sx-rpmsg"; + status = "disabled"; + }; + + + BOARD - arch/arm/boot/dts/.dts: + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + rpmsg_reserved: rpmsg@8fff0000 { + No-map; + reg = <0x8fff0000 0x10000>; + }; + }; + + &rpmsg { + vdev-nums = <1>; + reg = <0x8fff0000 0x10000>; + status = "okay"; + }; + + &uart2 { // adjust to the Zephyr uart console number of your board + status = "disabled"; + }; + + +You can use this repository as a reference: + +https://github.com/diegosueiro/linux-fslc/tree/4.9-1.0.x-imx + + +Open a serial terminal (minicom, putty, etc.) and connect the board with the +following settings for UART_2 for the colibri_imx7d_m4 and warp7_m4 boards, and +UART_5 for the udoo_neo_full_m4 board: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Here are the instructions to load and run Zephyr on M4 from A7 using u-boot. + +Copy the compiled ``zephyr.bin`` to the first EXT partition of the SD card and +plug the SD card into the board. Power up the board and stop the u-boot +execution. Set the u-boot environment variables and run the ``zephyr.bin`` from +the TCML memory, as described here: + +.. code-block:: console + + setenv bootm4 'ext4load mmc 0:1 $m4addr $m4fw && dcache flush && bootaux $m4addr' + setenv m4tcml 'setenv m4fw zephyr.bin; setenv m4addr 0x007F8000' + setenv bootm4tcml 'run m4tcml && run bootm4' + run bootm4tcml + run bootcmd + +In the Linux console load the imx_rpmsg_tty module: + +.. code-block:: console + + modprobe imx_rpmsg_tty + +And in the Zephyr console you should see: + +.. code-block:: console + + ***** Booting Zephyr OS zephyr-v1.13.0-2189-gdda6786 ***** + Starting application thread! + + OpenAMP remote echo demo started + echo message: hello world! + +You can use microcom on the Linux side to send and receive the characters: + +.. code-block:: console + + microcom /dev/ttyRPMSG diff --git a/samples/subsys/ipc/openamp/remote_echo/boards/colibri_imx7d_m4.conf b/samples/subsys/ipc/openamp/remote_echo/boards/colibri_imx7d_m4.conf new file mode 100644 index 00000000000000..e5fabe8d0e5a4a --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/boards/colibri_imx7d_m4.conf @@ -0,0 +1,3 @@ +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_IPM_IMX=y +CONFIG_IPM_IMX_MAX_DATA_SIZE_4=y diff --git a/samples/subsys/ipc/openamp/remote_echo/boards/udoo_neo_full_m4.conf b/samples/subsys/ipc/openamp/remote_echo/boards/udoo_neo_full_m4.conf new file mode 100644 index 00000000000000..e5fabe8d0e5a4a --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/boards/udoo_neo_full_m4.conf @@ -0,0 +1,3 @@ +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_IPM_IMX=y +CONFIG_IPM_IMX_MAX_DATA_SIZE_4=y diff --git a/samples/subsys/ipc/openamp/remote_echo/boards/warp7_m4.conf b/samples/subsys/ipc/openamp/remote_echo/boards/warp7_m4.conf new file mode 100644 index 00000000000000..e5fabe8d0e5a4a --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/boards/warp7_m4.conf @@ -0,0 +1,3 @@ +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_IPM_IMX=y +CONFIG_IPM_IMX_MAX_DATA_SIZE_4=y diff --git a/samples/subsys/ipc/openamp/remote_echo/common.h b/samples/subsys/ipc/openamp/remote_echo/common.h new file mode 100644 index 00000000000000..a51f945ce5e6b8 --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/common.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018 Diego Sueiro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef COMMOM_H__ +#define COMMON_H__ + +#define RPMSG_CHAN_NAME "rpmsg-openamp-demo-channel" + +#if defined(CONFIG_SOC_SERIES_IMX7_M4) || defined(CONFIG_SOC_SERIES_IMX_6X_M4) +/* Values aligned with Linux Master side implementation */ +#define SHM_START_ADDR 0x90040000 +#define SHM_SIZE 0x40000 +#define SHM_DEVICE_NAME "ddr.shm" + +#define VRING_COUNT 2 +#define VRING_TX_ADDRESS 0x8fff0000 +#define VRING_RX_ADDRESS 0x8fff8000 +#define VRING_ALIGNMENT 0x1000 +#define VRING_SIZE 256 + +#define IPM_LABEL DT_IPM_IMX_MU_B_NAME +#define RPMSG_MU_CHANNEL 1 + +#else +#error "Current SoC not support" +#endif + +#endif /* COMMON_H__ */ diff --git a/samples/subsys/ipc/openamp/remote_echo/prj.conf b/samples/subsys/ipc/openamp/remote_echo/prj.conf new file mode 100644 index 00000000000000..2466530f75450e --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/prj.conf @@ -0,0 +1,6 @@ +CONFIG_STDOUT_CONSOLE=y +CONFIG_PRINTK=y +CONFIG_IPM=y +CONFIG_PLATFORM_SPECIFIC_INIT=n +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_OPENAMP=y diff --git a/samples/subsys/ipc/openamp/remote_echo/sample.yaml b/samples/subsys/ipc/openamp/remote_echo/sample.yaml new file mode 100644 index 00000000000000..88c8bb4de44565 --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/sample.yaml @@ -0,0 +1,10 @@ +sample: + description: This app provides an example of how to integrate OpenAMP + with Zephyr. + name: OpenAMP remote echo example +tests: + test: + build_only: true + filter: CONFIG_SOC_FAMILY_IMX + platform_whitelist: colibri_imx7d_m4 warp7_m4 udoo_neo_full_m4 + tags: samples ipm diff --git a/samples/subsys/ipc/openamp/remote_echo/src/main.c b/samples/subsys/ipc/openamp/remote_echo/src/main.c new file mode 100644 index 00000000000000..67206f7ae1e475 --- /dev/null +++ b/samples/subsys/ipc/openamp/remote_echo/src/main.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2018, NXP + * Copyright (c) 2018, Nordic Semiconductor ASA + * Copyright (c) 2018, Linaro Limited + * Copyright (c) 2018, Diego Sueiro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +#define APP_TASK_STACK_SIZE (1024) +K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); +static struct k_thread thread_data; + +static int shutdown_req; +static unsigned int virtio_status; + +static struct device *ipm_handle; + +static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR }; +static struct metal_device shm_device = { + .name = SHM_DEVICE_NAME, + .bus = NULL, + .num_regions = 1, + { + { + .virt = (void *) SHM_START_ADDR, + .physmap = shm_physmap, + .size = SHM_SIZE, + .page_shift = 0xffffffff, + .page_mask = 0xffffffff, + .mem_flags = 0, + .ops = { NULL }, + }, + }, + .node = { NULL }, + .irq_num = 0, + .irq_info = NULL +}; + +static volatile unsigned int received_data; + +static struct virtio_vring_info rvrings[2] = { + [0] = { + .info.align = VRING_ALIGNMENT, + }, + [1] = { + .info.align = VRING_ALIGNMENT, + }, +}; + +static struct virtio_device vdev; +static struct rpmsg_virtio_device rvdev; +static struct metal_io_region *io; +static struct virtqueue *vq[2]; + +static unsigned char virtio_get_status(struct virtio_device *vdev) +{ + return virtio_status; +} + +static u32_t virtio_get_features(struct virtio_device *vdev) +{ + return 1 << VIRTIO_RPMSG_F_NS; +} + +static void virtio_set_features(struct virtio_device *vdev, + u32_t features) +{ +} + +static void virtio_notify(struct virtqueue *vq) +{ + /* Aligned with the i.MX RPMsg Linux Driver where the bit 16 is + * used to notify the message direction. + */ + u32_t vq_id = ((vq->vq_queue_index)&0x1) << 16; + + ipm_send(ipm_handle, 0, RPMSG_MU_CHANNEL, &vq_id, sizeof(vq_id)); +} + +struct virtio_dispatch dispatch = { + .get_status = virtio_get_status, + .get_features = virtio_get_features, + .set_features = virtio_set_features, + .notify = virtio_notify, +}; + +static K_SEM_DEFINE(data_sem, 0, 1); +static K_SEM_DEFINE(data_rx_sem, 0, 1); +static K_SEM_DEFINE(ept_sem, 0, 1); + +struct rpmsg_endpoint my_ept; +struct rpmsg_endpoint *ep = &my_ept; + +static void platform_ipm_callback(void *context, u32_t id, volatile void *data) +{ + /* After receiving the first ipm message from the Linux master we assume + * that the driver status is OK since the i.MX RPMsg Linux Driver + * doesn't implement a set_status callback function. + */ + if (!virtio_status) { + virtio_status = VIRTIO_CONFIG_STATUS_DRIVER_OK; + } + + k_sem_give(&data_sem); +} + +int endpoint_cb(struct rpmsg_endpoint *ept, void *data, + size_t len, u32_t src, void *priv) +{ + ARG_UNUSED(priv); + ARG_UNUSED(src); + char payload[RPMSG_BUFFER_SIZE]; + + /* Send data back to master */ + memset(payload, 0, RPMSG_BUFFER_SIZE); + memcpy(payload, data, len); + + printk("echo message: %s\n", payload); + if (rpmsg_send(ept, (char *)data, len) < 0) { + printk("rpmsg_send failed\n"); + goto destroy_ept; + } + + k_sem_give(&data_rx_sem); + + return RPMSG_SUCCESS; + +destroy_ept: + shutdown_req = 1; + k_sem_give(&data_rx_sem); + return RPMSG_SUCCESS; +} + + +static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) +{ + ARG_UNUSED(ept); + rpmsg_destroy_ept(ep); +} + +static void loopback_messages(void) +{ + while (k_sem_take(&data_rx_sem, K_NO_WAIT) != 0) { + int status = k_sem_take(&data_sem, K_FOREVER); + + if (status == 0) { + virtqueue_notification(vq[1]); + } + } +} + +void app_task(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + int status = 0; + struct metal_device *device; + struct rpmsg_device *rdev; + struct metal_init_params metal_params = METAL_INIT_DEFAULTS; + + shutdown_req = 0; + virtio_status = 0; + + status = metal_init(&metal_params); + if (status != 0) { + printk("metal_init failed: %d\n", status); + return; + } + + status = metal_register_generic_device(&shm_device); + if (status != 0) { + printk("Couldn't register shared memory device: %d\n", status); + metal_finish(); + return; + } + + status = metal_device_open("generic", SHM_DEVICE_NAME, &device); + if (status != 0) { + printk("metal_device_open failed: %d\n", status); + metal_finish(); + return; + } + + io = metal_device_io_region(device, 0); + if (io == NULL) { + printk("metal_device_io_region failed\n"); + metal_finish(); + return; + } + + /* setup IPM */ + ipm_handle = device_get_binding(IPM_LABEL); + if (ipm_handle == NULL) { + printk("device_get_binding %s failed\n", IPM_LABEL); + metal_finish(); + return; + } + + ipm_register_callback(ipm_handle, platform_ipm_callback, NULL); + + status = ipm_set_enabled(ipm_handle, 1); + if (status != 0) { + printk("ipm_set_enabled failed: %d\n", status); + metal_finish(); + return; + } + + /* setup vdev */ + vq[0] = virtqueue_allocate(VRING_SIZE); + if (vq[0] == NULL) { + printk("vq[0] virtqueue_allocate size %d failed\n", VRING_SIZE); + metal_finish(); + return; + } + vq[1] = virtqueue_allocate(VRING_SIZE); + if (vq[1] == NULL) { + printk("vq[1] virtqueue_allocate size %d failed\n", VRING_SIZE); + virtqueue_free(vq[0]); + metal_finish(); + return; + } + + vdev.role = RPMSG_REMOTE; + vdev.vrings_num = VRING_COUNT; + vdev.func = &dispatch; + rvrings[0].io = io; + rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS; + rvrings[0].info.num_descs = VRING_SIZE; + rvrings[0].info.align = VRING_ALIGNMENT; + rvrings[0].vq = vq[0]; + + rvrings[1].io = io; + rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS; + rvrings[1].info.num_descs = VRING_SIZE; + rvrings[1].info.align = VRING_ALIGNMENT; + rvrings[1].vq = vq[1]; + + vdev.vrings_info = &rvrings[0]; + + /* setup rvdev */ + status = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL); + if (status != 0) { + printk("rpmsg_init_vdev failed: %d\n", status); + virtqueue_free(vq[0]); + virtqueue_free(vq[1]); + metal_finish(); + return; + } + rdev = rpmsg_virtio_get_rpmsg_device(&rvdev); + + status = rpmsg_create_ept(ep, rdev, RPMSG_CHAN_NAME, RPMSG_ADDR_ANY, + RPMSG_ADDR_ANY, endpoint_cb, + rpmsg_service_unbind); + if (status != 0) { + printk("rpmsg_create_ept failed: %d\n", status); + goto _cleanup; + } + + printk("\r\nOpenAMP remote echo demo started\r\n"); + + while (1) { + + loopback_messages(); + + if (shutdown_req) { + printk("shutting down\n"); + goto _cleanup; + } + } + +_cleanup: + rpmsg_deinit_vdev(&rvdev); + metal_finish(); + + printk("OpenAMP remote echo demo ended.\n"); +} + +void main(void) +{ + printk("Starting application thread!\n"); + k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, + (k_thread_entry_t)app_task, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); +} diff --git a/samples/subsys/ipc/openamp/src/main.c b/samples/subsys/ipc/openamp/src/main.c new file mode 100644 index 00000000000000..a221b2daa0372c --- /dev/null +++ b/samples/subsys/ipc/openamp/src/main.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2018, NXP + * Copyright (c) 2018, Nordic Semiconductor ASA + * Copyright (c) 2018, Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +#define APP_TASK_STACK_SIZE (1024) +K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); +static struct k_thread thread_data; + +static struct device *ipm_handle; + +static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR }; +static struct metal_device shm_device = { + .name = SHM_DEVICE_NAME, + .bus = NULL, + .num_regions = 1, + { + { + .virt = (void *) SHM_START_ADDR, + .physmap = shm_physmap, + .size = SHM_SIZE, + .page_shift = 0xffffffff, + .page_mask = 0xffffffff, + .mem_flags = 0, + .ops = { NULL }, + }, + }, + .node = { NULL }, + .irq_num = 0, + .irq_info = NULL +}; + +static volatile unsigned int received_data; + +static struct virtio_vring_info rvrings[2] = { + [0] = { + .info.align = VRING_ALIGNMENT, + }, + [1] = { + .info.align = VRING_ALIGNMENT, + }, +}; +static struct virtio_device vdev; +static struct rpmsg_virtio_device rvdev; +static struct metal_io_region *io; +static struct virtqueue *vq[2]; + +static unsigned char virtio_get_status(struct virtio_device *vdev) +{ + return VIRTIO_CONFIG_STATUS_DRIVER_OK; +} + +static void virtio_set_status(struct virtio_device *vdev, unsigned char status) +{ + sys_write8(status, OPENAMP_STATUS_ADDR); +} + +static u32_t virtio_get_features(struct virtio_device *vdev) +{ + return 1 << VIRTIO_RPMSG_F_NS; +} + +static void virtio_set_features(struct virtio_device *vdev, + u32_t features) +{ +} + +static void virtio_notify(struct virtqueue *vq) +{ + u32_t dummy_data = 0x55005500; /* Some data must be provided */ + + ipm_send(ipm_handle, 0, 0, &dummy_data, sizeof(dummy_data)); +} + +struct virtio_dispatch dispatch = { + .get_status = virtio_get_status, + .set_status = virtio_set_status, + .get_features = virtio_get_features, + .set_features = virtio_set_features, + .notify = virtio_notify, +}; + +static K_SEM_DEFINE(data_sem, 0, 1); +static K_SEM_DEFINE(data_rx_sem, 0, 1); + +static void platform_ipm_callback(void *context, u32_t id, volatile void *data) +{ + k_sem_give(&data_sem); +} + +int endpoint_cb(struct rpmsg_endpoint *ept, void *data, + size_t len, u32_t src, void *priv) +{ + received_data = *((unsigned int *) data); + + k_sem_give(&data_rx_sem); + + return RPMSG_SUCCESS; +} + +static K_SEM_DEFINE(ept_sem, 0, 1); + +struct rpmsg_endpoint my_ept; +struct rpmsg_endpoint *ep = &my_ept; + +static void rpmsg_service_unbind(struct rpmsg_endpoint *ept) +{ + (void)ept; + rpmsg_destroy_ept(ep); +} + +void ns_bind_cb(struct rpmsg_device *rdev, const char *name, u32_t dest) +{ + (void)rpmsg_create_ept(ep, rdev, name, + RPMSG_ADDR_ANY, dest, + endpoint_cb, + rpmsg_service_unbind); + + k_sem_give(&ept_sem); +} + +static unsigned int receive_message(void) +{ + while (k_sem_take(&data_rx_sem, K_NO_WAIT) != 0) { + int status = k_sem_take(&data_sem, K_FOREVER); + + if (status == 0) { + virtqueue_notification(vq[0]); + } + } + return received_data; +} + +static int send_message(unsigned int message) +{ + return rpmsg_send(ep, &message, sizeof(message)); +} + +static struct rpmsg_virtio_shm_pool shpool; + +void app_task(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + int status = 0; + unsigned int message = 0; + struct metal_device *device; + struct metal_init_params metal_params = METAL_INIT_DEFAULTS; + + printk("\r\nOpenAMP[master] demo started\r\n"); + + metal_init(&metal_params); + if (status != 0) { + printk("metal_init: failed - error code %d\n", status); + return; + } + + status = metal_register_generic_device(&shm_device); + if (status != 0) { + printk("Couldn't register shared memory device: %d\n", status); + return; + } + + status = metal_device_open("generic", SHM_DEVICE_NAME, &device); + if (status != 0) { + printk("metal_device_open failed: %d\n", status); + return; + } + + io = metal_device_io_region(device, 0); + if (io == NULL) { + printk("metal_device_io_region failed to get region\n"); + return; + } + + /* setup IPM */ + ipm_handle = device_get_binding("MAILBOX_0"); + if (ipm_handle == NULL) { + printk("device_get_binding failed to find device\n"); + return; + } + + ipm_register_callback(ipm_handle, platform_ipm_callback, NULL); + + ipm_set_enabled(ipm_handle, 1); + if (status != 0) { + printk("ipm_set_enabled failed\n"); + return; + } + + /* setup vdev */ + vq[0] = virtqueue_allocate(VRING_SIZE); + if (vq[0] == NULL) { + printk("virtqueue_allocate failed to alloc vq[0]\n"); + return; + } + vq[1] = virtqueue_allocate(VRING_SIZE); + if (vq[1] == NULL) { + printk("virtqueue_allocate failed to alloc vq[1]\n"); + return; + } + + vdev.role = RPMSG_MASTER; + vdev.vrings_num = VRING_COUNT; + vdev.func = &dispatch; + rvrings[0].io = io; + rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS; + rvrings[0].info.num_descs = VRING_SIZE; + rvrings[0].info.align = VRING_ALIGNMENT; + rvrings[0].vq = vq[0]; + + rvrings[1].io = io; + rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS; + rvrings[1].info.num_descs = VRING_SIZE; + rvrings[1].info.align = VRING_ALIGNMENT; + rvrings[1].vq = vq[1]; + + vdev.vrings_info = &rvrings[0]; + + /* setup rvdev */ + rpmsg_virtio_init_shm_pool(&shpool, (void *)SHM_START_ADDR, SHM_SIZE); + status = rpmsg_init_vdev(&rvdev, &vdev, ns_bind_cb, io, &shpool); + if (status != 0) { + printk("rpmsg_init_vdev failed %d\n", status); + return; + } + + /* Since we are using name service, we need to wait for a response + * from NS setup and than we need to process it + */ + k_sem_take(&data_sem, K_FOREVER); + virtqueue_notification(vq[0]); + + /* Wait til nameservice ep is setup */ + k_sem_take(&ept_sem, K_FOREVER); + + while (message < 100) { + status = send_message(message); + if (status < 0) { + printk("send_message(%d) failed with status %d\n", + message, status); + goto _cleanup; + } + + message = receive_message(); + printk("Master core received a message: %d\n", message); + + message++; + } + +_cleanup: + rpmsg_deinit_vdev(&rvdev); + metal_finish(); + + printk("OpenAMP demo ended.\n"); +} + +void main(void) +{ + printk("Starting application thread!\n"); + k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, + (k_thread_entry_t)app_task, + NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); +} + +/* Make sure we clear out the status flag very early (before we bringup the + * secondary core) so the secondary core see's the proper status + */ +int init_status_flag(struct device *arg) +{ + virtio_set_status(NULL, 0); + + return 0; +} + +SYS_INIT(init_status_flag, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/samples/subsys/ipc/openamp/src/main_master.c b/samples/subsys/ipc/openamp/src/main_master.c deleted file mode 100644 index 6526da7b7dfb88..00000000000000 --- a/samples/subsys/ipc/openamp/src/main_master.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2018, NXP - * Copyright (c) 2018, Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - * - * This implements the master side of an OpenAMP system. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "platform.h" -#include "resource_table.h" - -#define APP_TASK_STACK_SIZE (512) -K_THREAD_STACK_DEFINE(thread_stack, APP_TASK_STACK_SIZE); -static struct k_thread thread_data; - -static struct rpmsg_channel *rp_channel; -static struct rpmsg_endpoint *rp_endpoint; - -static K_SEM_DEFINE(channel_created, 0, 1); - -static K_SEM_DEFINE(message_received, 0, 1); -static volatile unsigned int received_data; - -static struct rsc_table_info rsc_info; -static struct hil_proc *proc; - -static void rpmsg_recv_callback(struct rpmsg_channel *channel, void *data, - int data_length, void *private, - unsigned long src) -{ - received_data = *((unsigned int *) data); - k_sem_give(&message_received); -} - -static void rpmsg_channel_created(struct rpmsg_channel *channel) -{ - rp_channel = channel; - rp_endpoint = rpmsg_create_ept(rp_channel, rpmsg_recv_callback, - RPMSG_NULL, RPMSG_ADDR_ANY); - k_sem_give(&channel_created); -} - -static void rpmsg_channel_deleted(struct rpmsg_channel *channel) -{ - rpmsg_destroy_ept(rp_endpoint); -} - -static unsigned int receive_message(void) -{ - while (k_sem_take(&message_received, K_NO_WAIT) != 0) - hil_poll(proc, 0); - return received_data; -} - -static int send_message(unsigned int message) -{ - return rpmsg_send(rp_channel, &message, sizeof(message)); -} - -void app_task(void *arg1, void *arg2, void *arg3) -{ - ARG_UNUSED(arg1); - ARG_UNUSED(arg2); - ARG_UNUSED(arg3); - - printk("\r\nOpenAMP demo started\r\n"); - - struct metal_init_params metal_params = METAL_INIT_DEFAULTS; - - metal_init(&metal_params); - - proc = platform_init(RPMSG_MASTER); - if (proc == NULL) { - printk("platform_init() failed\n"); - goto _cleanup; - } - - resource_table_init((void **) &rsc_info.rsc_tab, &rsc_info.size); - - struct remote_proc *rproc_ptr = NULL; - int status = remoteproc_resource_init(&rsc_info, proc, - rpmsg_channel_created, - rpmsg_channel_deleted, - rpmsg_recv_callback, - &rproc_ptr, RPMSG_MASTER); - if (status != 0) { - printk("remoteproc_resource_init() failed with status %d\n", - status); - goto _cleanup; - } - - while (k_sem_take(&channel_created, K_NO_WAIT) != 0) - hil_poll(proc, 0); - - unsigned int message = 0U; - - status = send_message(message); - if (status < 0) { - printk("send_message(%d) failed with status %d\n", - message, status); - goto _cleanup; - } - - while (message <= 100) { - message = receive_message(); - printk("Primary core received a message: %d\n", message); - - message++; - status = send_message(message); - if (status < 0) { - printk("send_message(%d) failed with status %d\n", - message, status); - goto _cleanup; - } - } - -_cleanup: - if (rproc_ptr) { - remoteproc_resource_deinit(rproc_ptr); - } - metal_finish(); - - printk("OpenAMP demo ended.\n"); -} - -void main(void) -{ - printk("Starting application thread!\n"); - k_thread_create(&thread_data, thread_stack, APP_TASK_STACK_SIZE, - (k_thread_entry_t)app_task, - NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); -}