From 322504c6c6e26f5ef30c89e6268cec0cbfced63a Mon Sep 17 00:00:00 2001 From: Kinjal Pravinbhai Patel Date: Mon, 16 Mar 2015 14:06:05 +0530 Subject: [PATCH] lib: added initial version of openamp This patch contains initial version of xilopenamp library. Currently the library supports cortex-R5 processor Signed-off-by: Kinjal Pravinbhai Patel --- .../xilopenamp/data/xilopenamp.mld | 51 ++ .../xilopenamp/data/xilopenamp.tcl | 86 ++ .../sw_services/xilopenamp/src/Makefile | 115 +++ .../sw_services/xilopenamp/src/bm_env.c | 609 ++++++++++++++ .../sw_services/xilopenamp/src/bm_env.h | 133 +++ .../sw_services/xilopenamp/src/config.c | 101 +++ .../sw_services/xilopenamp/src/config.h | 59 ++ .../sw_services/xilopenamp/src/elf_loader.c | 643 +++++++++++++++ .../sw_services/xilopenamp/src/elf_loader.h | 234 ++++++ ThirdParty/sw_services/xilopenamp/src/env.h | 428 ++++++++++ ThirdParty/sw_services/xilopenamp/src/hil.c | 406 ++++++++++ ThirdParty/sw_services/xilopenamp/src/hil.h | 486 +++++++++++ ThirdParty/sw_services/xilopenamp/src/llist.c | 100 +++ ThirdParty/sw_services/xilopenamp/src/llist.h | 59 ++ .../sw_services/xilopenamp/src/open_amp.h | 37 + .../xilopenamp/src/remote_device.c | 513 ++++++++++++ .../sw_services/xilopenamp/src/remoteproc.c | 359 ++++++++ .../sw_services/xilopenamp/src/remoteproc.h | 466 +++++++++++ .../xilopenamp/src/remoteproc_loader.c | 241 ++++++ .../xilopenamp/src/remoteproc_loader.h | 92 +++ ThirdParty/sw_services/xilopenamp/src/rpmsg.c | 414 ++++++++++ ThirdParty/sw_services/xilopenamp/src/rpmsg.h | 402 +++++++++ .../sw_services/xilopenamp/src/rpmsg_core.c | 766 ++++++++++++++++++ .../sw_services/xilopenamp/src/rpmsg_core.h | 190 +++++ .../xilopenamp/src/rpmsg_retarget.c | 245 ++++++ .../xilopenamp/src/rpmsg_retarget.h | 52 ++ .../xilopenamp/src/rsc_table_parser.c | 234 ++++++ .../xilopenamp/src/rsc_table_parser.h | 53 ++ .../sw_services/xilopenamp/src/sh_mem.c | 230 ++++++ .../sw_services/xilopenamp/src/sh_mem.h | 89 ++ .../sw_services/xilopenamp/src/virtio.c | 95 +++ .../sw_services/xilopenamp/src/virtio.h | 151 ++++ .../sw_services/xilopenamp/src/virtio_ring.h | 165 ++++ .../sw_services/xilopenamp/src/virtqueue.c | 691 ++++++++++++++++ .../sw_services/xilopenamp/src/virtqueue.h | 233 ++++++ 35 files changed, 9228 insertions(+) create mode 100644 ThirdParty/sw_services/xilopenamp/data/xilopenamp.mld create mode 100644 ThirdParty/sw_services/xilopenamp/data/xilopenamp.tcl create mode 100644 ThirdParty/sw_services/xilopenamp/src/Makefile create mode 100644 ThirdParty/sw_services/xilopenamp/src/bm_env.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/bm_env.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/config.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/config.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/elf_loader.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/elf_loader.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/env.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/hil.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/hil.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/llist.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/llist.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/open_amp.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/remote_device.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/remoteproc.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/remoteproc.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/rpmsg.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/rpmsg.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/rpmsg_core.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/rpmsg_core.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/sh_mem.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/sh_mem.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/virtio.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/virtio.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/virtio_ring.h create mode 100644 ThirdParty/sw_services/xilopenamp/src/virtqueue.c create mode 100644 ThirdParty/sw_services/xilopenamp/src/virtqueue.h diff --git a/ThirdParty/sw_services/xilopenamp/data/xilopenamp.mld b/ThirdParty/sw_services/xilopenamp/data/xilopenamp.mld new file mode 100644 index 00000000..17a378cb --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/data/xilopenamp.mld @@ -0,0 +1,51 @@ +############################################################################### +# +# Copyright (C) 2015 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### +# +# Modification History +# +# Ver Who Date Changes +# ----- ---- -------- ----------------------------------------------- +# 1.00 pkp 12/03/15 Initial Release +# +############################################################################## + +OPTION psf_version = 2.1; + +BEGIN LIBRARY xilopenamp + OPTION DRC = openamp_drc; + OPTION COPYFILES = all; + OPTION REQUIRES_OS = (standalone); + OPTION APP_LINKER_FLAGS = "-Wl,--start-group,-lxil,-lxilopenamp,-lgcc,-lc,--end-group"; + OPTION DESC = "Xilinx openamp Library "; + OPTION VERSION = 1.0; + OPTION NAME = xilopenamp; +END LIBRARY diff --git a/ThirdParty/sw_services/xilopenamp/data/xilopenamp.tcl b/ThirdParty/sw_services/xilopenamp/data/xilopenamp.tcl new file mode 100644 index 00000000..4bb66312 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/data/xilopenamp.tcl @@ -0,0 +1,86 @@ +############################################################################### +# +# Copyright (C) 2015 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### +# +# Modification History +# +# Ver Who Date Changes +# ----- ---- -------- ----------------------------------------------- +# 1.00 pkp 12/03/15 Initial Release +############################################################################## + +#--------------------------------------------- +# openamp_drc +#--------------------------------------------- +proc openamp_drc {libhandle} { + +} + +proc generate {libhandle} { + +} + +#------- +# post_generate: called after generate called on all libraries +#------- +proc post_generate {libhandle} { + + xgen_opts_file $libhandle +} + +#------- +# execs_generate: called after BSP's, libraries and drivers have been compiled +# This procedure builds the libxilopenamp.a library +#------- +proc execs_generate {libhandle} { + +} + +proc xgen_opts_file {libhandle} { + # Copy the include files to the include directory + set srcdir src + set dstdir [file join .. .. include] + + # Create dstdir if it does not exist + if { ! [file exists $dstdir] } { + file mkdir $dstdir + } + puts "its openamp" + + # Get list of files in the srcdir + set sources [glob -join $srcdir *.h] + + # Copy each of the files in the list to dstdir + foreach source $sources { + file copy -force $source $dstdir + } + +} diff --git a/ThirdParty/sw_services/xilopenamp/src/Makefile b/ThirdParty/sw_services/xilopenamp/src/Makefile new file mode 100644 index 00000000..365fe9d8 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/Makefile @@ -0,0 +1,115 @@ +############################################################################### +# +# Copyright (C) 2015 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +############################################################################### + +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS = +EXTRA_ARCHIVE_FLAGS=rc +CC_FLAGS= -mcpu=cortex-r5 +RELEASEDIR=../../../lib +#RELEASEDIR= . +INCLUDEDIR=../../../include +INCLUDES=-I./include/ -I${INCLUDEDIR} +OPENAMP_DIR = . + +LIB_SRCS = $(OPENAMP_DIR)/config.c \ + $(OPENAMP_DIR)/bm_env.c \ + $(OPENAMP_DIR)/elf_loader.c \ + $(OPENAMP_DIR)/hil.c \ + $(OPENAMP_DIR)/llist.c \ + $(OPENAMP_DIR)/remote_device.c \ + $(OPENAMP_DIR)/remoteproc.c \ + $(OPENAMP_DIR)/remoteproc_loader.c \ + $(OPENAMP_DIR)/rpmsg.c \ + $(OPENAMP_DIR)/rpmsg_core.c \ + $(OPENAMP_DIR)/rpmsg_retarget.c\ + $(OPENAMP_DIR)/rsc_table_parser.c \ + $(OPENAMP_DIR)/sh_mem.c \ + $(OPENAMP_DIR)/virtio.c \ + $(OPENAMP_DIR)/virtqueue.c + + +# create SECURE_SRCS based on configured options + +OPENAMP_SRCS = $(LIB_SRCS) + +OPENAMP_OBJS = $(OPENAMP_SRCS:%.c=%.o) + + +EXPORT_INCLUDE_FILES = $(OPENAMP_DIR)/config.h \ + $(OPENAMP_DIR)/bm_env.h \ + $(OPENAMP_DIR)/elf_loader.h \ + $(OPENAMP_DIR)/env.h \ + $(OPENAMP_DIR)/hil.h \ + $(OPENAMP_DIR)/llist.h \ + $(OPENAMP_DIR)/open_amp.h \ + $(OPENAMP_DIR)/remoteproc.h \ + $(OPENAMP_DIR)/remoteproc_loader.h \ + $(OPENAMP_DIR)/rpmsg_retarget.h \ + $(OPENAMP_DIR)/rpmsg.h \ + $(OPENAMP_DIR)/rpmsg_core.h \ + $(OPENAMP_DIR)/rsc_table_parser.h \ + $(OPENAMP_DIR)/sh_mem.h \ + $(OPENAMP_DIR)/virtio.h \ + $(OPENAMP_DIR)/virtio_ring.h\ + $(OPENAMP_DIR)/virtqueue.h + + +libs: libxilopenamp.a + cp libxilopenamp.a $(RELEASEDIR) + make clean + +include: + @for i in $(EXPORT_INCLUDE_FILES); do \ + ${CP} -r $$i ${INCLUDEDIR}; \ + done + +clean: + rm -rf obj/config.o obj/bm_env.o obj/rpmsg_retarget.o obj/elf_loader.o obj/hil.o obj/llist.o obj/remote_device.o obj/remoteproc.o obj/remoteproc_loader.o obj/rpmsg.o obj/rpmsg_core.o obj/rsc_table_parser.o obj/sh_mem.o obj/virtio.o obj/virtqueue.o + rmdir obj + rm libxilopenamp.a + + +libxilopenamp.a: obj_dir print_msg_secure_base $(OPENAMP_OBJS) + @echo "Creating archive $@" + $(ARCHIVER) $(EXTRA_ARCHIVE_FLAGS) $@ obj/config.o obj/bm_env.o obj/rpmsg_retarget.o obj/elf_loader.o obj/hil.o obj/llist.o obj/remote_device.o obj/remoteproc.o obj/remoteproc_loader.o obj/rpmsg.o obj/rpmsg_core.o obj/rsc_table_parser.o obj/sh_mem.o obj/virtio.o obj/virtqueue.o + + +obj_dir: + mkdir obj + +print_msg_secure_base: + @echo "Compiling XilOpenAmp Library" + +.c.o: + $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(CC_FLAGS) $(INCLUDES) -c $< -o obj/$(@F) diff --git a/ThirdParty/sw_services/xilopenamp/src/bm_env.c b/ThirdParty/sw_services/xilopenamp/src/bm_env.c new file mode 100644 index 00000000..1b6096eb --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/bm_env.c @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * Copyright (C) 2015 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * FILE NAME + * + * bm_env.c + * + * + * DESCRIPTION + * + * This file is Bare Metal Implementation of env layer for OpenAMP. + * + * + **************************************************************************/ + +#include "env.h" +#include "config.h" + +#include +#include +#include "xil_exception.h" +#include "xpseudo_asm.h" +#include "bm_env.h" +#include "xscugic.h" + +#if (defined(__CC_ARM)) +#define MEM_BARRIER() __schedule_barrier() +#elif (defined(__GNUC__)) +#define MEM_BARRIER() asm volatile("" ::: "memory") +#else +#define MEM_BARRIER() +#endif +static void acquire_spin_lock(void *plock); +static void release_spin_lock(void *plock); + +struct isr_info isr_table[ISR_COUNT]; +int Intr_Count = 0; +/* Flag to show status of global interrupts. 0 for disabled and 1 for enabled. This + * is added to prevent recursive global interrupts enablement/disablement. + */ +int Intr_Enable_Flag = 1; + +unsigned int old_value = 0; +/** + * env_init + * + * Initializes OS/BM environment. + * + */ +int env_init() { + return 0; +} + +/** + * env_deinit + * + * Uninitializes OS/BM environment. + * + * @returns - execution status + */ + +int env_deinit() { + return 0; +} +/** + * env_allocate_memory - implementation + * + * @param size + */ +void *env_allocate_memory(unsigned int size) +{ + return (malloc(size)); +} + +/** + * env_free_memory - implementation + * + * @param ptr + */ +void env_free_memory(void *ptr) +{ + if (ptr != NULL) + { + free(ptr); + } +} + +/** + * + * env_memset - implementation + * + * @param ptr + * @param value + * @param size + */ +void env_memset(void *ptr, int value, unsigned long size) +{ + memset(ptr, value, size); +} + +/** + * + * env_memcpy - implementation + * + * @param dst + * @param src + * @param len + */ +void env_memcpy(void *dst, void const * src, unsigned long len) { + memcpy(dst,src,len); +} + +/** + * + * env_strcmp - implementation + * + * @param dst + * @param src + */ + +int env_strcmp(const char *dst, const char *src){ + return (strcmp(dst, src)); +} + +/** + * + * env_strncpy - implementation + * + * @param dest + * @param src + * @param len + */ +void env_strncpy(char * dest, const char *src, unsigned long len) +{ + strncpy(dest, src, len); +} + +/** + * + * env_strncmp - implementation + * + * @param dest + * @param src + * @param len + */ +int env_strncmp(char * dest, const char *src, unsigned long len) +{ + return (strncmp(dest, src, len)); +} + +/** + * + * env_mb - implementation + * + */ +void env_mb() +{ + MEM_BARRIER(); +} + +/** + * osalr_mb - implementation + */ +void env_rmb() +{ + MEM_BARRIER(); +} + +/** + * env_wmb - implementation + */ +void env_wmb() +{ + MEM_BARRIER(); +} + +/** + * env_map_vatopa - implementation + * + * @param address + */ +unsigned long env_map_vatopa(void *address) +{ + return platform_vatopa(address); +} + +/** + * env_map_patova - implementation + * + * @param address + */ +void *env_map_patova(unsigned long address) +{ + return platform_patova(address); +} + +/** + * env_create_mutex + * + * Creates a mutex with the given initial count. + * + */ +int env_create_mutex(void **lock, int count) +{ + return 0; +} + +/** + * env_delete_mutex + * + * Deletes the given lock + * + */ +void env_delete_mutex(void *lock) +{ +} + +/** + * env_lock_mutex + * + * Tries to acquire the lock, if lock is not available then call to + * this function will suspend. + */ +void env_lock_mutex(void *lock) +{ + env_disable_interrupts(); +} + +/** + * env_unlock_mutex + * + * Releases the given lock. + */ + +void env_unlock_mutex(void *lock) +{ + env_restore_interrupts(); +} + + +/** + * env_create_sync_lock + * + * Creates a synchronization lock primitive. It is used + * when signal has to be sent from the interrupt context to main + * thread context. + */ +int env_create_sync_lock(void **lock , int state) { + int *slock; + + slock = (int *)malloc(sizeof(int)); + if(slock){ + *slock = state; + *lock = slock; + } + else{ + *lock = NULL; + return -1; + } + + return 0; +} + +/** + * env_delete_sync_lock + * + * Deletes the given lock + * + */ +void env_delete_sync_lock(void *lock){ + if(lock) + free(lock); +} + +/** + * env_acquire_sync_lock + * + * Tries to acquire the lock, if lock is not available then call to + * this function waits for lock to become available. + */ +void env_acquire_sync_lock(void *lock){ + acquire_spin_lock(lock); +} + +/** + * env_release_sync_lock + * + * Releases the given lock. + */ + +void env_release_sync_lock(void *lock){ + release_spin_lock(lock); +} + +/** + * env_sleep_msec + * + * Suspends the calling thread for given time , in msecs. + */ + +void env_sleep_msec(int num_msec) +{ + +} + +/** + * env_disable_interrupts + * + * Disables system interrupts + * + */ +void env_disable_interrupts() +{ + if(Intr_Enable_Flag == 1) { + disable_global_interrupts(); + Intr_Enable_Flag = 0; + } +} + +/** + * env_restore_interrupts + * + * Enables system interrupts + * + */ +void env_restore_interrupts() +{ + if(Intr_Enable_Flag == 0) { + restore_global_interrupts(); + Intr_Enable_Flag = 1; + } +} + +/** + * env_register_isr + * + * Registers interrupt handler for the given interrupt vector. + * + * @param vector - interrupt vector number + * @param isr - interrupt handler + */ +void env_register_isr(int vector , void *data , + void (*isr)(int vector , void *data)) +{ + env_disable_interrupts(); + + if(Intr_Count < ISR_COUNT) + { + /* Save interrupt data */ + isr_table[Intr_Count].vector = vector; + isr_table[Intr_Count].data = data; + isr_table[Intr_Count++].isr = isr; + } + + env_restore_interrupts(); +} + +void env_update_isr(int vector , void *data , + void (*isr)(int vector , void *data)) +{ + int idx; + struct isr_info *info; + + env_disable_interrupts(); + + for(idx = 0; idx < ISR_COUNT; idx++) + { + info = &isr_table[idx]; + if(info->vector == vector) + { + info->data = data; + info->isr = isr; + break; + } + } + + env_restore_interrupts(); +} + +/** + * env_enable_interrupt + * + * Enables the given interrupt + * + * @param vector - interrupt vector number + * @param priority - interrupt priority + * @param polarity - interrupt polarity + */ + +void env_enable_interrupt(unsigned int vector , unsigned int priority , + unsigned int polarity) +{ + int idx; + + env_disable_interrupts(); + + for(idx = 0; idx < ISR_COUNT; idx++) + { + if(isr_table[idx].vector == vector) + { + isr_table[idx].priority = priority; + isr_table[idx].type = polarity; + XScuGic_EnableIntr(XPAR_SCUGIC_0_DIST_BASEADDR,vector); + break; + } + } + + env_restore_interrupts(); +} + +/** + * env_disable_interrupt + * + * Disables the given interrupt + * + * @param vector - interrupt vector number + */ + +void env_disable_interrupt(unsigned int vector) +{ + XScuGic_DisableIntr(XPAR_SCUGIC_0_DIST_BASEADDR,vector); +} + +/** + * env_map_memory + * + * Enables memory mapping for given memory region. + * + * @param pa - physical address of memory + * @param va - logical address of memory + * @param size - memory size + * param flags - flags for cache/uncached and access type + */ + +void env_map_memory(unsigned int pa, unsigned int va, unsigned int size, + unsigned int flags) { + int is_mem_mapped = 0; + int cache_type = 0; + + if ((flags & (0x0f << 4 )) == MEM_MAPPED) + { + is_mem_mapped = 1; + } + + if ((flags & 0x0f) == WB_CACHE) { + cache_type = WRITEBACK; + } + else if((flags & 0x0f) == WT_CACHE) { + cache_type = WRITETHROUGH; + } + else { + cache_type = NOCACHE; + } + + platform_map_mem_region(va, pa, size, is_mem_mapped, cache_type); +} + +/** + * env_disable_cache + * + * Disables system caches. + * + */ + +void env_disable_cache() { + platform_cache_all_flush_invalidate(); + platform_cache_disable(); +} + +/** + * + * env_get_timestamp + * + * Returns a 64 bit time stamp. + * + * + */ +unsigned long long env_get_timestamp(void) { + + /* TODO: Provide implementation for baremetal*/ + return 0; +} + +/*========================================================= */ +/* Util data / functions for BM */ + +void bm_env_isr(int vector) { + int idx; + struct isr_info *info; + + env_disable_interrupt(vector); + for(idx = 0; idx < ISR_COUNT; idx++) + { + info = &isr_table[idx]; + if(info->vector == vector) + { + info->isr(info->vector , info->data); + env_enable_interrupt(info->vector , info->priority, info->type); + break; + } + } +} + +static inline unsigned int xchg(void* plock, unsigned int lockVal) +{ + volatile unsigned int tmpVal = 0; + volatile unsigned int tmpVal1 = 0; + +#ifdef __GNUC__ + + + asm ( + "1: \n\t" + "LDREX %[tmpVal], [%[plock]] \n\t" + "STREX %[tmpVal1], %[lockVal], [%[plock]] \n\t" + "CMP %[tmpVal1], #0 \n\t" + "BNE 1b \n\t" + "DMB \n\t" + : [tmpVal] "=&r"(tmpVal) + : [tmpVal1] "r" (tmpVal1), [lockVal] "r"(lockVal), [plock] "r"(plock) + : "cc", "memory" + ); + +#endif + + return tmpVal; +} + +/** + * + * acquire_spin_lock + * + */ +static void acquire_spin_lock(void *plock) +{ + const int lockVal = 0; + volatile unsigned int retVal; + + do { + retVal = xchg(plock, lockVal); + } while (retVal==lockVal); +} + +/** + * release_spin_lock + */ +static void release_spin_lock(void *plock) +{ + MEM_BARRIER(); + + xchg(plock, 1); +} + +/* + * restore global interrupts + */ +void restore_global_interrupts() { + + ARM_AR_INT_BITS_SET(old_value); + +} + +/* + * disable global interrupts + */ +void disable_global_interrupts() { + + unsigned int value = 0; + + ARM_AR_INT_BITS_GET(&value); + + if (value != old_value) { + + ARM_AR_INT_BITS_SET(CORTEXR5_CPSR_INTERRUPTS_BITS); + + old_value = value; + + } + +} diff --git a/ThirdParty/sw_services/xilopenamp/src/bm_env.h b/ThirdParty/sw_services/xilopenamp/src/bm_env.h new file mode 100644 index 00000000..716f3655 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/bm_env.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * Copyright (C) 2015 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _BM_ENV_H +#define _BM_ENV_H + +#include "xil_cache.h" +#include "xreg_cortexr5.h" +#include "xpseudo_asm_gcc.h" +#include "xparameters.h" + +/* 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 */ + +#ifndef BAREMETAL_MASTER +#define BAREMETAL_MASTER 0 +#endif + +/* The vector table address is the same as image entry point */ +#define RAM_VECTOR_TABLE_ADDR ELF_START + +typedef enum { + TRIG_NOT_SUPPORTED, + TRIG_RISING_EDGE, + TRIG_FALLING_EDGE, + TRIG_LEVEL_LOW, + TRIG_LEVEL_HIGH, + TRIG_RISING_FALLING_EDGES, + TRIG_HIGH_LOW_RISING_FALLING_EDGES +} INT_TRIG_TYPE; + +typedef enum { + NOCACHE, + WRITEBACK, + WRITETHROUGH +} CACHE_TYPE; + +#define CORTEXR5_CPSR_INTERRUPTS_BITS (XREG_CPSR_IRQ_ENABLE | XREG_CPSR_FIQ_ENABLE) + +/* This macro writes the current program status register (CPSR - all fields) */ +#define ARM_AR_CPSR_CXSF_WRITE(cpsr_cxsf_value) \ + { \ + asm volatile(" MSR CPSR_cxsf, %0" \ + : /* No outputs */ \ + : "r" (cpsr_cxsf_value) ); \ + } + +/* This macro sets the interrupt related bits in the status register / control + register to the specified value. */ +#define ARM_AR_INT_BITS_SET(set_bits) \ + { \ + int tmp_val; \ + tmp_val = mfcpsr(); \ + tmp_val &= ~((unsigned int)CORTEXR5_CPSR_INTERRUPTS_BITS); \ + tmp_val |= set_bits; \ + ARM_AR_CPSR_CXSF_WRITE(tmp_val); \ + } + +/* This macro gets the interrupt related bits from the status register / control + register. */ +#define ARM_AR_INT_BITS_GET(get_bits_ptr) \ + { \ + int tmp_val; \ + tmp_val = mfcpsr(); \ + tmp_val &= CORTEXR5_CPSR_INTERRUPTS_BITS; \ + *get_bits_ptr = tmp_val; \ + } + +#define SWITCH_TO_SYS_MODE() \ + { \ + mtcpsr((mfcpsr() | XREG_CPSR_SYSTEM_MODE) & ~((unsigned int)CORTEXR5_CPSR_INTERRUPTS_BITS));\ + } + +void restore_global_interrupts(); +void disable_global_interrupts(); + +/* define function macros for OpenAMP API */ +#define platform_cache_all_flush_invalidate() \ + { \ + Xil_DCacheFlush(); \ + Xil_DCacheInvalidate(); \ + Xil_ICacheInvalidate(); \ + } + +#define platform_cache_disable() \ + { \ + Xil_DCacheDisable(); \ + Xil_ICacheDisable(); \ + } + +#define platform_dcache_all_flush() { Xil_DCacheFlush(); } + +#define platform_dcache_flush_range(addr, len) { Xil_DCacheFlushRange(addr, len); } + +#define platform_map_mem_region(...) + +#define platform_vatopa(addr) ((unsigned long)addr) +#define platform_patova(addr) ((void *)addr) + +#endif /* _BAREMETAL_H */ diff --git a/ThirdParty/sw_services/xilopenamp/src/config.c b/ThirdParty/sw_services/xilopenamp/src/config.c new file mode 100644 index 00000000..204bd7aa --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/config.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * FILE NAME + * + * config.c + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * + **************************************************************************/ + +#include "config.h" + +/* Start and end addresses of firmware image for remotes. These are defined in the + * object files that are obtained by converting the remote ELF Image into object + * files. These symbols are not used for remotes. + */ +extern unsigned char _binary_firmware1_start; +extern unsigned char _binary_firmware1_end; + +extern unsigned char _binary_firmware2_start; +extern unsigned char _binary_firmware2_end; + +#define FIRMWARE1_START (void *)&_binary_firmware1_start +#define FIRMWARE1_END (void *)&_binary_firmware1_end + +#define FIRMWARE2_START (void *)&_binary_firmware2_start +#define FIRMWARE2_END (void *)&_binary_firmware2_end +/* 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 */ +/* Init firmware table */ + +const struct firmware_info fw_table[] = { { "firmware1", + (unsigned int) FIRMWARE1_START, (unsigned int) FIRMWARE1_END }, + { "firmware2", (unsigned int) FIRMWARE2_START, + (unsigned int) FIRMWARE2_END } }; + +/** + * 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 + * + */ + +int config_get_firmware(char *fw_name, unsigned int *start_addr, unsigned int *size) { + int idx; + for (idx = 0; idx < sizeof(fw_table) / (sizeof(struct firmware_info)); + idx++) { + if (!env_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/ThirdParty/sw_services/xilopenamp/src/config.h b/ThirdParty/sw_services/xilopenamp/src/config.h new file mode 100644 index 00000000..0f2c59e3 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/config.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "env.h" + +/* Max supprted ISR counts */ +#define ISR_COUNT 4 + +/* Max supported firmwares */ +#define FW_COUNT 4 +/** + * Structure to keep track of registered ISR's. + */ +struct isr_info { + int vector; + int priority; + int type; + void *data; + void (*isr)(int vector, void *data); +}; + +struct firmware_info { + char name[32]; + unsigned int start_addr; + unsigned int end_addr; +}; + +int config_get_firmware(char *fw_name, unsigned int *start_addr, unsigned int *size); + +#endif diff --git a/ThirdParty/sw_services/xilopenamp/src/elf_loader.c b/ThirdParty/sw_services/xilopenamp/src/elf_loader.c new file mode 100644 index 00000000..7d4a21d2 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/elf_loader.c @@ -0,0 +1,643 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +#include "elf_loader.h" + +/* 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) { + + /* 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; +} + +/** + * 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) { + + struct elf_decode_info *elf_info; + int status; + + /* Allocate memory for decode info structure. */ + elf_info = env_allocate_memory(sizeof(struct elf_decode_info)); + + if (!elf_info) { + return RPROC_ERR_NO_MEM; + } + + /* Clear the ELF decode struct. */ + env_memset(elf_info, 0, sizeof(struct elf_decode_info)); + + /* Get the essential information to decode the ELF. */ + status = elf_loader_get_decode_info(firmware, elf_info); + + if (status) { + /* Free memory. */ + env_free_memory(elf_info); + return status; + } + + 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) { + + struct elf_decode_info *elf_info = + (struct elf_decode_info *) loader->fw_decode_info; + if (elf_info) { + /* Free memory. */ + env_free_memory(elf_info->shstrtab); + env_free_memory(elf_info->section_headers_start); + env_free_memory(elf_info); + } + + return RPROC_SUCCESS; +} + +/** + * 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) { + + return elf_loader_get_entry_point_address( + (struct elf_decode_info *)loader->fw_decode_info); +} + +/** + * 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) { + + Elf32_Shdr *rsc_header; + void* resource_section = NULL; + struct elf_decode_info *elf_info = + (struct elf_decode_info *) loader->fw_decode_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 *) ((unsigned int) elf_info->firmware + + rsc_header->sh_offset); + } + + /* 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) { + + struct elf_decode_info *elf_info = + (struct elf_decode_info *) loader->fw_decode_info; + int status; + + /* 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 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) { + + 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(!env_strcmp(current_name , ".text")){ + return ((void *) (current->sh_addr)); + } + /* Move to the next section. */ + section_count--; + } + + return (RPROC_ERR_PTR); +} +/** + * 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) { + 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 (env_strncmp(current_name, "ynsym", 5) == 0) { + elf_info->dynsym = current; + sections_to_find--; + } + + /* Check for '.dynstr'. */ + else if (env_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 (env_strncmp(current_name, "el.plt", 6) == 0) { + elf_info->rel_plt = current; + sections_to_find--; + } + + /* Check for '.rel.dyn'. */ + else if (env_strncmp(current_name, "el.dyn", 6) == 0) { + elf_info->rel_dyn = current; + sections_to_find--; + } + + /* Check for '.resource_table'. */ + else if (env_strncmp(current_name, "esource_table", 13) + == 0) { + elf_info->rsc = current; + sections_to_find--; + } + } + } + } + + /* Move to the next section. */ + section_count--; + } + + /* Return remaining sections section. */ + return (sections_to_find); +} + +/** + * 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) { + + unsigned char *section_load_addr = (unsigned char*) section->sh_addr; + int status = 0; + int i; + + /* 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 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) { + return ((void *) elf_info->elf_header.e_entry); +} + +/** + * elf_loader_relocate_link + * + * Relocates and links the given ELF object. + * + * @param elf_info - elf object decode info container. + + * + * @return - 0 if success, error otherwise + */ + +static int elf_loader_relocate_link(struct elf_decode_info *elf_info) { + int status = 0; + + /* 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); + } + + /* 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); + } + + /* Return status to caller */ + return (status); +} + +/** + * 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. + + * + * @return - 0 if success, error otherwise + */ + +static int elf_loader_seek_and_read(void *firmware, void *destination, + Elf32_Off offset, Elf32_Word size) { + char *src = (char *) firmware; + + /* Seek to the specified offset. */ + src = src + offset; + + /* Read the data. */ + env_memcpy((char *) destination, src, size); + + /* Return status to caller. */ + 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 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 = env_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 = env_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); + } + } + } + } + + /* Return status to caller. */ + return (status); +} + +/** + * 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 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); + } + } + + /* Move to the next section. */ + section_count--; + } + + /* Return status to caller. */ + return (status); +} + +/** + * 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) { + int status; + + /* Read the ELF headers (ELF header and section headers including + * the section header string table). */ + status = elf_loader_read_headers(firmware, elf_info); + + /* Ensure that ELF headers were read successfully. */ + if (!status) { + /* Retrieve the sections required for load. */ + elf_loader_get_needed_sections(elf_info); + + } + + /* 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) { + 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); +} + +/** + * 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) { + 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; + } + } + + break; + + default: + break; + } + + return status; +} diff --git a/ThirdParty/sw_services/xilopenamp/src/elf_loader.h b/ThirdParty/sw_services/xilopenamp/src/elf_loader.h new file mode 100644 index 00000000..003751cc --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/elf_loader.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef ELF_LOADER_H_ +#define ELF_LOADER_H_ + +#include "remoteproc_loader.h" + +/* ELF base types - 32-bit. */ +typedef unsigned int Elf32_Addr; +typedef unsigned short Elf32_Half; +typedef unsigned int Elf32_Off; +typedef signed int Elf32_Sword; +typedef unsigned int Elf32_Word; + +/* Size of ELF identifier field in the ELF file header. */ +#define EI_NIDENT 16 + +/* ELF file header */ +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; + +} Elf32_Ehdr; + +/* e_ident */ +#define ET_NONE 0 +#define ET_REL 1 /* Re-locatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOOS 0xfe00 /* Operating system-specific */ +#define ET_HIOS 0xfeff /* Operating system-specific */ +#define ET_LOPROC 0xff00 /* remote_proc-specific */ +#define ET_HIPROC 0xffff /* remote_proc-specific */ + +/* e_machine */ +#define EM_ARM 40 /* ARM/Thumb Architecture */ + +/* e_version */ +#define EV_CURRENT 1 /* Current version */ + +/* e_ident[] Identification Indexes */ +#define EI_MAG0 0 /* File identification */ +#define EI_MAG1 1 /* File identification */ +#define EI_MAG2 2 /* File identification */ +#define EI_MAG3 3 /* File identification */ +#define EI_CLASS 4 /* File class */ +#define EI_DATA 5 /* Data encoding */ +#define EI_VERSION 6 /* File version */ +#define EI_OSABI 7 /* Operating system/ABI identification */ +#define EI_ABIVERSION 8 /* ABI version */ +#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] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ + +/* 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. */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* See Data encodings, below */ +#define ELFDATA2MSB 2 /* See Data encodings, below */ + +/* EI_OSABI - We do not define an OS specific ABI */ +#define ELFOSABI_NONE 0 + +/* ELF section header. */ +typedef struct +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; + +} Elf32_Shdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 +#define SHT_GROUP 17 +#define SHT_SYMTAB_SHNDX 18 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* Relocation entry (without addend) */ +typedef struct +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + +} Elf32_Rel; + +/* Relocation entry with addend */ +typedef struct +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; + +} Elf32_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)) + +/* Symbol table entry */ +typedef struct +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; + +} Elf32_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 */ + + +/* ELF decoding information */ +struct elf_decode_info +{ + Elf32_Ehdr elf_header; + unsigned char *section_headers_start; + char *shstrtab; + + Elf32_Shdr *dynsym; + Elf32_Shdr *dynstr; + Elf32_Shdr *rel_plt; + Elf32_Shdr *rel_dyn; + Elf32_Shdr *rsc; + + unsigned char *dynsym_addr; + unsigned char *dynstr_addr; + + char *firmware; + +}; + + + +/* 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); + +#endif /* ELF_LOADER_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/env.h b/ThirdParty/sw_services/xilopenamp/src/env.h new file mode 100644 index 00000000..caaec46c --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/env.h @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + + /************************************************************************** + * FILE NAME + * + * env.h + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * This file defines abstraction layer for OpenAMP stack. The implementor + * must provide definition of all the functions. + * + * DATA STRUCTURES + * + * none + * + * FUNCTIONS + * + * env_allocate_memory + * env_free_memory + * env_memset + * env_memcpy + * env_strlen + * env_strcpy + * env_strncpy + * env_print + * env_map_vatopa + * env_map_patova + * env_mb + * env_rmb + * env_wmb + * env_create_mutex + * env_delete_mutex + * env_lock_mutex + * env_unlock_mutex + * env_sleep_msec + * env_disable_interrupts + * env_restore_interrupts + * + **************************************************************************/ +#ifndef _ENV_H_ +#define _ENV_H_ + +#include + +/** + * env_init + * + * Initializes OS/BM environment. + * + * @returns - execution status + */ + +int env_init(); + +/** + * env_deinit + * + * Uninitializes OS/BM environment. + * + * @returns - execution status + */ + +int env_deinit(); +/** + * ------------------------------------------------------------------------- + * + * Dynamic memory management functions. The parameters + * are similar to standard c functions. + * + *------------------------------------------------------------------------- + **/ + +/** + * env_allocate_memory + * + * Allocates memory with the given size. + * + * @param size - size of memory to allocate + * + * @return - pointer to allocated memory + */ +void *env_allocate_memory(unsigned int size); + +/** + * env_free_memory + * + * Frees memory pointed by the given parameter. + * + * @param ptr - pointer to memory to free + */ +void env_free_memory(void *ptr); + +/** + * ------------------------------------------------------------------------- + * + * RTL Functions + * + *------------------------------------------------------------------------- + */ + +void env_memset(void *, int, unsigned long); +void env_memcpy(void *, void const *, unsigned long); +size_t env_strlen(const char *); +void env_strcpy(char *, const char *); +int env_strcmp(const char *, const char *); +void env_strncpy(char *, const char *, unsigned long); +int env_strncmp(char *, const char *, unsigned long); +#define env_print(...) printf(__VA_ARGS__) + +/** + *----------------------------------------------------------------------------- + * + * Functions to convert physical address to virtual address and vice versa. + * + *----------------------------------------------------------------------------- + */ + +/** + * env_map_vatopa + * + * Converts logical address to physical address + * + * @param address - pointer to logical address + * + * @return - physical address + */ +unsigned long env_map_vatopa(void *address); + +/** + * env_map_patova + * + * Converts physical address to logical address + * + * @param address - pointer to physical address + * + * @return - logical address + * + */ +void *env_map_patova(unsigned long address); + +/** + *----------------------------------------------------------------------------- + * + * Abstractions for memory barrier instructions. + * + *----------------------------------------------------------------------------- + */ + +/** + * env_mb + * + * Inserts memory barrier. + */ + +void env_mb(); + +/** + * env_rmb + * + * Inserts read memory barrier + */ + +void env_rmb(); + +/** + * env_wmb + * + * Inserts write memory barrier + */ + +void env_wmb(); + +/** + *----------------------------------------------------------------------------- + * + * Abstractions for OS lock primitives. + * + *----------------------------------------------------------------------------- + */ + +/** + * env_create_mutex + * + * Creates a mutex with given initial count. + * + * @param lock - pointer to created mutex + * @param count - initial count 0 or 1 + * + * @return - status of function execution + */ +int env_create_mutex(void **lock , int count); + +/** + * env_delete_mutex + * + * Deletes the given lock. + * + * @param lock - mutex to delete + */ + +void env_delete_mutex(void *lock); + +/** + * env_lock_mutex + * + * Tries to acquire the lock, if lock is not available then call to + * this function will suspend. + * + * @param lock - mutex to lock + * + */ + +void env_lock_mutex(void *lock); + +/** + * env_unlock_mutex + * + * Releases the given lock. + * + * @param lock - mutex to unlock + */ + +void env_unlock_mutex(void *lock); + +/** + * env_create_sync_lock + * + * Creates a synchronization lock primitive. It is used + * when signal has to be sent from the interrupt context to main + * thread context. + * + * @param lock - pointer to created sync lock object + * @param state - initial state , lock or unlocked + * + * @returns - status of function execution + */ +#define LOCKED 0 +#define UNLOCKED 1 + +int env_create_sync_lock(void **lock , int state); + +/** + * env_create_sync_lock + * + * Deletes given sync lock object. + * + * @param lock - sync lock to delete. + * + */ + +void env_delete_sync_lock(void *lock); + + +/** + * env_acquire_sync_lock + * + * Tries to acquire the sync lock. + * + * @param lock - sync lock to acquire. + */ +void env_acquire_sync_lock(void *lock); + +/** + * env_release_sync_lock + * + * Releases synchronization lock. + * + * @param lock - sync lock to release. + */ +void env_release_sync_lock(void *lock); + +/** + * env_sleep_msec + * + * Suspends the calling thread for given time in msecs. + * + * @param num_msec - delay in msecs + */ +void env_sleep_msec(int num_msec); + +/** + * env_disable_interrupts + * + * Disables system interrupts + * + */ +void env_disable_interrupts(); + +/** + * env_restore_interrupts + * + * Enables system interrupts + * + */ +void env_restore_interrupts(); + +/** + * env_register_isr + * + * Registers interrupt handler for the given interrupt vector. + * + * @param vector - interrupt vector number + * @param data - private data + * @param isr - interrupt handler + */ + +void env_register_isr(int vector, void *data, + void (*isr)(int vector, void *data)); + +void env_update_isr(int vector, void *data, + void (*isr)(int vector, void *data)); + +/** + * env_enable_interrupt + * + * Enables the given interrupt. + * + * @param vector - interrupt vector number + * @param priority - interrupt priority + * @param polarity - interrupt polarity + */ + +void env_enable_interrupt(unsigned int vector, unsigned int priority, + unsigned int polarity); + +/** + * env_disable_interrupt + * + * Disables the given interrupt. + * + * @param vector - interrupt vector number + */ + +void env_disable_interrupt(unsigned int vector); + +/** + * env_map_memory + * + * Enables memory mapping for given memory region. + * + * @param pa - physical address of memory + * @param va - logical address of memory + * @param size - memory size + * param flags - flags for cache/uncached and access type + * + * Currently only first byte of flag parameter is used and bits mapping is defined as follow; + * + * Cache bits + * 0x0000_0001 = No cache + * 0x0000_0010 = Write back + * 0x0000_0100 = Write through + * 0x0000_x000 = Not used + * + * Memory types + * + * 0x0001_xxxx = Memory Mapped + * 0x0010_xxxx = IO Mapped + * 0x0100_xxxx = Shared + * 0x1000_xxxx = TLB + */ + +/* Macros for caching scheme used by the shared memory */ +#define UNCACHED (1 << 0) +#define WB_CACHE (1 << 1) +#define WT_CACHE (1 << 2) + +/* Memory Types */ +#define MEM_MAPPED (1 << 4) +#define IO_MAPPED (1 << 5) +#define SHARED_MEM (1 << 6) +#define TLB_MEM (1 << 7) + +void env_map_memory(unsigned int pa, unsigned int va, unsigned int size, + unsigned int flags); + +/** + * env_get_timestamp + * + * Returns a 64 bit time stamp. + * + * + */ +unsigned long long env_get_timestamp(void); + +/** + * env_disable_cache + * + * Disables system caches. + * + */ + +void env_disable_cache(); + +typedef void LOCK; + +#endif /* _ENV_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/hil.c b/ThirdParty/sw_services/xilopenamp/src/hil.c new file mode 100644 index 00000000..31e1a71e --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/hil.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * FILE NAME + * + * hil.c + * + * COMPONENT + * + * OpenAMP Stack. + * + * DESCRIPTION + * + * This file is implementation of generic part of HIL. + * + * + * + **************************************************************************/ + +#include "hil.h" + +/*--------------------------- Globals ---------------------------------- */ +struct hil_proc_list procs; + +#if defined (OPENAMP_BENCHMARK_ENABLE) + +unsigned long long boot_time_stamp; +unsigned long long shutdown_time_stamp; + +#endif + +extern int platform_get_processor_info(struct hil_proc *proc, int cpu_id); +extern int platform_get_processor_for_fw(char *fw_name); + +/** + * hil_create_proc + * + * This function creates a HIL proc instance for given CPU id and populates + * it with platform info. + * + * @param cpu_id - cpu id + * + * @return - pointer to proc instance + * + */ +struct hil_proc *hil_create_proc(int cpu_id) { + struct hil_proc *proc = NULL; + struct llist *node = NULL; + struct llist *proc_hd = procs.proc_list; + int status; + + /* If proc already exists then return it */ + while (proc_hd != NULL) { + proc = (struct hil_proc *) proc_hd->data; + if (proc->cpu_id == cpu_id) { + return proc; + } + proc_hd = proc_hd->next; + } + + /* Allocate memory for proc instance */ + proc = env_allocate_memory(sizeof(struct hil_proc)); + if (!proc) { + return NULL; + } + + /* Get HW specfic info */ + status = platform_get_processor_info(proc, cpu_id); + if (status) { + env_free_memory(proc); + return NULL; + } + + /* Enable mapping for the shared memory region */ + env_map_memory((unsigned int) proc->sh_buff.start_addr, + (unsigned int) proc->sh_buff.start_addr, proc->sh_buff.size, + (SHARED_MEM | UNCACHED)); + + /* Put the new proc in the procs list */ + node = env_allocate_memory(sizeof(struct llist)); + + if (!node) { + env_free_memory(proc); + return NULL; + } + + node->data = proc; + add_to_list(&procs.proc_list, node); + + return proc; +} + +/** + * hil_get_cpuforfw + * + * This function provides the CPU ID for the given firmware. + * + * @param fw_name - name of firmware + * + * @return - cpu id + * + */ +int hil_get_cpuforfw(char *fw_name) { + return (platform_get_processor_for_fw(fw_name)); +} + +/** + * 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 llist *proc_hd = NULL; + + if (!proc) + return; + + proc_hd = procs.proc_list; + + while (proc_hd != NULL) { + if (proc_hd->data == proc) { + remove_from_list(&procs.proc_list, proc_hd); + env_free_memory(proc_hd); + break; + } + proc_hd = proc_hd->next; + } + + env_free_memory(proc); +} + + +/** + * hil_isr() + * + * This function is called when interrupt is received for the vring. + * This function gets the corresponding virtqueue and generates + * call back for it. + * + * @param vring_hw - pointer to vring control block + * + */ +void hil_isr(struct proc_vring *vring_hw){ + virtqueue_notification(vring_hw->vq); +} + +/** + * hil_get_proc + * + * This function finds the proc instance based on the given ID + * from the proc list and returns it to user. + * + * @param cpu_id - cpu id + * + * @return - pointer to hil proc instance + * + */ +struct hil_proc *hil_get_proc(int cpu_id) { + struct llist *proc_hd = procs.proc_list; + + if (!proc_hd) + return NULL; + + while (proc_hd != NULL) { + struct hil_proc *proc = (struct hil_proc *) proc_hd->data; + if (proc->cpu_id == cpu_id) { + return proc; + } + proc_hd = proc_hd->next; + } + + return NULL; +} + +/** + * 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); +} + +/** + * 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) { + + *num_vrings = vdev->num_vrings; + 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); +} + +/** + * 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); + } + + return 0; +} + +/** + * 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->cpu_id, &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) { + /* 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) { + /* 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->cpu_id, start_addr); + } + +#if defined (OPENAMP_BENCHMARK_ENABLE) + boot_time_stamp = env_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->cpu_id); + } + +#if defined (OPENAMP_BENCHMARK_ENABLE) + shutdown_time_stamp = env_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, unsigned int *start_addr, unsigned int *size){ + return (config_get_firmware(fw_name , start_addr, size)); +} diff --git a/ThirdParty/sw_services/xilopenamp/src/hil.h b/ThirdParty/sw_services/xilopenamp/src/hil.h new file mode 100644 index 00000000..b781a884 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/hil.h @@ -0,0 +1,486 @@ +#ifndef _HIL_H_ +#define _HIL_H_ + +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 the 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. + */ + +/************************************************************************** + * 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 "virtio.h" +#include "config.h" + +/* 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 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; + /* Size of shared memory. */ + unsigned long size; + /* Attributes for shared memory - cached or uncached. */ + unsigned long flags; +}; + +/** +* 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; + /* 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 physical address */ + void *phy_addr; + /* 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 +{ + /* 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 +{ + /* CPU ID as defined by the platform */ + unsigned long cpu_id; + /* 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]; + /* HIL platform ops table */ + struct hil_platform_ops *ops; + /* Attrbites to represent processor role, master or remote . This field is for + * future use. */ + unsigned long attr; + /* + * CPU bitmask - shared variable updated by each core + * after it has been initialized. This field is for future use. + */ + unsigned long cpu_bitmask; + /* Spin lock - This field is for future use. */ + volatile unsigned int *slock; +}; + +/** + * struct hil_proc_list + * + * This structure serves as lists for cores present in the system. + * It provides entry point to access remote core parameters. + * + */ +struct hil_proc_list { + struct llist *proc_list; +}; + +/** + * hil_create_proc + * + * This function creates a HIL proc instance for given CPU id and populates + * it with platform info. + * + * @param cpu_id - cpu id + * + * @return - pointer to proc instance + * + */ +struct hil_proc *hil_create_proc(int cpu_id); + +/** + * 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_get_proc + * + * This function finds the proc instance based on the given ID + * from the proc list and returns it to user. + * + * @param cpu_id - cpu id + * + * @return - pointer to proc instance + * + */ +struct hil_proc *hil_get_proc(int cpu_id); + +/** + * hil_isr() + * + * This function is called when interrupt is received for the vring. + * This function gets the corresponding virtqueue and generates + * call back for it. + * + * @param vring_hw - pointer to vring control block + * + */ +void hil_isr(struct proc_vring *vring_hw); + +/** + * hil_get_cpuforfw + * + * This function provides the CPU ID for the given firmware. + * + * @param fw_name - name of firmware + * + * @return - cpu id + * + */ +int hil_get_cpuforfw(char *fw_name); + +/** + * 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_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_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_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, unsigned int *start_addr, unsigned int *size); + +/** + * + * 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) for given vring. + * + * @param vring_hw - pointer to vring control block + * + * @return - execution status + */ + int (*enable_interrupt)(struct proc_vring *vring_hw); + + /** + * reg_ipi_after_deinit() + * This function register interrupt(IPI) after openamp resource . + * + * @param vring_hw - pointer to vring control block + */ + void (*reg_ipi_after_deinit)(struct proc_vring *vring_hw); + + /** + * notify() + * + * This function generates IPI to let the other side know that there is + * job available for it. + * + * @param cpu_id - ID of CPU which is to be notified + * @param intr_info - pointer to interrupt info control block + */ + void (*notify)(int cpu_id , struct proc_intr *intr_info); + + /** + * 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 is initialized. + * + * @param cpu_id - ID of CPU for which status is requested. + * + * @return - execution status + */ + int (*get_status)(int cpu_id); + + /** + * set_status + * + * This function is used to update the status + * of the given core i.e it is ready for IPC. + * + * @param cpu_id - ID of CPU for which status is to be set + * + * @return - execution status + */ + + int (*set_status)(int cpu_id); + + /** + * boot_cpu + * + * This function boots the remote processor. + * + * @param cpu_id - ID of CPU to boot + * @param start_addr - start address of remote cpu + * + * @return - execution status + */ + int (*boot_cpu)(int cpu_id , unsigned int start_addr); + + /** + * shutdown_cpu + * + * This function shutdowns the remote processor. + * + * @param cpu_id - ID of CPU to shutdown + * + */ + void (*shutdown_cpu)(int cpu_id); + +}; + +#endif /* _HIL_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/llist.c b/ThirdParty/sw_services/xilopenamp/src/llist.c new file mode 100644 index 00000000..37e888c0 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/llist.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * FILE NAME + * + * llist.c + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * Source file for basic linked list service. + * + **************************************************************************/ +#include "llist.h" + +#define LIST_NULL ((void *)0) +/** + * add_to_list + * + * Places new element at the start of the list. + * + * @param head - list head + * @param node - new element to add + * + */ +void add_to_list(struct llist **head, struct llist *node) { + + if (!node) + return; + + if (*head) { + /* Place the new element at the start of list. */ + node->next = *head; + node->prev = LIST_NULL; + (*head)->prev = node; + *head = node; + } else { + /* List is empty - assign new element to list head. */ + *head = node; + (*head)->next = LIST_NULL; + (*head)->prev = LIST_NULL; + } +} + +/** + * remove_from_list + * + * Removes the given element from the list. + * + * @param head - list head + * @param element - element to remove from list + * + */ +void remove_from_list(struct llist **head, struct llist *node) { + + if (!(*head) || !(node)) + return; + + if (node == *head) { + /* First element has to be removed. */ + *head = (*head)->next; + } else if (node->next == LIST_NULL) { + /* Last element has to be removed. */ + node->prev->next = node->next; + } else { + /* Intermediate element has to be removed. */ + node->prev->next = node->next; + node->next->prev = node->prev; + } +} diff --git a/ThirdParty/sw_services/xilopenamp/src/llist.h b/ThirdParty/sw_services/xilopenamp/src/llist.h new file mode 100644 index 00000000..004f4e09 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/llist.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + + +/************************************************************************** + * FILE NAME + * + * llist.h + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * Header file for linked list service. + * + **************************************************************************/ + +#ifndef LLIST_H_ +#define LLIST_H_ + +struct llist { + void *data; + unsigned int attr; + struct llist *next; + struct llist *prev; +}; + +void add_to_list(struct llist **head, struct llist *node); +void remove_from_list(struct llist **head, struct llist *node); + +#endif /* LLIST_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/open_amp.h b/ThirdParty/sw_services/xilopenamp/src/open_amp.h new file mode 100644 index 00000000..5fcb22b8 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/open_amp.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OPEN_AMP_H_ +#define OPEN_AMP_H_ + +#include "rpmsg.h" +#include "remoteproc.h" + + +#endif /* OPEN_AMP_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/remote_device.c b/ThirdParty/sw_services/xilopenamp/src/remote_device.c new file mode 100644 index 00000000..7f6816d0 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/remote_device.c @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * 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 "rpmsg.h" + +/* Macro to initialize vring HW info */ +#define INIT_VRING_ALLOC_INFO(ring_info,vring_hw) \ + (ring_info).phy_addr = (vring_hw).phy_addr; \ + (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_rdev_init + * + * This function creates and initializes the remote device. The remote device + * encapsulates virtio device. + * + * @param rdev - pointer to newly created remote device + * @param dev-id - ID of device to create , remote cpu id + * @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 remote_device **rdev, int dev_id, 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 hil_proc *proc; + struct proc_shm *shm; + int status; + + /* Initialize HIL data structures for given device */ + proc = hil_create_proc(dev_id); + + if (!proc) { + return RPMSG_ERR_DEV_ID; + } + + /* Create software representation of remote processor. */ + rdev_loc = (struct remote_device *) env_allocate_memory( + sizeof(struct remote_device)); + + if (!rdev_loc) { + return RPMSG_ERR_NO_MEM; + } + + env_memset(rdev_loc, 0x00, sizeof(struct remote_device)); + status = env_create_mutex(&rdev_loc->lock, 1); + + if (status != RPMSG_SUCCESS) { + + /* Cleanup required in case of error is performed by caller */ + return status; + } + + 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; + + /* 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; + } + } + + /* 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 llist *rp_chnl_head, *rp_chnl_temp, *node; + struct rpmsg_channel *rp_chnl; + + rp_chnl_head = rdev->rp_channels; + + while (rp_chnl_head != RPMSG_NULL ) { + + rp_chnl_temp = rp_chnl_head->next; + rp_chnl = (struct rpmsg_channel *) rp_chnl_head->data; + + 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); + rp_chnl_head = rp_chnl_temp; + } + + /* Delete name service endpoint */ + node = rpmsg_rdev_get_endpoint_from_addr(rdev,RPMSG_NS_EPT_ADDR); + if (node) { + _destroy_endpoint(rdev, (struct rpmsg_endpoint *) node->data); + } + + if (rdev->rvq) { + virtqueue_free(rdev->rvq); + } + if (rdev->tvq) { + virtqueue_free(rdev->tvq); + } + if (rdev->mem_pool) { + sh_mem_delete_pool(rdev->mem_pool); + } + if (rdev->lock) { + env_delete_mutex(rdev->lock); + } + + env_free_memory(rdev); +} + +/** + * rpmsg_rdev_get_chnl_node_from_id + * + * This function returns channel node based on channel name. + * + * @param stack - pointer to remote device + * @param rp_chnl_id - rpmsg channel name + * + * @return - channel node + * + */ +struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev, + char *rp_chnl_id) { + struct rpmsg_channel *rp_chnl; + struct llist *rp_chnl_head; + + rp_chnl_head = rdev->rp_channels; + + env_lock_mutex(rdev->lock); + while (rp_chnl_head) { + rp_chnl = (struct rpmsg_channel *) rp_chnl_head->data; + if (env_strncmp(rp_chnl->name, rp_chnl_id, sizeof(rp_chnl->name)) + == 0) { + env_unlock_mutex(rdev->lock); + return rp_chnl_head; + } + rp_chnl_head = rp_chnl_head->next; + } + env_unlock_mutex(rdev->lock); + + return RPMSG_NULL ; +} + +/** + * rpmsg_rdev_get_chnl_from_addr + * + * This function returns channel node based on src/dst address. + * + * @param rdev - pointer remote device control block + * @param addr - src/dst address + * + * @return - channel node + * + */ +struct llist *rpmsg_rdev_get_chnl_from_addr(struct remote_device *rdev, + unsigned long addr) { + struct rpmsg_channel *rp_chnl; + struct llist *rp_chnl_head; + + rp_chnl_head = rdev->rp_channels; + + env_lock_mutex(rdev->lock); + while (rp_chnl_head) { + rp_chnl = (struct rpmsg_channel *) rp_chnl_head->data; + if ((rp_chnl->src == addr) || (rp_chnl->dst == addr)) { + env_unlock_mutex(rdev->lock); + return rp_chnl_head; + } + rp_chnl_head = rp_chnl_head->next; + } + env_unlock_mutex(rdev->lock); + + return RPMSG_NULL ; +} + +/** + * rpmsg_rdev_get_endpoint_from_addr + * + * This function returns endpoint node based on src address. + * + * @param rdev - pointer remote device control block + * @param addr - src address + * + * @return - endpoint node + * + */ +struct llist *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev, + unsigned long addr) { + struct llist *rp_ept_lut_head; + + rp_ept_lut_head = rdev->rp_endpoints; + + env_lock_mutex(rdev->lock); + while (rp_ept_lut_head) { + struct rpmsg_endpoint *rp_ept = + (struct rpmsg_endpoint *) rp_ept_lut_head->data; + if (rp_ept->addr == addr) { + env_unlock_mutex(rdev->lock); + return rp_ept_lut_head; + } + rp_ept_lut_head = rp_ept_lut_head->next; + } + env_unlock_mutex(rdev->lock); + + 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) { + int status = RPMSG_SUCCESS; + + if (rdev->role == RPMSG_REMOTE) { + status = hil_get_status(rdev->proc); + + /* + * Let the remote device know that Master is ready for + * communication. + */ + if (!status) + virtqueue_kick(rdev->rvq); + + } else { + status = hil_set_status(rdev->proc); + } + + if (status == RPMSG_SUCCESS) { + rdev->state = RPMSG_DEV_STATE_ACTIVE; + } + + return status; +} +/** + * 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; + + 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; +} + +/** + *------------------------------------------------------------------------ + * 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 llist node; + int idx, num_vrings, status; + + 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) { + env_memset((void*) ring_info.phy_addr, 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, + &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) { + for (idx = 0; ((idx < rdev->rvq->vq_nentries) + && (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; + } + + node.data = buffer; + node.attr = RPMSG_BUFFER_SIZE; + node.next = RPMSG_NULL; + + env_memset(buffer, 0x00, RPMSG_BUFFER_SIZE); + status = virtqueue_add_buffer(rdev->rvq, &node, 0, 1, buffer); + + if (status != RPMSG_SUCCESS) { + return status; + } + } + } + + return RPMSG_SUCCESS; +} + +unsigned char rpmsg_rdev_get_status(struct virtio_device *dev) { + return 0; +} + +void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status) { + +} + +unsigned long rpmsg_rdev_get_feature(struct virtio_device *dev) { + return dev->features; +} + +void rpmsg_rdev_set_feature(struct virtio_device *dev, unsigned long feature) { + dev->features |= feature; +} + +unsigned long rpmsg_rdev_negotiate_feature(struct virtio_device *dev, + unsigned long 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, unsigned long offset, + void *dst, int length) { + return; +} +void rpmsg_rdev_write_config(struct virtio_device *dev, unsigned long offset, + void *src, int length) { + return; +} +void rpmsg_rdev_reset(struct virtio_device *dev) { + return; +} diff --git a/ThirdParty/sw_services/xilopenamp/src/remoteproc.c b/ThirdParty/sw_services/xilopenamp/src/remoteproc.c new file mode 100644 index 00000000..02a9db8a --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/remoteproc.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +#include "remoteproc.h" +#include "remoteproc_loader.h" +#include "rsc_table_parser.h" +#include "env.h" +#include "hil.h" + +/** + * 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 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_resource_init(struct rsc_table_info *rsc_info, + rpmsg_chnl_cb_t channel_created, rpmsg_chnl_cb_t channel_destroyed, + rpmsg_rx_cb_t default_cb, struct remote_proc** rproc_handle) { + + struct remote_proc *rproc; + int status; + + if(!rsc_info) { + return RPROC_ERR_PARAM; + } + + /* Initialize environment component */ + status = env_init(); + if (status != RPROC_SUCCESS) { + return status; + } + + rproc = env_allocate_memory(sizeof(struct remote_proc)); + if (rproc) { + env_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 = hil_create_proc(HIL_RSVD_CPU_ID); + if (rproc->proc) { + /* 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; + status = rpmsg_init(rproc->proc->cpu_id, &rproc->rdev, + channel_created, channel_destroyed, default_cb, + RPMSG_MASTER); + } else { + status = RPROC_ERR_NO_RSC_TABLE; + } + } else { + status = RPROC_ERR_CPU_ID; + } + } else { + status = RPROC_ERR_NO_MEM; + } + + /* Cleanup in case of error */ + if (status != RPROC_SUCCESS) { + *rproc_handle = 0; + (void) remoteproc_resource_deinit(rproc); + return status; + } + return status; +} + +/** + * remoteproc_resource_deinit + * + * Uninitializes resources for remoteproc "remote" configuration. + * + * @param rproc - pointer to rproc instance + * + * @param returns - status of function execution + * + */ + +int remoteproc_resource_deinit(struct remote_proc *rproc) { + int i = 0; + struct proc_vring *vring_hw = 0; + if (rproc) { + if (rproc->rdev) { + /* disable IPC interrupts */ + if (rproc->proc->ops->reg_ipi_after_deinit) { + for(i = 0; i < 2; i++) { + vring_hw = &rproc->proc->vdev.vring_info[i]; + rproc->proc->ops->reg_ipi_after_deinit(vring_hw); + } + } + rpmsg_deinit(rproc->rdev); + } + if (rproc->proc) { + hil_delete_proc(rproc->proc); + } + + env_free_memory(rproc); + } + + env_deinit(); + + /* Disable the caches - This is required if master boots firmwares + * multiple times without hard reset on same core. If caches are + * not invalidated at this point in time then subsequent firmware + * boots on the same core may experience cache inconsistencies. + * + */ + env_disable_cache(); + + return RPROC_SUCCESS; +} + +/** + * 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 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, rpmsg_chnl_cb_t channel_created, + rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb, + struct remote_proc** rproc_handle) { + + struct remote_proc *rproc; + struct resource_table *rsc_table; + unsigned int fw_addr, fw_size, rsc_size; + int status, cpu_id; + + if (!fw_name) { + return RPROC_ERR_PARAM; + } + + /* Initialize environment component */ + status = env_init(); + if (status != RPROC_SUCCESS) { + return status; + } + + rproc = env_allocate_memory(sizeof(struct remote_proc)); + if (rproc) { + env_memset((void *) rproc, 0x00, sizeof(struct remote_proc)); + /* Get CPU ID for the given firmware name */ + cpu_id = hil_get_cpuforfw(fw_name); + if (cpu_id >= 0) { + /* Create proc instance */ + rproc->proc = hil_create_proc(cpu_id); + if (rproc->proc) { + /* 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; + } + } + } else { + status = RPROC_ERR_NO_MEM; + } + } else { + status = RPROC_ERR_INVLD_FW; + } + } else { + status = RPROC_ERR_NO_MEM; + } + + if (!status) { + rproc->role = RPROC_MASTER; + + /* 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); + } else { + status = RPROC_ERR_NO_RSC_TABLE; + } + } + + /* Cleanup in case of error */ + if (status != RPROC_SUCCESS) { + (void) remoteproc_deinit(rproc); + return status; + } + + rproc->channel_created = channel_created; + rproc->channel_destroyed = channel_destroyed; + rproc->default_cb = default_cb; + + *rproc_handle = rproc; + + + return status; +} + +/** + * 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) { + + if (rproc) { + if (rproc->loader) { + (void) remoteproc_loader_delete(rproc->loader); + rproc->loader = RPROC_NULL; + } + if (rproc->proc) { + hil_delete_proc(rproc->proc); + rproc->proc = RPROC_NULL; + } + env_free_memory(rproc); + } + + env_deinit(); + + return RPROC_SUCCESS; +} + +/** + * 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) { + + 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, + (unsigned int) 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 */ + env_sleep_msec(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->cpu_id, &rproc->rdev, + rproc->channel_created, + rproc->channel_destroyed, rproc->default_cb, + RPMSG_MASTER); +#else + status = rpmsg_init(rproc->proc->cpu_id, &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 status; +} + +/** + * 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) { + + if (rproc) { + if (rproc->rdev) { + rpmsg_deinit(rproc->rdev); + rproc->rdev = RPROC_NULL; + } + if (rproc->proc) { + hil_shutdown_cpu(rproc->proc); + } + } + + return RPROC_SUCCESS; +} diff --git a/ThirdParty/sw_services/xilopenamp/src/remoteproc.h b/ThirdParty/sw_services/xilopenamp/src/remoteproc.h new file mode 100644 index 00000000..1b985388 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/remoteproc.h @@ -0,0 +1,466 @@ +/* + * Remote remote_proc Framework + * + * 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_H +#define REMOTEPROC_H + +#include "rpmsg.h" +#include "config.h" +/** + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries + * + * A resource table is essentially a list of system resources required + * by the remote remote_proc. It may also include configuration entries. + * If needed, the remote remote_proc firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * Some resources entries are mere announcements, where the host is informed + * of specific remoteproc configuration. Other entries require the host to + * do something (e.g. allocate a system resource). Sometimes a negotiation + * is expected, where the firmware requests a resource, and once allocated, + * the host should provide back its details (e.g. address of an allocated + * memory region). + * + * The header of the resource table, as expressed by this structure, + * contains a version number (should we need to change this format in the + * future), the number of available resource entries, and their offsets + * in the table. + * + * Immediately following this header are the resource entries themselves, + * each of which begins with a resource entry header (as described below). + */ +struct resource_table { + unsigned int ver; + unsigned int num; + unsigned int reserved[2]; + unsigned int offset[0]; +} __attribute__((__packed__)); + +/** + * struct fw_rsc_hdr - firmware resource entry header + * @type: resource type + * @data: resource data + * + * Every resource entry begins with a 'struct fw_rsc_hdr' header providing + * its @type. The content of the entry itself will immediately follow + * this header, and it should be parsed according to the resource type. + */ +struct fw_rsc_hdr { + unsigned int type; + unsigned char data[0]; +} __attribute__((__packed__)); + +/** + * enum fw_resource_type - types of resource entries + * + * @RSC_CARVEOUT: request for allocation of a physically contiguous + * memory region. + * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. + * @RSC_TRACE: announces the availability of a trace buffer into which + * the remote remote_proc will be writing logs. + * @RSC_VDEV: declare support for a virtio device, and serve as its + * virtio header. + * @RSC_LAST: just keep this one at the end + * + * For more details regarding a specific resource type, please see its + * dedicated structure below. + * + * Please note that these values are used as indices to the rproc_handle_rsc + * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to + * check the validity of an index before the lookup table is accessed, so + * please update it as needed. + */ +enum fw_resource_type { + RSC_CARVEOUT = 0, + RSC_DEVMEM = 1, + RSC_TRACE = 2, + RSC_VDEV = 3, + RSC_LAST = 4, +}; + +#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) + +/** + * struct fw_rsc_carveout - physically contiguous memory request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested memory region + * + * This resource entry requests the host to allocate a physically contiguous + * memory region. + * + * These request entries should precede other firmware resource entries, + * as other entries might request placing other data objects inside + * these memory regions (e.g. data/code segments, trace resource entries, ...). + * + * Allocating memory this way helps utilizing the reserved physical memory + * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries + * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB + * pressure is important; it may have a substantial impact on performance. + * + * If the firmware is compiled with static addresses, then @da should specify + * the expected device address of this memory region. If @da is set to + * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then + * overwrite @da with the dynamically allocated address. + * + * We will always use @da to negotiate the device addresses, even if it + * isn't using an iommu. In that case, though, it will obviously contain + * physical addresses. + * + * Some remote remote_procs needs to know the allocated physical address + * even if they do use an iommu. This is needed, e.g., if they control + * hardware accelerators which access the physical memory directly (this + * is the case with OMAP4 for instance). In that case, the host will + * overwrite @pa with the dynamically allocated physical address. + * Generally we don't want to expose physical addresses if we don't have to + * (remote remote_procs are generally _not_ trusted), so we might want to + * change this to happen _only_ when explicitly required by the hardware. + * + * @flags is used to provide IOMMU protection flags, and @name should + * (optionally) contain a human readable name of this carveout region + * (mainly for debugging purposes). + */ +struct fw_rsc_carveout { + unsigned int type; + unsigned int da; + unsigned int pa; + unsigned int len; + unsigned int flags; + unsigned int reserved; + unsigned char name[32]; +} __attribute__((__packed__)); + +/** + * struct fw_rsc_devmem - iommu mapping request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested region to be mapped + * + * This resource entry requests the host to iommu map a physically contiguous + * memory region. This is needed in case the remote remote_proc requires + * access to certain memory-based peripherals; _never_ use it to access + * regular memory. + * + * This is obviously only needed if the remote remote_proc is accessing memory + * via an iommu. + * + * @da should specify the required device address, @pa should specify + * the physical address we want to map, @len should specify the size of + * the mapping and @flags is the IOMMU protection flags. As always, @name may + * (optionally) contain a human readable name of this mapping (mainly for + * debugging purposes). + * + * Note: at this point we just "trust" those devmem entries to contain valid + * physical addresses, but this isn't safe and will be changed: eventually we + * want remoteproc implementations to provide us ranges of physical addresses + * the firmware is allowed to request, and not allow firmwares to request + * access to physical addresses that are outside those ranges. + */ +struct fw_rsc_devmem { + unsigned int type; + unsigned int da; + unsigned int pa; + unsigned int len; + unsigned int flags; + unsigned int reserved; + unsigned char name[32]; +} __attribute__((__packed__)); + +/** + * struct fw_rsc_trace - trace buffer declaration + * @da: device address + * @len: length (in bytes) + * @reserved: reserved (must be zero) + * @name: human-readable name of the trace buffer + * + * This resource entry provides the host information about a trace buffer + * into which the remote remote_proc will write log messages. + * + * @da specifies the device address of the buffer, @len specifies + * its size, and @name may contain a human readable name of the trace buffer. + * + * After booting the remote remote_proc, the trace buffers are exposed to the + * user via debugfs entries (called trace0, trace1, etc..). + */ +struct fw_rsc_trace { + unsigned int type; + unsigned int da; + unsigned int len; + unsigned int reserved; + unsigned char name[32]; +} __attribute__((__packed__)); + +/** + * struct fw_rsc_vdev_vring - vring descriptor entry + * @da: device address + * @align: the alignment between the consumer and producer parts of the vring + * @num: num of buffers supported by this vring (must be power of two) + * @notifyid is a unique rproc-wide notify index for this vring. This notify + * index is used when kicking a remote remote_proc, to let it know that this + * vring is triggered. + * @reserved: reserved (must be zero) + * + * This descriptor is not a resource entry by itself; it is part of the + * vdev resource type (see below). + * + * Note that @da should either contain the device address where + * the remote remote_proc is expecting the vring, or indicate that + * dynamically allocation of the vring's device address is supported. + */ +struct fw_rsc_vdev_vring { + unsigned int da; + unsigned int align; + unsigned int num; + unsigned int notifyid; + unsigned int reserved; +} __attribute__((__packed__)); + +/** + * struct fw_rsc_vdev - virtio device header + * @id: virtio device id (as in virtio_ids.h) + * @notifyid is a unique rproc-wide notify index for this vdev. This notify + * index is used when kicking a remote remote_proc, to let it know that the + * status/features of this vdev have changes. + * @dfeatures specifies the virtio device features supported by the firmware + * @gfeatures is a place holder used by the host to write back the + * negotiated features that are supported by both sides. + * @config_len is the size of the virtio config space of this vdev. The config + * space lies in the resource table immediate after this vdev header. + * @status is a place holder where the host will indicate its virtio progress. + * @num_of_vrings indicates how many vrings are described in this vdev header + * @reserved: reserved (must be zero) + * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. + * + * This resource is a virtio device header: it provides information about + * the vdev, and is then used by the host and its peer remote remote_procs + * to negotiate and share certain virtio properties. + * + * By providing this resource entry, the firmware essentially asks remoteproc + * to statically allocate a vdev upon registration of the rproc (dynamic vdev + * allocation is not yet supported). + * + * Note: unlike virtualization systems, the term 'host' here means + * the Linux side which is running remoteproc to control the remote + * remote_procs. We use the name 'gfeatures' to comply with virtio's terms, + * though there isn't really any virtualized guest OS here: it's the host + * which is responsible for negotiating the final features. + * Yeah, it's a bit confusing. + * + * Note: immediately following this structure is the virtio config space for + * this vdev (which is specific to the vdev; for more info, read the virtio + * spec). the size of the config space is specified by @config_len. + */ +struct fw_rsc_vdev { + unsigned int type; + unsigned int id; + unsigned int notifyid; + unsigned int dfeatures; + unsigned int gfeatures; + unsigned int config_len; + unsigned char status; + unsigned char num_of_vrings; + unsigned char reserved[2]; + struct fw_rsc_vdev_vring vring[0]; +} __attribute__((__packed__)); + +/** + * struct remote_proc + * + * 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; +}; + +/** + * struct resc_table_info + * + * This structure is maintained by the remoteproc to allow applications + * to pass resource table info during remote initialization. + * + * @rsc_tab : pointer to resource table control block + * @size : size of resource table. + * + */ +struct rsc_table_info { + struct resource_table *rsc_tab; + int size; +}; + +/* 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 error codes */ +#define RPROC_ERR_BASE -4000 +#define RPROC_ERR_CPU_ID (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_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 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 execution + * + */ +int remoteproc_resource_init( + struct rsc_table_info *rsc_info, + rpmsg_chnl_cb_t channel_created, + rpmsg_chnl_cb_t channel_destroyed, + rpmsg_rx_cb_t default_cb, + struct remote_proc** rproc_handle); + + +/** + * remoteproc_resource_deinit + * + * Uninitializes resources for remoteproc remote configuration. + * + * @param rproc - pointer to remoteproc instance + * + * @param returns - status of execution + * + */ + +int remoteproc_resource_deinit(struct remote_proc *rproc); + +/** + * remoteproc_init + * + * Initializes resources for remoteproc master configuration. Only + * remoteproc master applications are allowed to call this function. + * + * @param fw_name - name of firmware + * @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, + rpmsg_chnl_cb_t channel_created, + rpmsg_chnl_cb_t channel_destroyed, + rpmsg_rx_cb_t default_cb, struct remote_proc** rproc_handle); + +/** + * remoteproc_deinit + * + * Uninitializes resources for remoteproc "master" configuration. + * + * @param rproc - pointer to remoteproc instance + * + * @param returns - status of function execution + * + */ +int remoteproc_deinit(struct remote_proc *rproc); + +/** + * 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); + +/** + * remoteproc_shutdown + * + * This function shutdowns the remote execution context. + * + * @param rproc - pointer to remoteproc instance to shutdown + * + * @param returns - status of function execution + */ +int remoteproc_shutdown(struct remote_proc *rproc); + +#endif /* REMOTEPROC_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.c b/ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.c new file mode 100644 index 00000000..487c9134 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +#include "remoteproc_loader.h" + +/** + * 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 = env_allocate_memory(sizeof(struct remoteproc_loader)); + + if (!loader) { + return RPROC_NULL ; + } + + /* Clear loader handle. */ + env_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. */ + env_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. */ + env_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/ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.h b/ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.h new file mode 100644 index 00000000..eeb7bb31 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/remoteproc_loader.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * FILE NAME + * + * remoteproc_loader.h + * + * COMPONENT + * + * OpenAMP stack. + * + * DESCRIPTION + * + * This file provides definitions for remoteproc loader + * + * + **************************************************************************/ +#ifndef REMOTEPROC_LOADER_H_ +#define REMOTEPROC_LOADER_H_ + +#include "remoteproc.h" + +/** + * 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. */ + +struct remoteproc_loader { + enum loader_type type; + void *remote_firmware; + /* Pointer to firmware decoded info control block */ + void *fw_decode_info; + + /* 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 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); + +#endif /* REMOTEPROC_LOADER_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/rpmsg.c b/ThirdParty/sw_services/xilopenamp/src/rpmsg.c new file mode 100644 index 00000000..ad79ca2a --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rpmsg.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * 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 "rpmsg.h" + +/** + * rpmsg_init + * + * Thus function allocates and initializes the rpmsg driver resources for + * given device ID(cpu id). The successful return from this function leaves + * fully enabled IPC link. + * + * @param dev_id - remote device for which driver is to + * be initialized + * @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 + * + */ + +int rpmsg_init(int dev_id, struct remote_device **rdev, + rpmsg_chnl_cb_t channel_created, + rpmsg_chnl_cb_t channel_destroyed, + rpmsg_rx_cb_t default_cb, int role) { + int status; + + /* Initialize IPC environment */ + status = env_init(); + if (status == RPMSG_SUCCESS) { + /* Initialize the remote device for given cpu id */ + status = rpmsg_rdev_init(rdev, dev_id, role, channel_created, + channel_destroyed, default_cb); + if (status == RPMSG_SUCCESS) { + /* Kick off IPC with the remote device */ + status = rpmsg_start_ipc(*rdev); + } + } + + /* Deinit system in case of error */ + if (status != RPMSG_SUCCESS) { + rpmsg_deinit(*rdev); + } + + return status; +} + +/** + * rpmsg_deinit + * + * Thus function frees rpmsg driver resources for given remote device. + * + * @param rdev - pointer to device to de-init + * + */ + +void rpmsg_deinit(struct remote_device *rdev) { + if (rdev) { + rpmsg_rdev_deinit(rdev); + env_deinit(); + } +} + +/** + * This function sends rpmsg "message" to remote device. + * + * @param rp_chnl - pointer to rpmsg channel + * @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 - status of function execution + * + */ + +int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, unsigned long src, + unsigned long dst, char *data, int size, int wait) { + struct remote_device *rdev; + struct rpmsg_hdr *rp_hdr; + void *buffer; + int status = RPMSG_SUCCESS; + unsigned short idx; + int tick_count = 0; + int buff_len; + + if (!rp_chnl) { + 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; + } + + /* Lock the device to enable exclusive access to virtqueues */ + env_lock_mutex(rdev->lock); + /* Get rpmsg buffer for sending message. */ + buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx); + if (!buffer && !wait) { + status = RPMSG_ERR_NO_MEM; + } + env_unlock_mutex(rdev->lock); + + if (status == RPMSG_SUCCESS) { + + while (!buffer) { + /* + * Wait parameter is true - pool the buffer for + * 15 secs as defined by the APIs. + */ + env_sleep_msec(RPMSG_TICKS_PER_INTERVAL); + env_lock_mutex(rdev->lock); + buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx); + env_unlock_mutex(rdev->lock); + tick_count += RPMSG_TICKS_PER_INTERVAL; + if (tick_count >= (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL)) { + status = RPMSG_ERR_NO_BUFF; + break; + } + } + + if (status == RPMSG_SUCCESS) { + //FIXME : may be just copy the data size equal to buffer length and Tx it. + if (size > (buff_len - sizeof(struct rpmsg_hdr))) + status = RPMSG_ERR_BUFF_SIZE; + + if (status == RPMSG_SUCCESS) { + rp_hdr = (struct rpmsg_hdr *) buffer; + + /* Initialize RPMSG header. */ + rp_hdr->dst = dst; + rp_hdr->src = src; + rp_hdr->len = size; + + /* Copy data to rpmsg buffer. */ + env_memcpy(rp_hdr->data, data, size); + + env_lock_mutex(rdev->lock); + /* Enqueue buffer on virtqueue. */ + status = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx); + if (status == RPMSG_SUCCESS) { + /* Let the other side know that there is a job to process. */ + virtqueue_kick(rdev->tvq); + } + env_unlock_mutex(rdev->lock); + } + + } + } + + /* Do cleanup in case of error.*/ + if (status != RPMSG_SUCCESS) { + rpmsg_free_buffer(rdev, buffer); + } + + return status; +} + +/** + * 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) { + struct remote_device *rdev; + int length; + + if (!rp_chnl) { + return RPMSG_ERR_PARAM; + } + + /* Get 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; + } + + env_lock_mutex(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); + } + + env_unlock_mutex(rdev->lock); + + return length; +} + +/** + * 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, unsigned long addr) { + + struct remote_device *rdev = RPMSG_NULL; + struct rpmsg_endpoint *rp_ept = RPMSG_NULL; + + if (!rp_chnl || !cb) { + return RPMSG_NULL ; + } + + rdev = rp_chnl->rdev; + + rp_ept = _create_endpoint(rdev, cb, priv, addr); + + if (rp_ept) { + rp_ept->rp_chnl = rp_chnl; + } + + return rp_ept; +} + +/** + * rpmsg_destroy_ept + * + * 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 + * + */ +void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl) { + + struct remote_device *rdev; + + if (!rp_chnl) { + 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; +} diff --git a/ThirdParty/sw_services/xilopenamp/src/rpmsg.h b/ThirdParty/sw_services/xilopenamp/src/rpmsg.h new file mode 100644 index 00000000..7e521566 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rpmsg.h @@ -0,0 +1,402 @@ +/* + * Remote processor messaging + * + * 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 _RPMSG_H_ +#define _RPMSG_H_ + +#include "rpmsg_core.h" + +/* The feature bitmap for virtio rpmsg */ +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ +#define RPMSG_NAME_SIZE 32 + +/** + * 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 + * @data: @len bytes of message payload data + * + * Every message sent(/received) on the rpmsg bus begins with this header. + */ +struct rpmsg_hdr { + unsigned long src; + unsigned long dst; + unsigned long reserved; + unsigned short len; + unsigned short flags; + unsigned char data[0]; +} __attribute__((packed)); + +/** + * 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). + */ +struct rpmsg_ns_msg { + char name[RPMSG_NAME_SIZE]; + unsigned long addr; + unsigned long flags; +} __attribute__((packed)); + +/** + * 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, +}; + +#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_channel { + char name[RPMSG_NAME_SIZE]; + unsigned long src; + unsigned long dst; + struct remote_device *rdev; + struct rpmsg_endpoint *rp_ept; + unsigned int state; +}; + +/** + * channel_info - channel info + * @name: channel name + * @src: local address + * @dst: destination address + */ + +struct channel_info { + char name[RPMSG_NAME_SIZE]; + unsigned long src; + unsigned long dest; +}; + +/** + * 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. + * + * 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()). + */ +struct rpmsg_endpoint { + struct rpmsg_channel *rp_chnl; + rpmsg_rx_cb_t cb; + unsigned long addr; + void *priv; +}; + +struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl, + rpmsg_rx_cb_t cb, void *priv, unsigned long addr); + +void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept); + +int +rpmsg_send_offchannel_raw(struct rpmsg_channel *, unsigned long, unsigned long, char *, int, int); + +/** + * rpmsg_sendto() - send a message across to the remote processor, specify dst + * @rpdev: the rpmsg channel + * @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. + * 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 0 on success and an appropriate error value on failure. + */ +static inline +int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, unsigned long dst) +{ + if (!rpdev || !data) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_raw(rpdev, rpdev->src, dst, (char *)data, len, RPMSG_TRUE); +} + +/** + * rpmsg_send() - send a message across to the remote processor + * @rpdev: the rpmsg channel + * @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. + * 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 0 on success and an appropriate error value on failure. + */ +static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len) +{ + if (!rpdev || !data) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_raw(rpdev, rpdev->src, rpdev->dst, (char*)data, len, RPMSG_TRUE); +} + +/** + * rpmsg_send_offchannel() - send a message using explicit src/dst addresses + * @rpdev: the rpmsg channel + * @src: source address + * @dst: destination address + * @data: payload of message + * @len: length of payload + * + * 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 + * 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 0 on success and an appropriate error value on failure. + */ +static inline +int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, unsigned long src, unsigned long dst, + void *data, int len) +{ + if (!rpdev || !data) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_raw(rpdev, src, dst, (char *)data, len, RPMSG_TRUE); +} + +/** + * rpmsg_trysend() - send a message across to the remote processor + * @rpdev: the rpmsg channel + * @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. + * 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 0 on success and an appropriate error value on failure. + */ +static inline +int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len) +{ + + if (!rpdev || !data) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_raw(rpdev, rpdev->src, rpdev->dst, (char *)data, len, RPMSG_FALSE); +} + +/** + * rpmsg_trysendto() - send a message across to the remote processor, specify dst + * @rpdev: the rpmsg channel + * @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. + * 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 0 on success and an appropriate error value on failure. + */ +static inline +int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, unsigned long dst) +{ + unsigned long src; + + if (!rpdev || !data) + return RPMSG_ERR_PARAM; + + src = rpdev->src; + + return rpmsg_send_offchannel_raw(rpdev, src, dst, (char *)data, len, RPMSG_FALSE); +} + +/** + * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses + * @rpdev: the rpmsg channel + * @src: source address + * @dst: destination address + * @data: payload of message + * @len: length of payload + * + * 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 + * 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 0 on success and an appropriate error value on failure. + */ +static inline +int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, unsigned long src, unsigned long dst, + void *data, int len) +{ + if (!rpdev || !data) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_raw(rpdev, src, dst, (char *)data, len, RPMSG_FALSE); +} + +/** + * rpmsg_init + * + * Thus function allocates and initializes the rpmsg driver resources for given + * device id (cpu id).The successful return from this function leaves + * fully enabled IPC link. + * + * @param dev_id - rpmsg remote device for which driver is to + * be initialized + * @param rdev - pointer to newly created remote device + * @param channel_created - callback function for channel creation + * @param channel_destroyed - callback function for channel deletion + * @default_cb - default callback for channel + * @param role - role of the other device, Master or Remote + * @return - status of function execution + * + */ + +int rpmsg_init(int dev_id, 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 + * + * @return - none + * + */ +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); + +/** + * rpmsg_create_channel + * + * Creates RPMSG channel with the given name for remote device. + * + * @param rdev - pointer to rpmsg remote device + * @param name - channel name + * + * @return - pointer to new rpmsg channel + * + */ +struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev, char *name); + +/** + * 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 + * + */ +void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl); + +#endif /* _RPMSG_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/rpmsg_core.c b/ThirdParty/sw_services/xilopenamp/src/rpmsg_core.c new file mode 100644 index 00000000..3a72f3c9 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rpmsg_core.c @@ -0,0 +1,766 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * 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 "rpmsg.h" + +/* Internal functions */ +static void rpmsg_rx_callback(struct virtqueue *vq); +static void rpmsg_tx_callback(struct virtqueue *vq); + +/** + * 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; + } + } + + status = rpmsg_rdev_notify(rdev); + + 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; + struct llist *node; + + rp_chnl = env_allocate_memory(sizeof(struct rpmsg_channel)); + if (rp_chnl) { + env_memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel)); + env_strncpy(rp_chnl->name, name, sizeof(rp_chnl->name)); + rp_chnl->src = src; + rp_chnl->dst = dst; + rp_chnl->rdev = rdev; + /* Place channel on channels list */ + node = env_allocate_memory(sizeof(struct llist)); + if (!node) { + env_free_memory(rp_chnl); + return RPMSG_NULL ; + } + node->data = rp_chnl; + env_lock_mutex(rdev->lock); + add_to_list(&rdev->rp_channels , node); + env_unlock_mutex(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) { + struct llist *node; + if (rp_chnl) { + node = rpmsg_rdev_get_chnl_node_from_id(rp_chnl->rdev, rp_chnl->name); + if (node) { + env_lock_mutex(rp_chnl->rdev->lock); + remove_from_list(&rp_chnl->rdev->rp_channels, node); + env_unlock_mutex(rp_chnl->rdev->lock); + env_free_memory(node); + } + env_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; + struct llist *node; + int status = RPMSG_SUCCESS; + + rp_ept = env_allocate_memory(sizeof(struct rpmsg_endpoint)); + if (!rp_ept) { + return RPMSG_NULL ; + } + + node = env_allocate_memory(sizeof(struct llist)); + if (!node) { + env_free_memory(rp_ept); + return RPMSG_NULL; + } + + env_lock_mutex(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 (addr < 0) { + status = RPMSG_ERR_DEV_ADDR; + } + } + + /* Do cleanup in case of error and return */ + if (status) { + env_free_memory(node); + env_free_memory(rp_ept); + env_unlock_mutex(rdev->lock); + return RPMSG_NULL; + } + + rp_ept->addr = addr; + rp_ept->cb = cb; + rp_ept->priv = priv; + + node->data = rp_ept; + add_to_list(&rdev->rp_endpoints, node); + + env_unlock_mutex(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) { + struct llist *node; + node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_ept->addr); + if (node) { + env_lock_mutex(rdev->lock); + rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, rp_ept->addr); + remove_from_list(&rdev->rp_endpoints, node); + env_unlock_mutex(rdev->lock); + env_free_memory(node); + } + env_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 + * + */ +void 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; + int len; + + env_lock_mutex(rdev->lock); + + /* Get Tx buffer. */ + rp_hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &len, &idx); + if (!rp_hdr) + return; + + /* Fill out name service data. */ + rp_hdr->dst = RPMSG_NS_EPT_ADDR; + rp_hdr->len = sizeof(struct rpmsg_ns_msg); + ns_msg = (struct rpmsg_ns_msg *) rp_hdr->data; + env_strncpy(ns_msg->name, rp_chnl->name, sizeof(rp_chnl->name)); + ns_msg->flags = flags; + ns_msg->addr = rp_chnl->src; + + /* Place the buffer on virtqueue. */ + rpmsg_enqueue_buffer(rdev, rp_hdr, len, idx); + + /* Notify the other side that it has data to process. */ + virtqueue_kick(rdev->tvq); + + env_unlock_mutex(rdev->lock); +} + +/** + * 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) { + struct llist node; + int status; + + /* Initialize buffer node */ + node.data = buffer; + node.attr = len; + node.next = RPMSG_NULL; + node.prev = RPMSG_NULL; + + if (rdev->role == RPMSG_REMOTE) { + status = virtqueue_add_buffer(rdev->tvq, &node, 0, 1, buffer); + } else { + 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 llist node; + + /* Initialize buffer node */ + node.data = buffer; + node.attr = len; + node.next = RPMSG_NULL; + node.prev = RPMSG_NULL; + + if (rdev->role == RPMSG_REMOTE) { + virtqueue_add_buffer(rdev->rvq, &node, 0, 1, buffer); + } else { + 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, int *len, + unsigned short *idx) { + void *data; + + if (rdev->role == RPMSG_REMOTE) { + data = virtqueue_get_buffer(rdev->tvq, (unsigned long *) len); + 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, + (unsigned long *) len); + } + return ((void *) env_map_vatopa(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, len); + } else { + data = virtqueue_get_available_buffer(rdev->rvq, idx, len); + } + return ((void *) env_map_vatopa(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(rdev->mem_pool, buffer); + } +} + +/** + * 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 llist *chnl_hd; + + vdev = (struct virtio_device *) vq->vq_dev; + rdev = (struct remote_device *) vdev; + chnl_hd = rdev->rp_channels; + + /* 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. + */ + while (chnl_hd != RPMSG_NULL) { + rp_chnl = (struct rpmsg_channel *) chnl_hd->data; + + if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) { + + if (rdev->support_ns) { + rp_chnl->state = RPMSG_CHNL_STATE_NS; + } else { + rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE; + } + + if (rp_chnl->state == RPMSG_CHNL_STATE_NS) { + rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE); + } + } + + chnl_hd = chnl_hd->next; + } + } +} + +/** + * 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 llist *node; + unsigned long len; + unsigned short idx; + struct llist *chnl_hd; + + vdev = (struct virtio_device *) vq->vq_dev; + rdev = (struct remote_device *) vdev; + + chnl_hd = rdev->rp_channels; + if ((chnl_hd != RPMSG_NULL) && (rdev->role == RPMSG_MASTER)) { + rp_chnl = (struct rpmsg_channel *) chnl_hd->data; + if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) { + if (rdev->support_ns) { + rp_chnl->state = RPMSG_CHNL_STATE_NS; + rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE); + } else { + rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE; + } + return; + } + } + + env_lock_mutex(rdev->lock); + + /* Process the received data from remote node */ + rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx); + + env_unlock_mutex(rdev->lock); + + if (!rp_hdr) { + return; + } + + /* Get the channel node from the remote device channels list. */ + node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst); + + if (!node) + /* Fatal error no endpoint for the given dst addr. */ + return; + + rp_ept = (struct rpmsg_endpoint *) node->data; + + 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 */ + 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, rp_hdr->data, rp_hdr->len, rp_ept->priv, + rp_hdr->src); + } + + env_lock_mutex(rdev->lock); + + /* Return used buffers. */ + rpmsg_return_buffer(rdev, rp_hdr, len, idx); + + env_unlock_mutex(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; + struct llist *node; + + 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; + ns_msg->name[len - 1] = '\0'; + + if (ns_msg->flags & RPMSG_NS_DESTROY) { + node = rpmsg_rdev_get_chnl_node_from_id(rdev, ns_msg->name); + if (node) { + rp_chnl = (struct rpmsg_channel *) node->data; + if (rdev->channel_destroyed) { + rdev->channel_destroyed(rp_chnl); + } + rpmsg_destroy_ept(rp_chnl->rp_ept); + _rpmsg_delete_channel(rp_chnl); + } + } else { + rp_chnl = _rpmsg_create_channel(rdev, ns_msg->name, 0x00, ns_msg->addr); + if (rp_chnl) { + rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE; + /* Create default endpoint for channel */ + 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; + /* + * Echo back the NS message to remote in order to + * complete the connection stage. Remote will know the endpoint + * address from this point onward which will enable it to send + * message without waiting for any application level message from + * master. + */ + rpmsg_send(rp_chnl,data,len); + 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 + 1; + 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/ThirdParty/sw_services/xilopenamp/src/rpmsg_core.h b/ThirdParty/sw_services/xilopenamp/src/rpmsg_core.h new file mode 100644 index 00000000..30e00143 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rpmsg_core.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef _RPMSG_CORE_H_ +#define _RPMSG_CORE_H_ + +#include "env.h" +#include "virtio.h" +#include "hil.h" +#include "sh_mem.h" +#include "llist.h" +#include "rpmsg.h" + +/* 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_ERRORS_BASE -3000 +#define RPMSG_ERR_NO_MEM (RPMSG_ERRORS_BASE - 1) +#define RPMSG_ERR_NO_BUFF (RPMSG_ERRORS_BASE - 2) +#define RPMSG_ERR_MAX_VQ (RPMSG_ERRORS_BASE - 3) +#define RPMSG_ERR_PARAM (RPMSG_ERRORS_BASE - 4) +#define RPMSG_ERR_DEV_STATE (RPMSG_ERRORS_BASE - 5) +#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERRORS_BASE - 6) +#define RPMSG_ERR_DEV_ID (RPMSG_ERRORS_BASE - 7) +#define RPMSG_ERR_DEV_ADDR (RPMSG_ERRORS_BASE - 8) + +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 llist *rp_channels; + struct llist *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; + LOCK *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); +void 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, int *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 remote_device **rdev, int dev_id, 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); +struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev, + char *rp_chnl_id); +struct llist *rpmsg_rdev_get_chnl_from_addr(struct remote_device *rdev, + unsigned long addr); +struct llist *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); + +unsigned long rpmsg_rdev_get_feature(struct virtio_device *dev); + +void rpmsg_rdev_set_feature(struct virtio_device *dev, unsigned long feature); + +unsigned long rpmsg_rdev_negotiate_feature(struct virtio_device *dev, + unsigned long 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, unsigned long offset, + void *dst, int length); +void rpmsg_rdev_write_config(struct virtio_device *dev, unsigned long offset, + void *src, int length); +void rpmsg_rdev_reset(struct virtio_device *dev); + +#endif /* _RPMSG_CORE_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.c b/ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.c new file mode 100644 index 00000000..4d45c0e7 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.c @@ -0,0 +1,245 @@ +#include "open_amp.h" +#include "rpmsg_retarget.h" +#include +#include +#include +#include "sleep.h" + + + +/************************************************************************* + * Description + * This files contains rpmsg based redefinitions for C RTL system calls + * such as _open, _read, _write, _close. + *************************************************************************/ +static struct _rpc_data* rpc_data; +static unsigned int rpc_data_synclock = 0; +int get_response = 0; + +int send_rpc(void *data, int len); +static int rpc_count=0; + +void rpc_cb(struct rpmsg_channel *rtl_rp_chnl, void *data, int len, void * priv, + unsigned long src) { + memcpy(rpc_data->rpc_response, data, len); + env_release_sync_lock(rpc_data->sync_lock); + get_response=1; + + + 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); + } +} + +int send_rpc(void *data, int len) { + int retval; + + retval = rpmsg_sendto(rpc_data->rpmsg_chnl, data, len, PROXY_ENDPOINT); + return retval; +} + + + +int rpmsg_retarget_init(struct rpmsg_channel *rp_chnl, rpc_shutdown_cb cb) { + int status; + + /* Allocate memory for rpc control block */ + rpc_data = (struct _rpc_data*) env_allocate_memory( + sizeof(struct _rpc_data)); + + /* Create a mutex for synchronization */ + status = env_create_mutex(&rpc_data->rpc_lock, 1); + + /* Create a mutex for synchronization */ + status = env_create_sync_lock(&rpc_data->sync_lock, LOCKED); + + /* 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 = env_allocate_memory(RPC_BUFF_SIZE); + rpc_data->rpc_response = env_allocate_memory(RPC_BUFF_SIZE); + rpc_data->shutdown_cb = cb; + + return status; +} + +int rpmsg_retarget_deinit(struct rpmsg_channel *rp_chnl) { + env_free_memory(rpc_data->rpc); + env_free_memory(rpc_data->rpc_response); + env_delete_mutex(rpc_data->rpc_lock); + env_delete_sync_lock(rpc_data->sync_lock); + rpmsg_destroy_ept(rpc_data->rp_ept); + env_free_memory(rpc_data); + + return 0; +} + +/************************************************************************* + * + * FUNCTION + * + * _open + * + * DESCRIPTION + * + * Open a file. Minimal implementation + * + *************************************************************************/ +int _open(const char * filename, int flags, int mode) { + int filename_len = strlen(filename) + 1; + int payload_size = sizeof(struct _sys_rpc) + filename_len; + int retval = -1; + + if ((!filename) || (filename_len > FILE_NAME_LEN)) { + return -1; + } + + /* 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 */ + env_lock_mutex(rpc_data->rpc_lock); + send_rpc((void*) rpc_data->rpc, payload_size); + env_unlock_mutex(rpc_data->rpc_lock); + + /* Wait for response from proxy on master */ + env_acquire_sync_lock(rpc_data->sync_lock); + + /* 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; + } + + return retval; +} + +/************************************************************************* + * + * FUNCTION + * + * _read + * + * DESCRIPTION + * + * Low level function to redirect IO to serial. + * + *************************************************************************/ +int _read(int fd, char * buffer, int buflen) { + int payload_size = sizeof(struct _sys_rpc); + int retval = -1; + + if (!buffer || !buflen) + return retval; + + /* 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 */ + env_lock_mutex(rpc_data->rpc_lock); + get_response=0; + send_rpc((void*) rpc_data->rpc, payload_size); + env_unlock_mutex(rpc_data->rpc_lock); + + /* Wait for response from proxy on master */ + env_acquire_sync_lock(rpc_data->sync_lock); + + /* 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); + } + + retval = rpc_data->rpc_response->sys_call_args.int_field1; + } + + return retval; +} + +/************************************************************************* + * + * FUNCTION + * + * _write + * + * DESCRIPTION + * + * Low level function to redirect IO to serial. + * + *************************************************************************/ +int _write(int fd, const char * ptr, int len) { + int retval = -1; + int payload_size = sizeof(struct _sys_rpc) + len; + int null_term = 0; + + if (fd == 1) { + null_term = 1; + } + + 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; + } + + env_lock_mutex(rpc_data->rpc_lock); + send_rpc((void*) rpc_data->rpc, payload_size); + env_unlock_mutex(rpc_data->rpc_lock); + + env_acquire_sync_lock(rpc_data->sync_lock); + + if (rpc_data->rpc_response->id == WRITE_SYSCALL_ID) { + retval = rpc_data->rpc_response->sys_call_args.int_field1; + } + + return retval; + +} + +/************************************************************************* + * + * FUNCTION + * + * _close + * + * DESCRIPTION + * + * Close a file. Minimal implementation + * + *************************************************************************/ +int _close(int fd) { + int payload_size = sizeof(struct _sys_rpc); + int retval = -1; + + 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*/ + + env_lock_mutex(rpc_data->rpc_lock); + send_rpc((void*) rpc_data->rpc, payload_size); + env_unlock_mutex(rpc_data->rpc_lock); + + /* Wait for response from proxy on master */ + env_acquire_sync_lock(rpc_data->sync_lock); + + if (rpc_data->rpc_response->id == CLOSE_SYSCALL_ID) { + retval = rpc_data->rpc_response->sys_call_args.int_field1; + } + + return retval; +} diff --git a/ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.h b/ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.h new file mode 100644 index 00000000..cb268b35 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rpmsg_retarget.h @@ -0,0 +1,52 @@ +#include "open_amp.h" +/* RPC response buffer size */ +#define RPC_BUFF_SIZE 512 + +/* 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 FILE_NAME_LEN 50 + +/* Proxy device endpoint ID */ +#define PROXY_ENDPOINT 127 + +typedef void (*rpc_shutdown_cb)(struct rpmsg_channel *); + +struct _rpc_data +{ + struct rpmsg_channel* rpmsg_chnl; + struct rpmsg_endpoint* rp_ept; + void* rpc_lock; + void* sync_lock; + struct _sys_rpc* rpc; + struct _sys_rpc* rpc_response; + rpc_shutdown_cb shutdown_cb; +}; + +struct _sys_call_args +{ + int int_field1; + int int_field2; + unsigned int data_len; + char data[0]; +}; + +/* System call rpc data structure */ +struct _sys_rpc +{ + unsigned int id; + struct _sys_call_args sys_call_args; +}; + + +void debug_print(char* str, int len); + +/* API prototypes */ +int rpmsg_retarget_init(struct rpmsg_channel *rp_chnl, rpc_shutdown_cb cb); +int rpmsg_retarget_deinit(struct rpmsg_channel *rp_chnl); diff --git a/ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.c b/ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.c new file mode 100644 index 00000000..5675adeb --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +#include "rsc_table_parser.h" + +/* Resources handler */ +rsc_handler rsc_handler_table[] = +{ + handle_carve_out_rsc, + handle_trace_rsc, + handle_dev_mem_rsc, + handle_vdev_rsc, + handle_mmu_rsc +}; + +/** + * 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) { + + unsigned char *rsc_start; + unsigned int *rsc_offset; + unsigned int rsc_type; + int idx, status = 0; + + /* Validate rsc table header fields*/ + + /* Minimum rsc table size */ + if (sizeof(struct resource_table) > size) { + return (RPROC_ERR_RSC_TAB_TRUNC); + } + + /* Supported version */ + if (rsc_table->ver != RSC_TAB_SUPPORTED_VERSION) { + return (RPROC_ERR_RSC_TAB_VER); + } + + /* Offset array */ + if (sizeof(struct resource_table) + + rsc_table->num * sizeof(rsc_table->offset[0]) > 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; + } + + rsc_start = (unsigned char *) rsc_table; + + /* 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; + } + } + + return status; +} + +/** + * handle_carve_out_rsc + * + * Carveout resource handler. + * + * @param rproc - pointer to remote remote_proc + * @param rsc - pointer to carveout resource + * + * @returns - execution status + * + */ +int handle_carve_out_rsc(struct remote_proc *rproc, void *rsc) { + struct fw_rsc_carveout *carve_rsc = (struct fw_rsc_carveout *) rsc; + + /* Validate resource fields */ + if (!carve_rsc) { + return RPROC_ERR_RSC_TAB_NP; + } + + if (carve_rsc->reserved) { + return RPROC_ERR_RSC_TAB_RSVD; + } + + if (rproc->role == RPROC_MASTER) { + /* Map memory region for loading the image */ + env_map_memory(carve_rsc->da, carve_rsc->da, carve_rsc->len, + (SHARED_MEM | UNCACHED)); + } + + return RPROC_SUCCESS; +} + +/** + * 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) { + 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) { + 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) { + + struct fw_rsc_vdev *vdev_rsc = (struct fw_rsc_vdev *) rsc; + struct fw_rsc_vdev_vring *vring; + struct proc_vdev *vdev; + struct proc_vring *vring_table; + int idx; + + 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; + } + + /* Reserved fields - must be zero */ + if (vdev_rsc->reserved[0] || vdev_rsc->reserved[1]) { + return RPROC_ERR_RSC_TAB_RSVD; + } + + /* 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; + vring_table = &vdev->vring_info[0]; + + for (idx = 0; idx < vdev_rsc->num_of_vrings; idx++) { + vring = &vdev_rsc->vring[idx]; + + /* Initialize HIL vring resources */ + vring_table[idx].phy_addr = (void *) vring->da; + vring_table[idx].num_descs = vring->num; + vring_table[idx].align = vring->align; + + /* Enable access to vring memory regions */ + env_map_memory(vring->da, vring->da, + vring_size(vring->num, vring->align), + (SHARED_MEM | UNCACHED)); + } + + return RPROC_SUCCESS; +} + +/** + * 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) { + return RPROC_ERR_RSC_TAB_NS; +} diff --git a/ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.h b/ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.h new file mode 100644 index 00000000..d286badd --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/rsc_table_parser.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RSC_TABLE_PARSER_H +#define RSC_TABLE_PARSER_H + +#include "remoteproc.h" +#include "env.h" +#include "hil.h" + +#define RSC_TAB_SUPPORTED_VERSION 1 +#define RSC_TAB_HEADER_SIZE 12 +#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_mmu_rsc(struct remote_proc *rproc, void *rsc); + +#endif /* RSC_TABLE_PARSER_H */ diff --git a/ThirdParty/sw_services/xilopenamp/src/sh_mem.c b/ThirdParty/sw_services/xilopenamp/src/sh_mem.c new file mode 100644 index 00000000..6a290a48 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/sh_mem.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ +/************************************************************************** + * 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 "sh_mem.h" + +/** + * 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 status, 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) + WORD_SIZE * bmp_size; + + /* Create pool control block. */ + mem_pool = env_allocate_memory(pool_size); + + if (mem_pool) { + /* Initialize pool parameters */ + env_memset(mem_pool, 0x00, pool_size); + status = env_create_mutex(&mem_pool->lock , 1); + if (status){ + env_free_memory(mem_pool); + return NULL; + } + 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 idx, bit_idx; + + if (!pool) + return NULL; + + env_lock_mutex(pool->lock); + + if (pool->used_buffs >= pool->total_buffs) { + env_unlock_mutex(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(pool->bitmap[idx]); + if (bit_idx < 32) { + /* Set bit to mark it as consumed. */ + pool->bitmap[idx] |= (1 << bit_idx); + buff = (char *) pool->start_addr + + pool->buff_size * (idx * BITMAP_WORD_SIZE + bit_idx); + pool->used_buffs++; + break; + } + } + + env_unlock_mutex(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 */ + env_lock_mutex(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 = &pool->bitmap[bmp_idx]; + + /* Mark the buffer as free */ + *bitmask ^= (1 << bit_idx); + + pool->used_buffs--; + + /* Release the pool lock. */ + env_unlock_mutex(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) { + env_delete_mutex(pool->lock); + env_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 + */ +unsigned int get_first_zero_bit(unsigned long value) { + unsigned int idx; + unsigned int tmp32; + + /* Invert value */ + value = ~value; + + /* (~value) & (2's complement of value) */ + value = (value & (-value)) - 1; + + /* log2(value) */ + + tmp32 = value - ((value >> 1) & 033333333333) + - ((value >> 2) & 011111111111); + + idx = ((tmp32 + (tmp32 >> 3)) & 030707070707) % 63; + + return idx; +} diff --git a/ThirdParty/sw_services/xilopenamp/src/sh_mem.h b/ThirdParty/sw_services/xilopenamp/src/sh_mem.h new file mode 100644 index 00000000..0214aca5 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/sh_mem.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * 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 Mentor Graphics Corporation 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. + */ + +/************************************************************************** + * 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 "env.h" + + +/* Macros */ +#define BITMAP_WORD_SIZE 32 +#define WORD_SIZE sizeof(unsigned long) +#define WORD_ALIGN(a) (((a) & (WORD_SIZE-1)) != 0)? \ + (((a) & (~(WORD_SIZE-1))) + 4):(a) +/* + * 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 + * @bitmap - array to keep record of free and used blocks + * + */ + +struct sh_mem_pool { + void *start_addr; + LOCK *lock; + int size; + int buff_size; + int total_buffs; + int used_buffs; + int bmp_size; + unsigned long bitmap[0]; +}; + +/* 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); +unsigned int get_first_zero_bit(unsigned long value); + +#endif /* SH_MEM_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/virtio.c b/ThirdParty/sw_services/xilopenamp/src/virtio.c new file mode 100644 index 00000000..0a7514f2 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/virtio.c @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2011, Bryan Venteicher + * 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 unmodified, 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 AUTHOR ``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 AUTHOR 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 "virtio.h" + +static const char *virtio_feature_name(unsigned long feature, struct virtio_feature_desc *); + +//TODO : This structure may change depending on the types of devices we support. +static struct virtio_ident { + unsigned short devid; + const char *name; +} virtio_ident_table[] = { + { VIRTIO_ID_NETWORK, "Network" }, + { VIRTIO_ID_BLOCK, "Block" }, + { VIRTIO_ID_CONSOLE, "Console" }, + { VIRTIO_ID_ENTROPY, "Entropy" }, + { VIRTIO_ID_BALLOON, "Balloon" }, + { VIRTIO_ID_IOMEMORY, "IOMemory" }, + { VIRTIO_ID_SCSI, "SCSI" }, + { VIRTIO_ID_9P, "9P Transport" }, + + { 0, NULL } +}; + +/* Device independent features. */ +static struct virtio_feature_desc virtio_common_feature_desc[] = { + { VIRTIO_F_NOTIFY_ON_EMPTY, "NotifyOnEmpty" }, + { VIRTIO_RING_F_INDIRECT_DESC, "RingIndirect" }, + { VIRTIO_RING_F_EVENT_IDX, "EventIdx" }, + { VIRTIO_F_BAD_FEATURE, "BadFeature" }, + + { 0, NULL } +}; + +const char * +virtio_dev_name(unsigned short devid) +{ + struct virtio_ident *ident; + + for (ident = virtio_ident_table; ident->name != NULL; ident++) { + if (ident->devid == devid) + return (ident->name); + } + + return (NULL); +} + +static const char * +virtio_feature_name(unsigned long val, struct virtio_feature_desc *desc) +{ + int i, j; + struct virtio_feature_desc *descs[2] = { desc, + virtio_common_feature_desc }; + + for (i = 0; i < 2; i++) { + if (descs[i] == NULL) + continue; + + for (j = 0; descs[i][j].vfd_val != 0; j++) { + if (val == descs[i][j].vfd_val) + return (descs[i][j].vfd_str); + } + } + + return (NULL); +} + +void virtio_describe(struct virtio_device *dev, const char *msg, + uint32_t features, struct virtio_feature_desc *desc) +{ + // TODO: Not used currently - keeping it for future use + virtio_feature_name(0,desc); +} diff --git a/ThirdParty/sw_services/xilopenamp/src/virtio.h b/ThirdParty/sw_services/xilopenamp/src/virtio.h new file mode 100644 index 00000000..fce105b2 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/virtio.h @@ -0,0 +1,151 @@ +/*- + * This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * 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 IBM 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 IBM 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. + * + * $FreeBSD$ + */ + +#ifndef _VIRTIO_H_ +#define _VIRTIO_H_ + +#include "virtqueue.h" + +/* 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 + +/* Status byte for guest to report progress. */ +#define VIRTIO_CONFIG_STATUS_RESET 0x00 +#define VIRTIO_CONFIG_STATUS_ACK 0x01 +#define VIRTIO_CONFIG_STATUS_DRIVER 0x02 +#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 +#define VIRTIO_CONFIG_STATUS_FAILED 0x80 + +/* + * Generate interrupt when the virtqueue ring is + * completely used, even if we've suppressed them. + */ +#define VIRTIO_F_NOTIFY_ON_EMPTY (1 << 24) + +/* + * The guest should never negotiate this feature; it + * is used to detect faulty drivers. + */ +#define VIRTIO_F_BAD_FEATURE (1 << 30) + +/* + * Some VirtIO feature bits (currently bits 28 through 31) are + * reserved for the transport being used (eg. virtio_ring), the + * rest are per-device feature bits. + */ +#define VIRTIO_TRANSPORT_F_START 28 +#define VIRTIO_TRANSPORT_F_END 32 + +typedef struct _virtio_dispatch_ virtio_dispatch; + +struct virtio_feature_desc { + uint32_t vfd_val; + const char *vfd_str; +}; + +/* + * 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; +}; + +/* + * Helper functions. + */ +const char *virtio_dev_name(uint16_t devid); +void virtio_describe(struct virtio_device *dev, const char *msg, + uint32_t features, struct virtio_feature_desc *feature_desc); + +/* + * 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, 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 (*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); + +}; + +#endif /* _VIRTIO_H_ */ diff --git a/ThirdParty/sw_services/xilopenamp/src/virtio_ring.h b/ThirdParty/sw_services/xilopenamp/src/virtio_ring.h new file mode 100644 index 00000000..8e902ab5 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/virtio_ring.h @@ -0,0 +1,165 @@ +/*- + * Copyright Rusty Russell IBM Corporation 2007. + * + * This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * 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 IBM 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 IBM 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. + * + * $FreeBSD$ + */ + +#ifndef VIRTIO_RING_H +#define VIRTIO_RING_H + +/* This marks a buffer as continuing via the next field. */ +#define VRING_DESC_F_NEXT 1 +/* This marks a buffer as write-only (otherwise read-only). */ +#define VRING_DESC_F_WRITE 2 +/* This means the buffer contains a list of buffer descriptors. */ +#define VRING_DESC_F_INDIRECT 4 + +/* 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. */ +#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. */ +#define VRING_AVAIL_F_NO_INTERRUPT 1 + +/* VirtIO ring descriptors: 16 bytes. + * These can chain together via "next". */ +struct vring_desc { + /* Address (guest-physical). */ + uint64_t addr; + /* Length. */ + uint32_t len; + /* The flags as indicated above. */ + uint16_t flags; + /* We chain unused descriptors via this, too. */ + uint16_t next; +}; + +struct vring_avail { + uint16_t flags; + uint16_t idx; + uint16_t ring[0]; +}; + +/* uint32_t is used here for ids for padding reasons. */ +struct vring_used_elem { + /* Index of start of used descriptor chain. */ + uint32_t id; + /* Total length of the descriptor chain which was written to. */ + uint32_t len; +}; + +struct vring_used { + uint16_t flags; + uint16_t idx; + struct vring_used_elem ring[0]; +}; + +struct vring { + unsigned int num; + + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; +}; + +/* The standard layout for the ring is a continuous chunk of memory which + * looks like this. We assume num is a power of 2. + * + * struct vring { + * // The actual descriptors (16 bytes each) + * struct vring_desc desc[num]; + * + * // A ring of available descriptor heads with free-running index. + * __u16 avail_flags; + * __u16 avail_idx; + * __u16 available[num]; + * __u16 used_event_idx; + * + * // Padding to the next align boundary. + * char pad[]; + * + * // A ring of used descriptor heads with free-running index. + * __u16 used_flags; + * __u16 used_idx; + * struct vring_used_elem used[num]; + * __u16 avail_event_idx; + * }; + * + * NOTE: for VirtIO PCI, align is 4096. + */ + +/* + * We publish the used event index at the end of the available ring, and vice + * versa. They are at the end for backwards compatibility. + */ +#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) +#define vring_avail_event(vr) (*(uint16_t *)&(vr)->used->ring[(vr)->num]) + +static inline int +vring_size(unsigned int num, unsigned long align) +{ + int size; + + size = num * sizeof(struct vring_desc); + size += sizeof(struct vring_avail) + (num * sizeof(uint16_t)) + + sizeof(uint16_t); + size = (size + align - 1) & ~(align - 1); + size += sizeof(struct vring_used) + + (num * sizeof(struct vring_used_elem)) + sizeof(uint16_t); + return (size); +} + +static inline void +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 = (void *) + (((unsigned long) &vr->avail->ring[num] + align-1) & ~(align-1)); +} + +/* + * The following is used with VIRTIO_RING_F_EVENT_IDX. + * + * Assuming a given event_idx value from the other size, if we have + * just incremented index from old to new_idx, should we trigger an + * event? + */ +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); +} +#endif /* VIRTIO_RING_H */ diff --git a/ThirdParty/sw_services/xilopenamp/src/virtqueue.c b/ThirdParty/sw_services/xilopenamp/src/virtqueue.c new file mode 100644 index 00000000..2d36fe37 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/virtqueue.c @@ -0,0 +1,691 @@ +/*- + * Copyright (c) 2011, Bryan Venteicher + * 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 unmodified, 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 AUTHOR ``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 AUTHOR 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 "virtqueue.h" + +/* Prototype for internal functions. */ +static void vq_ring_init(struct virtqueue *); +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 llist *, 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); + +/** + * virtqueue_create - Creates new VirtIO queue + * + * @param device - Pointer to VirtIO device + * @param id - VirtIO queue ID , must be unique + * @param name - Name of VirtIO queue + * @param ring - Pointer to vring_alloc_info control block + * @param callback - Pointer to callback function, invoked + * 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 v_queue - Created VirtIO queue. + * + * @return - Function status + */ +int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, char *name, + struct vring_alloc_info *ring, void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue **v_queue) { + + struct virtqueue *vq = VQ_NULL; + int status = VQUEUE_SUCCESS; + uint32_t vq_size = 0; + + VQ_PARAM_CHK(ring == VQ_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); + + //TODO : Error check for indirect buffer addition + + if (status == VQUEUE_SUCCESS) { + + vq_size = sizeof(struct virtqueue) + + (ring->num_descs) * sizeof(struct vq_desc_extra); + vq = (struct virtqueue *) env_allocate_memory(vq_size); + + if (vq == VQ_NULL) { + return (ERROR_NO_MEM); + } + + env_memset(vq, 0x00, vq_size); + + vq->vq_dev = virt_dev; + env_strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ); + vq->vq_queue_index = id; + vq->vq_alignment = ring->align; + vq->vq_nentries = ring->num_descs; + vq->vq_free_cnt = vq->vq_nentries; + vq->callback = callback; + vq->notify = notify; + + //TODO : Whether we want to support indirect addition or not. + vq->vq_ring_size = vring_size(ring->num_descs, ring->align); + vq->vq_ring_mem = (void *) ring->phy_addr; + + /* Initialize vring control block in virtqueue. */ + vq_ring_init(vq); + + /* Disable callbacks - will be enabled by the application + * once initialization is completed. + */ + virtqueue_disable_cb(vq); + + *v_queue = vq; + + //TODO : Need to add cleanup in case of error used with the indirect buffer addition + //TODO: do we need to save the new queue in db based on its id + } + + return (status); +} + +/** + * virtqueue_add_buffer() - Enqueues new buffer in vring for consumption + * by other side. Readable buffers are always + * inserted before writable buffers + * + * @param vq - Pointer to VirtIO queue control block. + * @param buffer - Pointer to buffer list + * @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 llist *buffer, + int readable, int writable, void *cookie) { + + struct vq_desc_extra *dxp = VQ_NULL; + int status = VQUEUE_SUCCESS; + uint16_t head_idx; + uint16_t idx; + int needed; + + needed = readable + writable; + + VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(needed < 1, status, ERROR_VQUEUE_INVLD_PARAM); + VQ_PARAM_CHK(vq->vq_free_cnt == 0, status, ERROR_VRING_FULL); + + //TODO: Add parameters validation for indirect buffer addition + + VQUEUE_BUSY(vq); + + if (status == VQUEUE_SUCCESS) { + + //TODO : Indirect buffer addition support + + VQASSERT(vq, cookie != VQ_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 == VQ_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, buffer, + readable, writable); + + vq->vq_desc_head_idx = idx; + vq->vq_free_cnt -= needed; + + if (vq->vq_free_cnt == 0) + VQ_RING_ASSERT_CHAIN_TERM(vq); + else + VQ_RING_ASSERT_VALID_IDX(vq, idx); + + /* + * Update vring_avail control block fields so that other + * side can get buffer using it. + */ + vq_ring_update_avail(vq, head_idx); + } + + 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 buffer_addr - Address of buffer + * @param len - Length of buffer + * @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, + void *buffer_addr, uint_t len, 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 == 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 != VQ_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 = env_map_vatopa(buffer_addr); + dp->len = 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); +} + +/** + * virtqueue_get_buffer - Returns used buffers from VirtIO queue + * + * @param vq - Pointer to VirtIO queue control block + * @param len - Length of conumed buffer + * + * @return - Pointer to used buffer + */ +void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len) { + struct vring_used_elem *uep; + void *cookie; + uint16_t used_idx, desc_idx; + + if ((vq == VQ_NULL) || (vq->vq_used_cons_idx == vq->vq_ring.used->idx)) + return (VQ_NULL); + + VQUEUE_BUSY(vq); + + used_idx = vq->vq_used_cons_idx++ & (vq->vq_nentries - 1); + uep = &vq->vq_ring.used->ring[used_idx]; + + env_rmb(); + + desc_idx = (uint16_t) uep->id; + if (len != VQ_NULL) + *len = uep->len; + + vq_ring_free_chain(vq, desc_idx); + + cookie = vq->vq_descx[desc_idx].cookie; + vq->vq_descx[desc_idx].cookie = VQ_NULL; + + VQUEUE_IDLE(vq); + + return (cookie); +} + +/** + * virtqueue_free - Frees VirtIO queue resources + * + * @param vq - Pointer to VirtIO queue control block + * + */ +void virtqueue_free(struct virtqueue *vq) { + + if (vq != VQ_NULL) { + + if (vq->vq_free_cnt != vq->vq_nentries) { + env_print("\r\nWARNING %s: freeing non-empty virtqueue\r\n", vq->vq_name); + } + + //TODO : Need to free indirect buffers here + + if (vq->vq_ring_mem != VQ_NULL) { + vq->vq_ring_size = 0; + vq->vq_ring_mem = VQ_NULL; + } + + env_free_memory(vq); + } +} + +/** + * virtqueue_get_available_buffer - Returns buffer available for use in the + * VirtIO queue + * + * @param vq - Pointer to VirtIO queue control block + * @param avail_idx - Pointer to index used in vring desc table + * @param len - Length of buffer + * + * @return - Pointer to available buffer + */ +void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, + uint32_t *len) { + + uint16_t head_idx = 0; + void *buffer; + + if (vq->vq_available_idx == vq->vq_ring.avail->idx) { + return (VQ_NULL); + } + + VQUEUE_BUSY(vq); + + head_idx = vq->vq_available_idx++ & (vq->vq_nentries - 1); + *avail_idx = vq->vq_ring.avail->ring[head_idx]; + + env_rmb(); + + buffer = env_map_patova(vq->vq_ring.desc[*avail_idx].addr); + *len = vq->vq_ring.desc[*avail_idx].len; + + VQUEUE_IDLE(vq); + + return (buffer); +} + +/** + * virtqueue_add_consumed_buffer - Returns consumed buffer back to VirtIO queue + * + * @param vq - Pointer to VirtIO queue control block + * @param head_idx - Index of vring desc containing used buffer + * @param len - Length of buffer + * + * @return - Function status + */ +int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, + uint_t len) { + + struct vring_used_elem *used_desc = VQ_NULL; + uint16_t used_idx; + + if ((head_idx > vq->vq_nentries) || (head_idx < 0)) { + 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->id = head_idx; + used_desc->len = len; + + env_wmb(); + + vq->vq_ring.used->idx++; + + VQUEUE_IDLE(vq); + + return (VQUEUE_SUCCESS); +} + +/** + * virtqueue_enable_cb - Enables callback generation + * + * @param vq - Pointer to VirtIO queue control block + * + * @return - Function status + */ +int virtqueue_enable_cb(struct virtqueue *vq) { + + return (vq_ring_enable_interrupt(vq, 0)); +} + +/** + * virtqueue_enable_cb - Disables callback generation + * + * @param vq - Pointer to VirtIO queue control block + * + */ +void virtqueue_disable_cb(struct virtqueue *vq) { + + VQUEUE_BUSY(vq); + + if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) { + vring_used_event(&vq->vq_ring)= vq->vq_used_cons_idx - vq->vq_nentries + - 1; + } else { + vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; + } + + VQUEUE_IDLE(vq); +} + +/** + * virtqueue_kick - Notifies other side that there is buffer available for it. + * + * @param vq - Pointer to VirtIO queue control block + */ +void virtqueue_kick(struct virtqueue *vq) { + + VQUEUE_BUSY(vq); + + /* Ensure updated avail->idx is visible to host. */ + env_mb(); + + if (vq_ring_must_notify_host(vq)) + vq_ring_notify_host(vq); + + vq->vq_queued_cnt = 0; + + VQUEUE_IDLE(vq); +} + +/** + * virtqueue_dump Dumps important virtqueue fields , use for debugging purposes + * + * @param vq - Pointer to VirtIO queue control block + */ +void virtqueue_dump(struct virtqueue *vq) { + + if (vq == VQ_NULL) + return; + + env_print("VQ: %s - size=%d; free=%d; used=%d; queued=%d; " + "desc_head_idx=%d; avail.idx=%d; used_cons_idx=%d; " + "used.idx=%d; avail.flags=0x%x; used.flags=0x%x\r\n", vq->vq_name, + vq->vq_nentries, vq->vq_free_cnt, virtqueue_nused(vq), + vq->vq_queued_cnt, vq->vq_desc_head_idx, vq->vq_ring.avail->idx, + vq->vq_used_cons_idx, vq->vq_ring.used->idx, + vq->vq_ring.avail->flags, vq->vq_ring.used->flags); +} + +/** + * virtqueue_get_desc_size - Returns vring descriptor size + * + * @param vq - Pointer to VirtIO queue control block + * + * @return - Descriptor length + */ +uint32_t virtqueue_get_desc_size(struct virtqueue *vq) { + uint16_t head_idx = 0; + uint16_t avail_idx = 0; + uint32_t len = 0; + + if (vq->vq_available_idx == vq->vq_ring.avail->idx) { + return (VQ_NULL); + } + + VQUEUE_BUSY(vq); + + head_idx = vq->vq_available_idx & (vq->vq_nentries - 1); + avail_idx = vq->vq_ring.avail->ring[head_idx]; + len = vq->vq_ring.desc[avail_idx].len; + + VQUEUE_IDLE(vq); + + return (len); +} +/************************************************************************** + * Helper Functions * + **************************************************************************/ + +/** + * + * vq_ring_add_buffer + * + */ +static uint16_t vq_ring_add_buffer(struct virtqueue *vq, + struct vring_desc *desc, uint16_t head_idx, struct llist *buffer, + int readable, int writable) { + + struct vring_desc *dp; + int i, needed; + uint16_t idx; + + needed = readable + writable; + + for (i = 0, idx = head_idx; (i < needed && buffer != VQ_NULL); + i++, idx = dp->next, buffer = buffer->next) { + + VQASSERT(vq, idx != VQ_RING_DESC_CHAIN_END, + "premature end of free desc chain"); + + dp = &desc[idx]; + dp->addr = env_map_vatopa(buffer->data); + dp->len = buffer->attr; + dp->flags = 0; + + if (i < needed - 1) + dp->flags |= VRING_DESC_F_NEXT; + + /* Readable buffers are inserted into vring before the writable buffers.*/ + if (i >= readable) + dp->flags |= VRING_DESC_F_WRITE; + } + + return (idx); +} + +/** + * + * vq_ring_free_chain + * + */ +static void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) { + struct vring_desc *dp; + struct vq_desc_extra *dxp; + + VQ_RING_ASSERT_VALID_IDX(vq, desc_idx); + dp = &vq->vq_ring.desc[desc_idx]; + dxp = &vq->vq_descx[desc_idx]; + + if (vq->vq_free_cnt == 0) + VQ_RING_ASSERT_CHAIN_TERM(vq); + + vq->vq_free_cnt += dxp->ndescs; + dxp->ndescs--; + + if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) { + while (dp->flags & VRING_DESC_F_NEXT) { + VQ_RING_ASSERT_VALID_IDX(vq, dp->next); + dp = &vq->vq_ring.desc[dp->next]; + dxp->ndescs--; + } + } + + VQASSERT(vq, (dxp->ndescs == 0), + "failed to free entire desc chain, remaining"); + + /* + * We must append the existing free chain, if any, to the end of + * newly freed chain. If the virtqueue was completely used, then + * head would be VQ_RING_DESC_CHAIN_END (ASSERTed above). + */ + dp->next = vq->vq_desc_head_idx; + vq->vq_desc_head_idx = desc_idx; +} + +/** + * + * vq_ring_init + * + */ +static void vq_ring_init(struct virtqueue *vq) { + struct vring *vr; + unsigned char *ring_mem; + int i, size; + + ring_mem = vq->vq_ring_mem; + size = vq->vq_nentries; + vr = &vq->vq_ring; + + vring_init(vr, size, ring_mem, vq->vq_alignment); + + for (i = 0; i < size - 1; i++) + vr->desc[i].next = i + 1; + vr->desc[i].next = VQ_RING_DESC_CHAIN_END; +} + +/** + * + * vq_ring_update_avail + * + */ +static void vq_ring_update_avail(struct virtqueue *vq, uint16_t desc_idx) { + uint16_t avail_idx; + + /* + * Place the head of the descriptor chain into the next slot and make + * it usable to the host. The chain is made available now rather than + * deferring to virtqueue_notify() in the hopes that if the host is + * currently running on another CPU, we can keep it processing the new + * descriptor. + */ + avail_idx = vq->vq_ring.avail->idx & (vq->vq_nentries - 1); + vq->vq_ring.avail->ring[avail_idx] = desc_idx; + + env_wmb(); + + vq->vq_ring.avail->idx++; + + /* Keep pending count until virtqueue_notify(). */ + vq->vq_queued_cnt++; +} + +/** + * + * vq_ring_enable_interrupt + * + */ +static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) { + + /* + * Enable interrupts, making sure we get the latest index of + * what's already been consumed. + */ + if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) { + vring_used_event(&vq->vq_ring)= vq->vq_used_cons_idx + ndesc; + } else { + vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; + } + + env_mb(); + + /* + * Enough items may have already been consumed to meet our threshold + * since we last checked. Let our caller know so it processes the new + * entries. + */ + if (virtqueue_nused(vq) > ndesc) { + return (1); + } + + return (0); +} + +/** + * + * virtqueue_interrupt + * + */ +void virtqueue_notification(struct virtqueue *vq) { + + if (vq->callback != VQ_NULL) + vq->callback(vq); +} + +/** + * + * vq_ring_must_notify_host + * + */ +static int vq_ring_must_notify_host(struct virtqueue *vq) { + uint16_t new_idx, prev_idx, event_idx; + + if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) { + new_idx = vq->vq_ring.avail->idx; + prev_idx = new_idx - vq->vq_queued_cnt; + event_idx = vring_avail_event(&vq->vq_ring); + + return (vring_need_event(event_idx, new_idx, prev_idx) != 0); + } + + return ((vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) == 0); +} + +/** + * + * vq_ring_notify_host + * + */ +static void vq_ring_notify_host(struct virtqueue *vq) { + + if (vq->notify != VQ_NULL) + vq->notify(vq); +} + +/** + * + * virtqueue_nused + * + */ +static int virtqueue_nused(struct virtqueue *vq) { + uint16_t used_idx, nused; + + used_idx = vq->vq_ring.used->idx; + + nused = (uint16_t) (used_idx - vq->vq_used_cons_idx); + VQASSERT(vq, nused <= vq->vq_nentries, "used more than available"); + + return (nused); +} diff --git a/ThirdParty/sw_services/xilopenamp/src/virtqueue.h b/ThirdParty/sw_services/xilopenamp/src/virtqueue.h new file mode 100644 index 00000000..8bc2ecb3 --- /dev/null +++ b/ThirdParty/sw_services/xilopenamp/src/virtqueue.h @@ -0,0 +1,233 @@ +#ifndef VIRTQUEUE_H_ +#define VIRTQUEUE_H_ + +/*- + * Copyright (c) 2011, Bryan Venteicher + * 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 unmodified, 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 AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +typedef unsigned int uint_t; +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef uint8_t boolean; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; +typedef signed long long int64_t; + +#include "virtio_ring.h" +#include "env.h" +#include "llist.h" + +/*Error Codes*/ +#define VQ_ERROR_BASE -3000 +#define ERROR_VRING_FULL (VQ_ERROR_BASE - 1) +#define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2) +#define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3) +#define ERROR_NO_MEM (VQ_ERROR_BASE - 4) +#define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5) +#define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6) +#define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7) +#define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8) + +#define true 1 +#define false 0 +#define VQUEUE_SUCCESS 0 +#define VQUEUE_DEBUG false + +//TODO: +/* This is temporary macro to replace C NULL support. + * At the moment all the RTL specific functions are present in env. + * */ +#define VQ_NULL 0 + +/* 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 + * in the descriptor table. This is used to verify we are correctly + * handling vq_free_cnt. + */ +#define VQ_RING_DESC_CHAIN_END 32768 +#define VIRTQUEUE_FLAG_INDIRECT 0x0001 +#define VIRTQUEUE_FLAG_EVENT_IDX 0x0002 +#define VIRTQUEUE_MAX_NAME_SZ 32 + +/* Support for indirect buffer descriptors. */ +#define VIRTIO_RING_F_INDIRECT_DESC (1 << 28) + +/* 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 { + //TODO: Need to define proper structure for + // virtio device with RPmsg and paravirtualization. + + struct virtio_device *vq_dev; + char vq_name[VIRTQUEUE_MAX_NAME_SZ]; + 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); + void (*notify)(struct virtqueue *vq); + int vq_max_indirect_size; + int vq_indirect_mem_size; + struct vring vq_ring; + uint16_t vq_free_cnt; + uint16_t vq_queued_cnt; + + /* + * 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. + */ + + struct vq_desc_extra { + void *cookie; + struct vring_desc *indirect; + uint32_t indirect_paddr; + uint16_t ndescs; + } vq_descx[0]; +}; + +/* struct to hold vring specific information */ +struct vring_alloc_info { + void *phy_addr; + uint32_t align; + uint16_t num_descs; + uint16_t pad; +}; + +typedef void vq_callback(struct virtqueue *); +typedef void vq_notify(struct virtqueue *); + +#if (VQUEUE_DEBUG == true) + +#define VQASSERT(_vq, _exp, _msg) do{ \ + if (!(_exp)){ env_print("%s: %s - "_msg, __func__, (_vq)->vq_name); while(1);} \ + } while(0) + +#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \ + 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") + +#define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false) + +#else + +#define KASSERT(cond, str) +#define VQASSERT(_vq, _exp, _msg) +#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) +#define VQ_RING_ASSERT_CHAIN_TERM(_vq) +#define VQ_PARAM_CHK(condition, status_var, status_err) +#define VQUEUE_BUSY(vq) +#define VQUEUE_IDLE(vq) + +#endif + +int virtqueue_create(struct virtio_device *device, unsigned short id, char *name, + struct vring_alloc_info *ring, void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), struct virtqueue **v_queue); + +int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer, + int readable, int writable, void *cookie); + +int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie, + void* buffer_addr, uint_t len, int writable, boolean has_next); + +void *virtqueue_get_buffer(struct virtqueue *vq, 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, + uint_t len); + +void virtqueue_disable_cb(struct virtqueue *vq); + +int virtqueue_enable_cb(struct virtqueue *vq); + +void virtqueue_kick(struct virtqueue *vq); + +void virtqueue_free(struct virtqueue *vq); + +void virtqueue_dump(struct virtqueue *vq); + +void virtqueue_notification(struct virtqueue *vq); + +uint32_t virtqueue_get_desc_size(struct virtqueue *vq); + +#endif /* VIRTQUEUE_H_ */