diff --git a/Makefile b/Makefile index efbf1b0..4304138 100644 --- a/Makefile +++ b/Makefile @@ -22,11 +22,13 @@ SIZE = $(CROSS_COMPILE)size LINKER_SCRIPT = linker/STM32H747AIIX_FLASH.ld -CFLAGS = -O2 -Wall -Werror -pedantic -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -std=gnu11 -g3 -ffunction-sections -fdata-sections -fstack-usage +CFLAGS = -O2 -Wall -Werror -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -std=gnu11 -g3 -ffunction-sections -fdata-sections -fstack-usage CXXFLAGS = -O2 -Wall -Werror -pedantic -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -std=c++11 -g3 -ffunction-sections -fdata-sections -fstack-usage ASFLAGS = -O2 -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -c -x assembler-with-cpp -g3 LDFLAGS = --specs=nosys.specs -Wl,--gc-sections -static --specs=nano.specs -T$(LINKER_SCRIPT) -Wl,--start-group -lc -lm -Wl,--end-group +CFLAGS += -Wno-variadic-macros -Wno-discarded-qualifiers + TAG_COMMIT := $(shell git rev-list --abbrev-commit --tags --max-count=1) TAG := $(shell git describe --abbrev=0 --tags ${TAG_COMMIT} 2>/dev/null || true) COMMIT := $(shell git rev-parse --short HEAD) @@ -48,7 +50,7 @@ DEFINES = \ -DSTM32H747xx \ -DVECT_TAB_SRAM \ -DMETAL_INTERNAL \ - -DVIRTIO_MASTER_ONLY \ + -DVIRTIO_DRIVER_ONLY \ -DNO_ATOMIC_64_SUPPORT \ -DMETAL_MAX_DEVICE_REGIONS=2 \ -DRPMSG_BUFFER_SIZE=2000 \ diff --git a/include/debug.h b/include/debug.h index 82738ec..98c7e16 100644 --- a/include/debug.h +++ b/include/debug.h @@ -22,11 +22,12 @@ /************************************************************************************** * DEFINE **************************************************************************************/ +#include #ifdef DEBUG #define dbg_printf(...) printf(__VA_ARGS__) #else -#define dbg_printf(...) +#define dbg_printf(...) do {} while (0) #endif #endif /* PORTENTAX8_STM32H7_FW_DEBUG_H */ diff --git a/libraries/openamp_arduino/library.properties b/libraries/openamp_arduino/library.properties index 6cffb98..51525e1 100644 --- a/libraries/openamp_arduino/library.properties +++ b/libraries/openamp_arduino/library.properties @@ -6,5 +6,5 @@ sentence=Enables the communication between H747 cores via shared memory and open paragraph= category=Communication url= -architectures=mbed,mbed_portenta +architectures=mbed,mbed_portenta,mbed_nicla,mbed_opta dot_a_linkage=true diff --git a/libraries/openamp_arduino/src/device.c b/libraries/openamp_arduino/src/device.c index a3bc12c..45e08ec 100644 --- a/libraries/openamp_arduino/src/device.c +++ b/libraries/openamp_arduino/src/device.c @@ -5,9 +5,9 @@ */ #include -#include #include #include +#include #include #include #include @@ -43,11 +43,10 @@ int metal_bus_find(const char *name, struct metal_bus **result) metal_list_for_each(&_metal.common.bus_list, node) { bus = metal_container_of(node, struct metal_bus, node); - if (strcmp(bus->name, name) != 0) - continue; - if (result) + if (strcmp(bus->name, name) == 0 && result) { *result = bus; - return 0; + return 0; + } } return -ENOENT; } @@ -106,10 +105,10 @@ int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name, metal_list_for_each(&_metal.common.generic_device_list, node) { dev = metal_container_of(node, struct metal_device, node); - if (strcmp(dev->name, dev_name) != 0) - continue; - *device = dev; - return metal_generic_dev_sys_open(dev); + if (strcmp(dev->name, dev_name) == 0) { + *device = dev; + return metal_generic_dev_sys_open(dev); + } } return -ENODEV; @@ -122,9 +121,9 @@ int metal_generic_dev_dma_map(struct metal_bus *bus, int nents_in, struct metal_sg *sg_out) { + int i; (void)bus; (void)device; - int i; if (sg_out != sg_in) memcpy(sg_out, sg_in, nents_in*(sizeof(struct metal_sg))); @@ -144,10 +143,10 @@ void metal_generic_dev_dma_unmap(struct metal_bus *bus, struct metal_sg *sg, int nents) { + int i; (void)bus; (void)device; (void)dir; - int i; for (i = 0; i < nents; i++) { metal_cache_invalidate(sg[i].virt, sg[i].len); diff --git a/libraries/openamp_arduino/src/dma.c b/libraries/openamp_arduino/src/dma.c new file mode 100644 index 0000000..7edaa54 --- /dev/null +++ b/libraries/openamp_arduino/src/dma.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +int metal_dma_map(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out) +{ + int nents_out; + + if (!dev || !sg_in || !sg_out) + return -EINVAL; + if (!dev->bus->ops.dev_dma_map) + return -ENODEV; + + /* memory barrier */ + if (dir == METAL_DMA_DEV_R) + /* If it is device read, apply memory write fence. */ + atomic_thread_fence(memory_order_release); + else + /* If it is device write or r/w, apply memory r/w fence. */ + atomic_thread_fence(memory_order_acq_rel); + nents_out = dev->bus->ops.dev_dma_map(dev->bus, + dev, dir, sg_in, nents_in, sg_out); + return nents_out; +} + +void metal_dma_unmap(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg, + int nents) +{ + /* memory barrier */ + if (dir == METAL_DMA_DEV_R) + /* If it is device read, apply memory write fence. */ + atomic_thread_fence(memory_order_release); + else + /*If it is device write or r/w, apply memory r/w fence */ + atomic_thread_fence(memory_order_acq_rel); + + if (!dev || !dev->bus->ops.dev_dma_unmap || !sg) + return; + dev->bus->ops.dev_dma_unmap(dev->bus, + dev, dir, sg, nents); +} diff --git a/libraries/openamp_arduino/src/elf_loader.c b/libraries/openamp_arduino/src/elf_loader.c new file mode 100644 index 0000000..c90b8d4 --- /dev/null +++ b/libraries/openamp_arduino/src/elf_loader.c @@ -0,0 +1,707 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +static int elf_is_64(const void *elf_info) +{ + const unsigned char *tmp = elf_info; + + if (tmp[EI_CLASS] == ELFCLASS64) + return 1; + else + return 0; +} + +static size_t elf_ehdr_size(const void *elf_info) +{ + if (!elf_info) + return sizeof(Elf64_Ehdr); + else if (elf_is_64(elf_info) != 0) + return sizeof(Elf64_Ehdr); + else + return sizeof(Elf32_Ehdr); +} + +static size_t elf_phoff(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_phoff; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_phoff; + } +} + +static size_t elf_phentsize(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_phentsize; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_phentsize; + } +} + +static int elf_phnum(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_phnum; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_phnum; + } +} + +static size_t elf_shoff(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shoff; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shoff; + } +} + +static size_t elf_shentsize(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shentsize; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shentsize; + } +} + +static int elf_shnum(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shnum; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shnum; + } +} + +static int elf_shstrndx(const void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Ehdr *ehdr = elf_info; + + return ehdr->e_shstrndx; + } else { + const Elf64_Ehdr *ehdr = elf_info; + + return ehdr->e_shstrndx; + } +} + +static void **elf_phtable_ptr(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return (void **)&einfo->phdrs; + } else { + struct elf64_info *einfo = elf_info; + + return (void **)&einfo->phdrs; + } +} + +static void **elf_shtable_ptr(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return (void **)&einfo->shdrs; + } else { + struct elf64_info *einfo = elf_info; + + return (void **)&einfo->shdrs; + } +} + +static void **elf_shstrtab_ptr(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return &einfo->shstrtab; + } else { + struct elf64_info *einfo = elf_info; + + return &einfo->shstrtab; + } +} + +static int *elf_load_state(void *elf_info) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + + return &einfo->load_state; + } else { + struct elf64_info *einfo = elf_info; + + return &einfo->load_state; + } +} + +static void elf_parse_segment(void *elf_info, const void *elf_phdr, + unsigned int *p_type, size_t *p_offset, + metal_phys_addr_t *p_vaddr, + metal_phys_addr_t *p_paddr, + size_t *p_filesz, size_t *p_memsz) +{ + if (elf_is_64(elf_info) == 0) { + const Elf32_Phdr *phdr = elf_phdr; + + if (p_type) + *p_type = (unsigned int)phdr->p_type; + if (p_offset) + *p_offset = (size_t)phdr->p_offset; + if (p_vaddr) + *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr; + if (p_paddr) + *p_paddr = (metal_phys_addr_t)phdr->p_paddr; + if (p_filesz) + *p_filesz = (size_t)phdr->p_filesz; + if (p_memsz) + *p_memsz = (size_t)phdr->p_memsz; + } else { + const Elf64_Phdr *phdr = elf_phdr; + + if (p_type) + *p_type = (unsigned int)phdr->p_type; + if (p_offset) + *p_offset = (size_t)phdr->p_offset; + if (p_vaddr) + *p_vaddr = (metal_phys_addr_t)phdr->p_vaddr; + if (p_paddr) + *p_paddr = (metal_phys_addr_t)phdr->p_paddr; + if (p_filesz) + *p_filesz = (size_t)phdr->p_filesz; + if (p_memsz) + *p_memsz = (size_t)phdr->p_memsz; + } +} + +static const void *elf_get_segment_from_index(void *elf_info, int index) +{ + if (elf_is_64(elf_info) == 0) { + const struct elf32_info *einfo = elf_info; + const Elf32_Ehdr *ehdr = &einfo->ehdr; + const Elf32_Phdr *phdrs = einfo->phdrs; + + if (!phdrs) + return NULL; + if (index < 0 || index >= ehdr->e_phnum) + return NULL; + return &phdrs[index]; + } else { + const struct elf64_info *einfo = elf_info; + const Elf64_Ehdr *ehdr = &einfo->ehdr; + const Elf64_Phdr *phdrs = einfo->phdrs; + + if (!phdrs) + return NULL; + if (index < 0 || index >= ehdr->e_phnum) + return NULL; + return &phdrs[index]; + } +} + +static void *elf_get_section_from_name(void *elf_info, const char *name) +{ + unsigned int i; + const char *name_table; + + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + Elf32_Ehdr *ehdr = &einfo->ehdr; + Elf32_Shdr *shdr = einfo->shdrs; + + name_table = einfo->shstrtab; + if (!shdr || !name_table) + return NULL; + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (strcmp(name, name_table + shdr->sh_name)) + continue; + else + return shdr; + } + } else { + struct elf64_info *einfo = elf_info; + Elf64_Ehdr *ehdr = &einfo->ehdr; + Elf64_Shdr *shdr = einfo->shdrs; + + name_table = einfo->shstrtab; + if (!shdr || !name_table) + return NULL; + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + if (strcmp(name, name_table + shdr->sh_name)) + continue; + else + return shdr; + } + } + return NULL; +} + +static void *elf_get_section_from_index(void *elf_info, int index) +{ + if (elf_is_64(elf_info) == 0) { + struct elf32_info *einfo = elf_info; + Elf32_Ehdr *ehdr = &einfo->ehdr; + Elf32_Shdr *shdr = einfo->shdrs; + + if (!shdr) + return NULL; + if (index < 0 || index >= ehdr->e_shnum) + return NULL; + return &einfo->shdrs[index]; + } else { + struct elf64_info *einfo = elf_info; + Elf64_Ehdr *ehdr = &einfo->ehdr; + Elf64_Shdr *shdr = einfo->shdrs; + + if (!shdr) + return NULL; + if (index < 0 || index >= ehdr->e_shnum) + return NULL; + return &einfo->shdrs[index]; + } +} + +static void elf_parse_section(void *elf_info, void *elf_shdr, + unsigned int *sh_type, unsigned int *sh_flags, + metal_phys_addr_t *sh_addr, + size_t *sh_offset, size_t *sh_size, + unsigned int *sh_link, unsigned int *sh_info, + unsigned int *sh_addralign, + size_t *sh_entsize) +{ + if (elf_is_64(elf_info) == 0) { + Elf32_Shdr *shdr = elf_shdr; + + if (sh_type) + *sh_type = shdr->sh_type; + if (sh_flags) + *sh_flags = shdr->sh_flags; + if (sh_addr) + *sh_addr = (metal_phys_addr_t)shdr->sh_addr; + if (sh_offset) + *sh_offset = shdr->sh_offset; + if (sh_size) + *sh_size = shdr->sh_size; + if (sh_link) + *sh_link = shdr->sh_link; + if (sh_info) + *sh_info = shdr->sh_info; + if (sh_addralign) + *sh_addralign = shdr->sh_addralign; + if (sh_entsize) + *sh_entsize = shdr->sh_entsize; + } else { + Elf64_Shdr *shdr = elf_shdr; + + if (sh_type) + *sh_type = shdr->sh_type; + if (sh_flags) + *sh_flags = shdr->sh_flags; + if (sh_addr) + *sh_addr = (metal_phys_addr_t)shdr->sh_addr; + if (sh_offset) + *sh_offset = shdr->sh_offset; + if (sh_size) + *sh_size = shdr->sh_size; + if (sh_link) + *sh_link = shdr->sh_link; + if (sh_info) + *sh_info = shdr->sh_info; + if (sh_addralign) + *sh_addralign = shdr->sh_addralign; + if (sh_entsize) + *sh_entsize = shdr->sh_entsize; + } +} + +static const void *elf_next_load_segment(void *elf_info, int *nseg, + metal_phys_addr_t *da, + size_t *noffset, size_t *nfsize, + size_t *nmsize) +{ + const void *phdr = PT_NULL; + unsigned int p_type = PT_NULL; + + if (!elf_info || !nseg) + return NULL; + while (p_type != PT_LOAD) { + phdr = elf_get_segment_from_index(elf_info, *nseg); + if (!phdr) + return NULL; + elf_parse_segment(elf_info, phdr, &p_type, noffset, + da, NULL, nfsize, nmsize); + *nseg = *nseg + 1; + } + return phdr; +} + +static size_t elf_info_size(const void *img_data) +{ + if (elf_is_64(img_data) == 0) + return sizeof(struct elf32_info); + else + return sizeof(struct elf64_info); +} + +int elf_identify(const void *img_data, size_t len) +{ + if (len < SELFMAG || !img_data) + return -RPROC_EINVAL; + if (memcmp(img_data, ELFMAG, SELFMAG) != 0) + return -RPROC_EINVAL; + else + return 0; +} + +int elf_load_header(const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + size_t *noffset, size_t *nlen) +{ + int *load_state; + + metal_assert(noffset); + metal_assert(nlen); + /* Get ELF header */ + if (last_load_state == ELF_STATE_INIT) { + size_t tmpsize; + + metal_log(METAL_LOG_DEBUG, "Loading ELF headering\r\n"); + tmpsize = elf_ehdr_size(img_data); + if (len < tmpsize) { + *noffset = 0; + *nlen = tmpsize; + return ELF_STATE_INIT; + } else { + size_t infosize = elf_info_size(img_data); + + if (!*img_info) { + *img_info = metal_allocate_memory(infosize); + if (!*img_info) + return -RPROC_ENOMEM; + memset(*img_info, 0, infosize); + } + memcpy(*img_info, img_data, tmpsize); + load_state = elf_load_state(*img_info); + *load_state = ELF_STATE_WAIT_FOR_PHDRS; + last_load_state = ELF_STATE_WAIT_FOR_PHDRS; + } + } + metal_assert(*img_info); + load_state = elf_load_state(*img_info); + if (last_load_state != *load_state) + return -RPROC_EINVAL; + /* Get ELF program headers */ + if (*load_state == ELF_STATE_WAIT_FOR_PHDRS) { + size_t phdrs_size; + size_t phdrs_offset; + void **phdrs; + const void *img_phdrs; + + metal_log(METAL_LOG_DEBUG, "Loading ELF program header.\r\n"); + phdrs_offset = elf_phoff(*img_info); + phdrs_size = elf_phnum(*img_info) * elf_phentsize(*img_info); + if (offset > phdrs_offset || + offset + len < phdrs_offset + phdrs_size) { + *noffset = phdrs_offset; + *nlen = phdrs_size; + return *load_state; + } + /* calculate the programs headers offset to the image_data */ + phdrs_offset -= offset; + img_phdrs = (const char *)img_data + phdrs_offset; + phdrs = elf_phtable_ptr(*img_info); + *phdrs = metal_allocate_memory(phdrs_size); + if (!*phdrs) + return -RPROC_ENOMEM; + memcpy(*phdrs, img_phdrs, phdrs_size); + *load_state = ELF_STATE_WAIT_FOR_SHDRS | + RPROC_LOADER_READY_TO_LOAD; + } + /* Get ELF Section Headers */ + if ((*load_state & ELF_STATE_WAIT_FOR_SHDRS) != 0) { + size_t shdrs_size; + size_t shdrs_offset; + void **shdrs; + const void *img_shdrs; + + metal_log(METAL_LOG_DEBUG, "Loading ELF section header.\r\n"); + shdrs_offset = elf_shoff(*img_info); + if (elf_shnum(*img_info) == 0) { + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_HDRS_COMPLETE; + *nlen = 0; + return *load_state; + } + shdrs_size = elf_shnum(*img_info) * elf_shentsize(*img_info); + if (offset > shdrs_offset || + offset + len < shdrs_offset + shdrs_size) { + *noffset = shdrs_offset; + *nlen = shdrs_size; + return *load_state; + } + /* calculate the sections headers offset to the image_data */ + shdrs_offset -= offset; + img_shdrs = (const char *)img_data + shdrs_offset; + shdrs = elf_shtable_ptr(*img_info); + *shdrs = metal_allocate_memory(shdrs_size); + if (!*shdrs) + return -RPROC_ENOMEM; + memcpy(*shdrs, img_shdrs, shdrs_size); + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_WAIT_FOR_SHSTRTAB; + metal_log(METAL_LOG_DEBUG, + "Loading ELF section header complete.\r\n"); + } + /* Get ELF SHSTRTAB section */ + if ((*load_state & ELF_STATE_WAIT_FOR_SHSTRTAB) != 0) { + size_t shstrtab_size; + size_t shstrtab_offset; + int shstrndx; + void *shdr; + void **shstrtab; + + metal_log(METAL_LOG_DEBUG, "Loading ELF shstrtab.\r\n"); + shstrndx = elf_shstrndx(*img_info); + shdr = elf_get_section_from_index(*img_info, shstrndx); + if (!shdr) + return -RPROC_EINVAL; + elf_parse_section(*img_info, shdr, NULL, NULL, + NULL, &shstrtab_offset, + &shstrtab_size, NULL, NULL, + NULL, NULL); + if (offset > shstrtab_offset || + offset + len < shstrtab_offset + shstrtab_size) { + *noffset = shstrtab_offset; + *nlen = shstrtab_size; + return *load_state; + } + /* Calculate shstrtab section offset to the input image data */ + shstrtab_offset -= offset; + shstrtab = elf_shstrtab_ptr(*img_info); + *shstrtab = metal_allocate_memory(shstrtab_size); + if (!*shstrtab) + return -RPROC_ENOMEM; + memcpy(*shstrtab, + (const char *)img_data + shstrtab_offset, + shstrtab_size); + *load_state = (*load_state & (~ELF_STATE_MASK)) | + ELF_STATE_HDRS_COMPLETE; + *nlen = 0; + return *load_state; + } + return last_load_state; +} + +int elf_load(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize) +{ + int *load_state; + const void *phdr; + + (void)rproc; + metal_assert(da); + metal_assert(noffset); + metal_assert(nlen); + if ((last_load_state & RPROC_LOADER_MASK) == RPROC_LOADER_NOT_READY) { + metal_log(METAL_LOG_DEBUG, + "needs to load header first\r\n"); + last_load_state = elf_load_header(img_data, offset, len, + img_info, last_load_state, + noffset, nlen); + if ((last_load_state & RPROC_LOADER_MASK) == + RPROC_LOADER_NOT_READY) { + *da = RPROC_LOAD_ANYADDR; + return last_load_state; + } + } + metal_assert(img_info && *img_info); + load_state = elf_load_state(*img_info); + /* For ELF, segment padding value is 0 */ + if (padding) + *padding = 0; + if ((*load_state & RPROC_LOADER_READY_TO_LOAD) != 0) { + int nsegment; + size_t nsegmsize = 0; + size_t nsize = 0; + int phnums = 0; + + nsegment = *load_state & ELF_NEXT_SEGMENT_MASK; + phdr = elf_next_load_segment(*img_info, &nsegment, da, + noffset, &nsize, &nsegmsize); + if (!phdr) { + metal_log(METAL_LOG_DEBUG, "cannot find more segment\r\n"); + *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | + (nsegment & ELF_NEXT_SEGMENT_MASK); + return *load_state; + } + *nlen = nsize; + *nmemsize = nsegmsize; + phnums = elf_phnum(*img_info); + metal_log(METAL_LOG_DEBUG, "segment: %d, total segs %d\r\n", + nsegment, phnums); + if (nsegment == phnums) { + *load_state = (*load_state & (~RPROC_LOADER_MASK)) | + RPROC_LOADER_POST_DATA_LOAD; + } + *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | + (nsegment & ELF_NEXT_SEGMENT_MASK); + } else if ((*load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) { + if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) { + last_load_state = elf_load_header(img_data, offset, + len, img_info, + last_load_state, + noffset, nlen); + if (last_load_state < 0) + return last_load_state; + if ((last_load_state & ELF_STATE_HDRS_COMPLETE) != 0) { + *load_state = (*load_state & + (~RPROC_LOADER_MASK)) | + RPROC_LOADER_LOAD_COMPLETE; + *nlen = 0; + } + *da = RPROC_LOAD_ANYADDR; + } else { + /* TODO: will handle relocate later */ + *nlen = 0; + *load_state = (*load_state & + (~RPROC_LOADER_MASK)) | + RPROC_LOADER_LOAD_COMPLETE; + } + } + return *load_state; +} + +void elf_release(void *img_info) +{ + if (!img_info) + return; + if (elf_is_64(img_info) == 0) { + struct elf32_info *elf_info = img_info; + + if (elf_info->phdrs) + metal_free_memory(elf_info->phdrs); + if (elf_info->shdrs) + metal_free_memory(elf_info->shdrs); + if (elf_info->shstrtab) + metal_free_memory(elf_info->shstrtab); + metal_free_memory(img_info); + + } else { + struct elf64_info *elf_info = img_info; + + if (elf_info->phdrs) + metal_free_memory(elf_info->phdrs); + if (elf_info->shdrs) + metal_free_memory(elf_info->shdrs); + if (elf_info->shstrtab) + metal_free_memory(elf_info->shstrtab); + metal_free_memory(img_info); + } +} + +metal_phys_addr_t elf_get_entry(void *elf_info) +{ + if (!elf_info) + return METAL_BAD_PHYS; + + if (elf_is_64(elf_info) == 0) { + Elf32_Ehdr *elf_ehdr = elf_info; + Elf32_Addr e_entry; + + e_entry = elf_ehdr->e_entry; + return (metal_phys_addr_t)e_entry; + } else { + Elf64_Ehdr *elf_ehdr = elf_info; + Elf64_Addr e_entry; + + e_entry = elf_ehdr->e_entry; + return (metal_phys_addr_t)e_entry; + } +} + +int elf_locate_rsc_table(void *elf_info, metal_phys_addr_t *da, + size_t *offset, size_t *size) +{ + char *sect_name = ".resource_table"; + void *shdr; + int *load_state; + + if (!elf_info) + return -RPROC_EINVAL; + + load_state = elf_load_state(elf_info); + if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) + return -RPROC_ERR_LOADER_STATE; + shdr = elf_get_section_from_name(elf_info, sect_name); + if (!shdr) { + metal_assert(size); + *size = 0; + return 0; + } + elf_parse_section(elf_info, shdr, NULL, NULL, + da, offset, size, + NULL, NULL, NULL, NULL); + return 0; +} + +int elf_get_load_state(void *img_info) +{ + int *load_state; + + if (!img_info) + return -RPROC_EINVAL; + load_state = elf_load_state(img_info); + return *load_state; +} + +const struct loader_ops elf_ops = { + .load_header = elf_load_header, + .load_data = elf_load, + .locate_rsc_table = elf_locate_rsc_table, + .release = elf_release, + .get_entry = elf_get_entry, + .get_load_state = elf_get_load_state, +}; diff --git a/libraries/openamp_arduino/src/generic_device.c b/libraries/openamp_arduino/src/generic_device.c index d01fd3c..ec6e538 100644 --- a/libraries/openamp_arduino/src/generic_device.c +++ b/libraries/openamp_arduino/src/generic_device.c @@ -17,7 +17,7 @@ int metal_generic_dev_sys_open(struct metal_device *dev) { struct metal_io_region *io; - unsigned i; + unsigned int i; /* map I/O memory regions */ for (i = 0; i < dev->num_regions; i++) { diff --git a/libraries/openamp_arduino/src/generic_io.c b/libraries/openamp_arduino/src/generic_io.c index 670f239..966bfc5 100644 --- a/libraries/openamp_arduino/src/generic_io.c +++ b/libraries/openamp_arduino/src/generic_io.c @@ -17,8 +17,8 @@ void metal_sys_io_mem_map(struct metal_io_region *io) size_t psize; size_t *va; - va = (size_t *)io->virt; - psize = io->size; + va = io->virt; + psize = (size_t)io->size; if (psize) { if (psize >> io->page_shift) psize = (size_t)1 << io->page_shift; diff --git a/libraries/openamp_arduino/src/init.c b/libraries/openamp_arduino/src/init.c index 3152177..5a6a006 100644 --- a/libraries/openamp_arduino/src/init.c +++ b/libraries/openamp_arduino/src/init.c @@ -11,6 +11,9 @@ int metal_init(const struct metal_init_params *params) { int error = 0; + if (_metal.common.ref_count++ != 0) + return 0; + memset(&_metal, 0, sizeof(_metal)); _metal.common.log_handler = params->log_handler; @@ -24,11 +27,15 @@ int metal_init(const struct metal_init_params *params) if (error) return error; + ++_metal.common.ref_count; return error; } void metal_finish(void) { + if (--_metal.common.ref_count != 0) + return; + metal_sys_finish(); memset(&_metal, 0, sizeof(_metal)); } diff --git a/libraries/openamp_arduino/src/io.c b/libraries/openamp_arduino/src/io.c index fccf110..7faf405 100644 --- a/libraries/openamp_arduino/src/io.c +++ b/libraries/openamp_arduino/src/io.c @@ -4,17 +4,19 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include #include +#include #include #include void metal_io_init(struct metal_io_region *io, void *virt, const metal_phys_addr_t *physmap, size_t size, - unsigned page_shift, unsigned int mem_flags, + unsigned int page_shift, unsigned int mem_flags, const struct metal_io_ops *ops) { - const struct metal_io_ops nops = {NULL, NULL, NULL, NULL, NULL, NULL}; + const struct metal_io_ops nops = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; io->virt = virt; io->physmap = physmap; @@ -37,7 +39,7 @@ int metal_io_block_read(struct metal_io_region *io, unsigned long offset, unsigned char *dest = dst; int retlen; - if (offset > io->size) + if (!ptr) return -ERANGE; if ((offset + len) > io->size) len = io->size - offset; @@ -74,7 +76,7 @@ int metal_io_block_write(struct metal_io_region *io, unsigned long offset, const unsigned char *source = src; int retlen; - if (offset > io->size) + if (!ptr) return -ERANGE; if ((offset + len) > io->size) len = io->size - offset; @@ -110,7 +112,7 @@ int metal_io_block_set(struct metal_io_region *io, unsigned long offset, unsigned char *ptr = metal_io_virt(io, offset); int retlen = len; - if (offset > io->size) + if (!ptr) return -ERANGE; if ((offset + len) > io->size) len = io->size - offset; @@ -123,7 +125,7 @@ int metal_io_block_set(struct metal_io_region *io, unsigned long offset, unsigned int i; for (i = 1; i < sizeof(int); i++) - cint |= ((unsigned int)value << (8 * i)); + cint |= ((unsigned int)value << (CHAR_BIT * i)); for (; len && ((uintptr_t)ptr % sizeof(int)); ptr++, len--) *(unsigned char *)ptr = (unsigned char) value; diff --git a/libraries/openamp_arduino/src/irq.c b/libraries/openamp_arduino/src/irq.c index 750728f..c8578fa 100644 --- a/libraries/openamp_arduino/src/irq.c +++ b/libraries/openamp_arduino/src/irq.c @@ -1,282 +1,140 @@ /* - * Copyright (c) 2016 - 2017, Xilinx Inc. and Contributors. All rights reserved. + * Copyright (c) 2019, Xilinx Inc. and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -/* - * @file generic/irq.c - * @brief generic libmetal irq definitions. - */ - #include #include -#include -#include -#include +#include #include #include -#include - -/** IRQ handlers descriptor structure */ -struct metal_irq_hddesc { - metal_irq_handler hd; /**< irq handler */ - void *drv_id; /**< id to identify the driver - of the irq handler */ - struct metal_device *dev; /**< device identifier */ - struct metal_list node; /**< node on irq handlers list */ -}; - -/** IRQ descriptor structure */ -struct metal_irq_desc { - int irq; /**< interrupt number */ - struct metal_list hdls; /**< interrupt handlers */ - struct metal_list node; /**< node on irqs list */ -}; -/** IRQ state structure */ -struct metal_irqs_state { - struct metal_list irqs; /**< interrupt descriptors */ - metal_mutex_t irq_lock; /**< access lock */ -}; +/** List of registered IRQ controller */ +static METAL_DECLARE_LIST(irq_cntrs); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-braces" -static struct metal_irqs_state _irqs = { - .irqs = METAL_INIT_LIST(_irqs.irqs), - .irq_lock = METAL_MUTEX_INIT(_irqs.irq_lock), -}; -#pragma GCC diagnostic pop - -int metal_irq_register(int irq, - metal_irq_handler hd, - struct metal_device *dev, - void *drv_id) +static int metal_irq_allocate(int irq_base, int irq_num) { - struct metal_irq_desc *irq_p = NULL; - struct metal_irq_hddesc *hdl_p; struct metal_list *node; - unsigned int irq_flags_save; + struct metal_irq_controller *cntr; + int irq_tocheck = irq_base, irq_end_tocheck; - if (irq < 0) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d need to be a positive number\n", - __func__, irq); - return -EINVAL; + if (irq_num == 0) { + return METAL_IRQ_ANY; } - - if ((drv_id == NULL) || (hd == NULL)) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n", - __func__, irq); - return -EINVAL; + if (irq_tocheck == METAL_IRQ_ANY) { + irq_tocheck = 0; } - - /* Search for irq in list */ - metal_mutex_acquire(&_irqs.irq_lock); - metal_list_for_each(&_irqs.irqs, node) { - irq_p = metal_container_of(node, struct metal_irq_desc, node); - - if (irq_p->irq == irq) { - struct metal_list *h_node; - - /* Check if drv_id already exist */ - metal_list_for_each(&irq_p->hdls, h_node) { - hdl_p = metal_container_of(h_node, - struct metal_irq_hddesc, - node); - - /* if drv_id already exist reject */ - if ((hdl_p->drv_id == drv_id) && - ((dev == NULL) || (hdl_p->dev == dev))) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d already registered." - "Will not register again.\n", - __func__, irq); - metal_mutex_release(&_irqs.irq_lock); - return -EINVAL; - } + irq_end_tocheck = irq_tocheck + irq_num; + + metal_list_for_each(&irq_cntrs, node) { + int cntr_irq_base, cntr_irq_end; + + cntr = metal_container_of(node, + struct metal_irq_controller, node); + cntr_irq_base = cntr->irq_base; + cntr_irq_end = cntr_irq_base + cntr->irq_num; + if (irq_tocheck < cntr_irq_end && + irq_end_tocheck > cntr_irq_base) { + if (irq_base != METAL_IRQ_ANY) { + /* IRQ has been allocated */ + return METAL_IRQ_ANY; } - /* irq found and drv_id not used, get out of metal_list_for_each */ - break; + irq_tocheck = cntr_irq_end; + irq_end_tocheck = irq_tocheck + irq_num; } } - - /* Either need to add handler to an existing list or to a new one */ - hdl_p = metal_allocate_memory(sizeof(struct metal_irq_hddesc)); - if (hdl_p == NULL) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d cannot allocate mem for drv_id %d.\n", - __func__, irq, drv_id); - metal_mutex_release(&_irqs.irq_lock); - return -ENOMEM; - } - hdl_p->hd = hd; - hdl_p->drv_id = drv_id; - hdl_p->dev = dev; - - /* interrupt already registered, add handler to existing list*/ - if ((irq_p != NULL) && (irq_p->irq == irq)) { - irq_flags_save = metal_irq_save_disable(); - metal_list_add_tail(&irq_p->hdls, &hdl_p->node); - metal_irq_restore_enable(irq_flags_save); - - metal_log(METAL_LOG_DEBUG, "%s: success, irq %d add drv_id %p \n", - __func__, irq, drv_id); - metal_mutex_release(&_irqs.irq_lock); - return 0; - } - - /* interrupt was not already registered, add */ - irq_p = metal_allocate_memory(sizeof(struct metal_irq_desc)); - if (irq_p == NULL) { - metal_log(METAL_LOG_ERROR, "%s: irq %d cannot allocate mem.\n", - __func__, irq); - metal_mutex_release(&_irqs.irq_lock); - return -ENOMEM; - } - irq_p->irq = irq; - metal_list_init(&irq_p->hdls); - metal_list_add_tail(&irq_p->hdls, &hdl_p->node); - - irq_flags_save = metal_irq_save_disable(); - metal_list_add_tail(&_irqs.irqs, &irq_p->node); - metal_irq_restore_enable(irq_flags_save); - - metal_log(METAL_LOG_DEBUG, "%s: success, added irq %d\n", __func__, irq); - metal_mutex_release(&_irqs.irq_lock); - return 0; -} - -/* helper function for metal_irq_unregister() */ -static void metal_irq_delete_node(struct metal_list *node, void *p_to_free) -{ - unsigned int irq_flags_save; - - irq_flags_save=metal_irq_save_disable(); - metal_list_del(node); - metal_irq_restore_enable(irq_flags_save); - metal_free_memory(p_to_free); + return irq_tocheck; } -int metal_irq_unregister(int irq, - metal_irq_handler hd, - struct metal_device *dev, - void *drv_id) +int metal_irq_register_controller(struct metal_irq_controller *cntr) { - struct metal_irq_desc *irq_p; + int irq_base; struct metal_list *node; - if (irq < 0) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need to be a positive number\n", - __func__, irq); + if (cntr == NULL) { return -EINVAL; } - - /* Search for irq in list */ - metal_mutex_acquire(&_irqs.irq_lock); - metal_list_for_each(&_irqs.irqs, node) { - - irq_p = metal_container_of(node, struct metal_irq_desc, node); - - if (irq_p->irq == irq) { - struct metal_list *h_node, *h_prenode; - struct metal_irq_hddesc *hdl_p; - unsigned int delete_count = 0; - - metal_log(METAL_LOG_DEBUG, "%s: found irq %d\n", - __func__, irq); - - /* Search through handlers */ - metal_list_for_each(&irq_p->hdls, h_node) { - hdl_p = metal_container_of(h_node, - struct metal_irq_hddesc, - node); - - if (((hd == NULL) || (hdl_p->hd == hd)) && - ((drv_id == NULL) || (hdl_p->drv_id == drv_id)) && - ((dev == NULL) || (hdl_p->dev == dev))) { - metal_log(METAL_LOG_DEBUG, - "%s: unregister hd=%p drv_id=%p dev=%p\n", - __func__, hdl_p->hd, hdl_p->drv_id, hdl_p->dev); - h_prenode = h_node->prev; - metal_irq_delete_node(h_node, hdl_p); - h_node = h_prenode; - delete_count++; - } - } - - /* we did not find any handler to delete */ - if (!delete_count) { - metal_log(METAL_LOG_DEBUG, "%s: No matching entry\n", - __func__); - metal_mutex_release(&_irqs.irq_lock); - return -ENOENT; - - } - - /* if interrupt handlers list is empty, unregister interrupt */ - if (metal_list_is_empty(&irq_p->hdls)) { - metal_log(METAL_LOG_DEBUG, - "%s: handlers list empty, unregister interrupt\n", - __func__); - metal_irq_delete_node(node, irq_p); - } - - metal_log(METAL_LOG_DEBUG, "%s: success\n", __func__); - - metal_mutex_release(&_irqs.irq_lock); + metal_list_for_each(&irq_cntrs, node) { + if (node == &cntr->node) { return 0; } } - metal_log(METAL_LOG_DEBUG, "%s: No matching IRQ entry\n", __func__); + /* + * Allocate IRQ numbers which are not yet used by any IRQ + * controllers. + */ + irq_base = metal_irq_allocate(cntr->irq_base, cntr->irq_num); + if (irq_base == METAL_IRQ_ANY) { + return -EINVAL; + } + cntr->irq_base = irq_base; - metal_mutex_release(&_irqs.irq_lock); - return -ENOENT; + metal_list_add_tail(&irq_cntrs, &cntr->node); + return 0; } -unsigned int metal_irq_save_disable(void) +static struct metal_irq_controller *metal_irq_get_controller(int irq) { - return sys_irq_save_disable(); + struct metal_list *node; + struct metal_irq_controller *cntr; + + metal_list_for_each(&irq_cntrs, node) { + int irq_base, irq_end; + + cntr = (struct metal_irq_controller *) + metal_container_of(node, struct metal_irq_controller, + node); + irq_base = cntr->irq_base; + irq_end = irq_base + cntr->irq_num; + if (irq >= irq_base && irq < irq_end) { + return cntr; + } + } + return NULL; } -void metal_irq_restore_enable(unsigned int flags) +static void _metal_irq_set_enable(int irq, unsigned int state) { - sys_irq_restore_enable(flags); + struct metal_irq_controller *cntr; + + cntr = metal_irq_get_controller(irq); + if (cntr == NULL) { + return; + } + cntr->irq_set_enable(cntr, irq, state); } -void metal_irq_enable(unsigned int vector) +int metal_irq_register(int irq, + metal_irq_handler irq_handler, + void *arg) { - sys_irq_enable(vector); + struct metal_irq_controller *cntr; + struct metal_irq *irq_data; + + cntr = metal_irq_get_controller(irq); + if (cntr == NULL) { + return -EINVAL; + } + if (cntr->irq_register != NULL) { + return cntr->irq_register(cntr, irq, irq_handler, arg); + } + if (cntr->irqs == NULL) { + return -EINVAL; + } + irq_data = &cntr->irqs[irq - cntr->irq_base]; + irq_data->hd = irq_handler; + irq_data->arg = arg; + return 0; } -void metal_irq_disable(unsigned int vector) +void metal_irq_enable(unsigned int vector) { - sys_irq_disable(vector); + _metal_irq_set_enable((int)vector, METAL_IRQ_ENABLE); } -/** - * @brief default handler - */ -void metal_irq_isr(unsigned int vector) +void metal_irq_disable(unsigned int vector) { - struct metal_list *node; - struct metal_irq_desc *irq_p; - - metal_list_for_each(&_irqs.irqs, node) { - irq_p = metal_container_of(node, struct metal_irq_desc, node); - - if ((unsigned int)irq_p->irq == vector) { - struct metal_list *h_node; - struct metal_irq_hddesc *hdl_p; - - metal_list_for_each(&irq_p->hdls, h_node) { - hdl_p = metal_container_of(h_node, - struct metal_irq_hddesc, - node); - - (hdl_p->hd)(vector, hdl_p->drv_id); - } - } - } + _metal_irq_set_enable((int)vector, METAL_IRQ_DISABLE); } diff --git a/libraries/openamp_arduino/src/log.c b/libraries/openamp_arduino/src/log.c index 83bec1f..22c8b9b 100644 --- a/libraries/openamp_arduino/src/log.c +++ b/libraries/openamp_arduino/src/log.c @@ -16,7 +16,7 @@ void metal_default_log_handler(enum metal_log_level level, #ifdef DEFAULT_LOGGER_ON char msg[1024]; va_list args; - static const char *level_strs[] = { + static const char * const level_strs[] = { "metal: emergency: ", "metal: alert: ", "metal: critical: ", diff --git a/libraries/openamp_arduino/src/mailbox_hsem_if.c b/libraries/openamp_arduino/src/mailbox_hsem_if.c index d6ac7bf..c99feba 100644 --- a/libraries/openamp_arduino/src/mailbox_hsem_if.c +++ b/libraries/openamp_arduino/src/mailbox_hsem_if.c @@ -65,9 +65,7 @@ #define RX_NEW_MSG 1 /* Private variables ---------------------------------------------------------*/ -static uint32_t msg_received = RX_NO_MSG; - -void OPENAMP_check_for_message(void); +static volatile uint32_t msg_received = RX_NO_MSG; /* Private functions ---------------------------------------------------------*/ void HAL_HSEM_FreeCallback(uint32_t SemMask) @@ -95,13 +93,13 @@ int MAILBOX_Init(void) #ifdef CORE_CM7 /* Enable CM7 receive irq */ - HAL_NVIC_SetPriority(HSEM1_IRQn, 2, 0); + HAL_NVIC_SetPriority(HSEM1_IRQn, 0, 1); HAL_NVIC_EnableIRQ(HSEM1_IRQn); HAL_HSEM_ActivateNotification(__HAL_HSEM_SEMID_TO_MASK(HSEM_ID_1)); #endif -#ifdef CORE_CM4 +#ifdef CORE_CM4 /* Enable CM4 receive irq */ - HAL_NVIC_SetPriority(HSEM2_IRQn, 2, 0); + HAL_NVIC_SetPriority(HSEM2_IRQn, 0, 1); HAL_NVIC_EnableIRQ(HSEM2_IRQn); HAL_HSEM_ActivateNotification(__HAL_HSEM_SEMID_TO_MASK(HSEM_ID_0)); #endif diff --git a/libraries/openamp_arduino/src/mailbox_hsem_if.h b/libraries/openamp_arduino/src/mailbox_hsem_if.h index e638d6b..4c0cab5 100644 --- a/libraries/openamp_arduino/src/mailbox_hsem_if.h +++ b/libraries/openamp_arduino/src/mailbox_hsem_if.h @@ -1,55 +1,55 @@ -/** - ****************************************************************************** - * @file mailbox_hsem_if.h - * @author MCD Application Team - * @brief header for mailbox_hsem_if.c module - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2017 STMicroelectronics

- * - * 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 STMicroelectronics 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. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef MAILBOX_HSEM_IF_H_ -#define MAILBOX_HSEM_IF_H_ - -/* USER CODE BEGIN firstSection */ -/* can be used to modify / undefine following code or add new definitions */ -/* USER CODE END firstSection */ - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -#define HSEM_ID_0 0 /* CM7 to CM4 Notification */ -#define HSEM_ID_1 1 /* CM4 to CM7 Notification */ - -/* Exported functions ------------------------------------------------------- */ -int MAILBOX_Notify(void *priv, uint32_t id); -int MAILBOX_Init(void); -int MAILBOX_Poll(struct virtio_device *vdev); - -#endif /* MAILBOX_HSEM_IF_H_ */ +/** + ****************************************************************************** + * @file mailbox_hsem_if.h + * @author MCD Application Team + * @brief header for mailbox_hsem_if.c module + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * 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 STMicroelectronics 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. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MAILBOX_HSEM_IF_H_ +#define MAILBOX_HSEM_IF_H_ + +/* USER CODE BEGIN firstSection */ +/* can be used to modify / undefine following code or add new definitions */ +/* USER CODE END firstSection */ + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +#define HSEM_ID_0 0 /* CM7 to CM4 Notification */ +#define HSEM_ID_1 1 /* CM4 to CM7 Notification */ + +/* Exported functions ------------------------------------------------------- */ +int MAILBOX_Notify(void *priv, uint32_t id); +int MAILBOX_Init(void); +int MAILBOX_Poll(struct virtio_device *vdev); + +#endif /* MAILBOX_HSEM_IF_H_ */ diff --git a/libraries/openamp_arduino/src/mbox_hsem.h b/libraries/openamp_arduino/src/mbox_hsem.h index 170fc72..d860f43 100644 --- a/libraries/openamp_arduino/src/mbox_hsem.h +++ b/libraries/openamp_arduino/src/mbox_hsem.h @@ -1,39 +1,39 @@ -/** - ****************************************************************************** - * @file mabox_hsem.h - * @author MCD Application Team - * @brief header for mbox_hsem.c module - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef MBOX_HSEM_IF_H_ -#define MBOX_HSEM_IF_H_ - -/* USER CODE BEGIN firstSection */ -/* can be used to modify / undefine following code or add new definitions */ -/* USER CODE END firstSection */ - -/* Includes ------------------------------------------------------------------*/ -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -#define HSEM_ID_0 0 /* CM7 to CM4 Notification */ -#define HSEM_ID_1 1 /* CM4 to CM7 Notification */ - -/* Exported functions ------------------------------------------------------- */ -int MAILBOX_Notify(void *priv, uint32_t id); -int MAILBOX_Init(void); -int MAILBOX_Poll(struct virtio_device *vdev); - -#endif /* MBOX_HSEM_IF_H_ */ +/** + ****************************************************************************** + * @file mabox_hsem.h + * @author MCD Application Team + * @brief header for mbox_hsem.c module + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef MBOX_HSEM_IF_H_ +#define MBOX_HSEM_IF_H_ + +/* USER CODE BEGIN firstSection */ +/* can be used to modify / undefine following code or add new definitions */ +/* USER CODE END firstSection */ + +/* Includes ------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +#define HSEM_ID_0 0 /* CM7 to CM4 Notification */ +#define HSEM_ID_1 1 /* CM4 to CM7 Notification */ + +/* Exported functions ------------------------------------------------------- */ +int MAILBOX_Notify(void *priv, uint32_t id); +int MAILBOX_Init(void); +int MAILBOX_Poll(struct virtio_device *vdev); + +#endif /* MBOX_HSEM_IF_H_ */ diff --git a/libraries/openamp_arduino/src/metal/alloc.h b/libraries/openamp_arduino/src/metal/alloc.h index b82a09a..02f860b 100755 --- a/libraries/openamp_arduino/src/metal/alloc.h +++ b/libraries/openamp_arduino/src/metal/alloc.h @@ -1,46 +1,53 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file alloc.h - * @brief Memory allocation handling primitives for libmetal. - */ - -#ifndef __METAL_ALLOC__H__ -#define __METAL_ALLOC__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup Memory Allocation Interfaces - * @{ */ - -/** - * @brief allocate requested memory size - * return a pointer to the allocated memory - * - * @param[in] size size in byte of requested memory - * @return memory pointer, or 0 if it failed to allocate - */ -static inline void *metal_allocate_memory(unsigned int size); - -/** - * @brief free the memory previously allocated - * - * @param[in] ptr pointer to memory - */ -static inline void metal_free_memory(void *ptr); - -#include - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_ALLOC__H__ */ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file alloc.h + * @brief Memory allocation handling primitives for libmetal. + */ + +#ifndef __METAL_ALLOC__H__ +#define __METAL_ALLOC__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Memory Allocation Interfaces + * @{ + */ + +/** + * @brief allocate requested memory size + * return a pointer to the allocated memory + * + * @param[in] size size in byte of requested memory + * @return memory pointer, or 0 if it failed to allocate + */ +static inline void *metal_allocate_memory(unsigned int size) +{ + return __metal_allocate_memory(size); +} + +/** + * @brief free the memory previously allocated + * + * @param[in] ptr pointer to memory + */ +static inline void metal_free_memory(void *ptr) +{ + __metal_free_memory(ptr); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_ALLOC__H__ */ diff --git a/libraries/openamp_arduino/src/metal/assert.h b/libraries/openamp_arduino/src/metal/assert.h index 8357fdf..4476b64 100755 --- a/libraries/openamp_arduino/src/metal/assert.h +++ b/libraries/openamp_arduino/src/metal/assert.h @@ -1,26 +1,24 @@ -/* - * Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file assert.h - * @brief Assertion support. - */ - -#ifndef __METAL_ASSERT__H__ -#define __METAL_ASSERT__H__ - -//#include -//#include -#include - -/** - * @brief Assertion macro. - * @param cond Condition to test. - */ -#define metal_assert(cond) metal_sys_assert(cond) - -#endif /* __METAL_ASSERT_H__ */ - +/* + * Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file assert.h + * @brief Assertion support. + */ + +#ifndef __METAL_ASSERT__H__ +#define __METAL_ASSERT__H__ + +#include + +/** + * @brief Assertion macro. + * @param cond Condition to test. + */ +#define metal_assert(cond) metal_sys_assert(cond) + +#endif /* __METAL_ASSERT_H__ */ + diff --git a/libraries/openamp_arduino/src/metal/atomic.h b/libraries/openamp_arduino/src/metal/atomic.h index 14f771e..ce8595d 100755 --- a/libraries/openamp_arduino/src/metal/atomic.h +++ b/libraries/openamp_arduino/src/metal/atomic.h @@ -1,32 +1,113 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file atomic.h - * @brief Atomic primitives for libmetal. - */ - -#ifndef __METAL_ATOMIC__H__ -#define __METAL_ATOMIC__H__ - -#include - -#if defined(HAVE_STDATOMIC_H) && !defined (__CC_ARM) && \ - !defined(__STDC_NO_ATOMICS__) && !defined(__cplusplus) - -# include - -#ifndef atomic_thread_fence -#define atomic_thread_fence(order) -#endif - -#elif defined(__GNUC__) -# include -#else -# include -#endif - -#endif /* __METAL_ATOMIC__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file atomic.h + * @brief Atomic primitives for libmetal. + */ + +#ifndef __METAL_ATOMIC__H__ +#define __METAL_ATOMIC__H__ + +#include + +#if defined(__cplusplus) +# include + +/* + * has the same functionality as but all members are only + * accessible in the std namespace. As the rest of libmetal is pure C, it does + * not know about namespaces, even when compiled as part of a C++ file. So we + * just export the members of into the global namespace. + */ +# include +using std::atomic_flag; +using std::memory_order; +using std::memory_order_relaxed; +using std::memory_order_consume; +using std::memory_order_acquire; +using std::memory_order_release; +using std::memory_order_acq_rel; +using std::memory_order_seq_cst; + +using std::atomic_bool; +using std::atomic_char; +using std::atomic_schar; +using std::atomic_uchar; +using std::atomic_short; +using std::atomic_ushort; +using std::atomic_int; +using std::atomic_uint; +using std::atomic_long; +using std::atomic_ulong; +using std::atomic_llong; +using std::atomic_ullong; +using std::atomic_char16_t; +using std::atomic_char32_t; +using std::atomic_wchar_t; +using std::atomic_int_least8_t; +using std::atomic_uint_least8_t; +using std::atomic_int_least16_t; +using std::atomic_uint_least16_t; +using std::atomic_int_least32_t; +using std::atomic_uint_least32_t; +using std::atomic_int_least64_t; +using std::atomic_uint_least64_t; +using std::atomic_int_fast8_t; +using std::atomic_uint_fast8_t; +using std::atomic_int_fast16_t; +using std::atomic_uint_fast16_t; +using std::atomic_int_fast32_t; +using std::atomic_uint_fast32_t; +using std::atomic_int_fast64_t; +using std::atomic_uint_fast64_t; +using std::atomic_intptr_t; +using std::atomic_uintptr_t; +using std::atomic_size_t; +using std::atomic_ptrdiff_t; +using std::atomic_intmax_t; +using std::atomic_uintmax_t; + +using std::atomic_flag_test_and_set; +using std::atomic_flag_test_and_set_explicit; +using std::atomic_flag_clear; +using std::atomic_flag_clear_explicit; +using std::atomic_init; +using std::atomic_is_lock_free; +using std::atomic_store; +using std::atomic_store_explicit; +using std::atomic_load; +using std::atomic_load_explicit; +using std::atomic_exchange; +using std::atomic_exchange_explicit; +using std::atomic_compare_exchange_strong; +using std::atomic_compare_exchange_strong_explicit; +using std::atomic_compare_exchange_weak; +using std::atomic_compare_exchange_weak_explicit; +using std::atomic_fetch_add; +using std::atomic_fetch_add_explicit; +using std::atomic_fetch_sub; +using std::atomic_fetch_sub_explicit; +using std::atomic_fetch_or; +using std::atomic_fetch_or_explicit; +using std::atomic_fetch_xor; +using std::atomic_fetch_xor_explicit; +using std::atomic_fetch_and; +using std::atomic_fetch_and_explicit; +using std::atomic_thread_fence; +using std::atomic_signal_fence; + +#elif defined(HAVE_STDATOMIC_H) && !defined(__CC_ARM) && \ + !defined(__STDC_NO_ATOMICS__) +# include +# include +#elif defined(__GNUC__) +# include +#else +# include +#endif + +#endif /* __METAL_ATOMIC__H__ */ diff --git a/libraries/openamp_arduino/src/metal/cache.h b/libraries/openamp_arduino/src/metal/cache.h index 54a0155..02917b4 100755 --- a/libraries/openamp_arduino/src/metal/cache.h +++ b/libraries/openamp_arduino/src/metal/cache.h @@ -1,57 +1,57 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file cache.h - * @brief CACHE operation primitives for libmetal. - */ - -#ifndef __METAL_CACHE__H__ -#define __METAL_CACHE__H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \defgroup cache CACHE Interfaces - * @{ */ - -/** - * @brief flush specified data cache - * - * @param[in] addr start memory logical address - * @param[in] len length of memory - * If addr is NULL, and len is 0, - * It will flush the whole data cache. - */ -static inline void metal_cache_flush(void *addr, unsigned int len) -{ - __metal_cache_flush(addr, len); -} - -/** - * @brief invalidate specified data cache - * - * @param[in] addr start memory logical address - * @param[in] len length of memory - * If addr is NULL, and len is 0, - * It will invalidate the whole data cache. - */ -static inline void metal_cache_invalidate(void *addr, unsigned int len) -{ - __metal_cache_invalidate(addr, len); -} - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_CACHE__H__ */ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cache.h + * @brief CACHE operation primitives for libmetal. + */ + +#ifndef __METAL_CACHE__H__ +#define __METAL_CACHE__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup cache CACHE Interfaces + * @{ + */ + +/** + * @brief flush specified data cache + * + * @param[in] addr start memory logical address + * @param[in] len length of memory + * If addr is NULL, and len is 0, + * It will flush the whole data cache. + */ +static inline void metal_cache_flush(void *addr, unsigned int len) +{ + __metal_cache_flush(addr, len); +} + +/** + * @brief invalidate specified data cache + * + * @param[in] addr start memory logical address + * @param[in] len length of memory + * If addr is NULL, and len is 0, + * It will invalidate the whole data cache. + */ +static inline void metal_cache_invalidate(void *addr, unsigned int len) +{ + __metal_cache_invalidate(addr, len); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_CACHE__H__ */ diff --git a/libraries/openamp_arduino/src/metal/compiler.h b/libraries/openamp_arduino/src/metal/compiler.h index ec4c675..08c2094 100755 --- a/libraries/openamp_arduino/src/metal/compiler.h +++ b/libraries/openamp_arduino/src/metal/compiler.h @@ -1,25 +1,25 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file compiler.h - * @brief Compiler specific primitives for libmetal. - */ - -#ifndef __METAL_COMPILER__H__ -#define __METAL_COMPILER__H__ - -#if defined(__GNUC__) -# include -#elif defined(__ICCARM__) -# include -#elif defined (__CC_ARM) -# error "MDK-ARM ARMCC compiler requires the GNU extentions to work correctly" -#else -# error "Missing compiler support" -#endif - -#endif /* __METAL_COMPILER__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file compiler.h + * @brief Compiler specific primitives for libmetal. + */ + +#ifndef __METAL_COMPILER__H__ +#define __METAL_COMPILER__H__ + +#if defined(__GNUC__) +# include +#elif defined(__ICCARM__) +# include +#elif defined(__CC_ARM) +# error "MDK-ARM ARMCC compiler requires the GNU extensions to work correctly" +#else +# error "Missing compiler support" +#endif + +#endif /* __METAL_COMPILER__H__ */ diff --git a/libraries/openamp_arduino/src/metal/compiler/gcc/atomic.h b/libraries/openamp_arduino/src/metal/compiler/gcc/atomic.h index 4470342..7d66299 100755 --- a/libraries/openamp_arduino/src/metal/compiler/gcc/atomic.h +++ b/libraries/openamp_arduino/src/metal/compiler/gcc/atomic.h @@ -1,123 +1,124 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file gcc/atomic.h - * @brief GCC specific atomic primitives for libmetal. - */ - -#ifndef __METAL_GCC_ATOMIC__H__ -#define __METAL_GCC_ATOMIC__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef int atomic_flag; -typedef char atomic_char; -typedef unsigned char atomic_uchar; -typedef short atomic_short; -typedef unsigned short atomic_ushort; -typedef int atomic_int; -typedef unsigned int atomic_uint; -typedef long atomic_long; -typedef unsigned long atomic_ulong; -typedef long long atomic_llong; -typedef unsigned long long atomic_ullong; - -#define ATOMIC_FLAG_INIT 0 -#define ATOMIC_VAR_INIT(VAL) (VAL) - -typedef enum { - memory_order_relaxed, - memory_order_consume, - memory_order_acquire, - memory_order_release, - memory_order_acq_rel, - memory_order_seq_cst, -} memory_order; - -#define atomic_flag_test_and_set(FLAG) \ - __sync_lock_test_and_set((FLAG), 1) -#define atomic_flag_test_and_set_explicit(FLAG, MO) \ - atomic_flag_test_and_set(FLAG) -#define atomic_flag_clear(FLAG) \ - __sync_lock_release((FLAG)) -#define atomic_flag_clear_explicit(FLAG, MO) \ - atomic_flag_clear(FLAG) -#define atomic_init(OBJ, VAL) \ - do { *(OBJ) = (VAL); } while (0) -#define atomic_is_lock_free(OBJ) \ - (sizeof(*(OBJ)) <= sizeof(long)) -#define atomic_store(OBJ, VAL) \ - do { *(OBJ) = (VAL); __sync_synchronize(); } while (0) -#define atomic_store_explicit(OBJ, VAL, MO) \ - atomic_store((OBJ), (VAL)) -#define atomic_load(OBJ) \ - ({ __sync_synchronize(); *(OBJ); }) -#define atomic_load_explicit(OBJ, MO) \ - atomic_load(OBJ) -#define atomic_exchange(OBJ, DES) \ - ({ \ - typeof(OBJ) obj = (OBJ); \ - typeof(*obj) des = (DES); \ - typeof(*obj) expval; \ - typeof(*obj) oldval = atomic_load(obj); \ - do { \ - expval = oldval; \ - oldval = __sync_val_compare_and_swap( \ - obj, expval, des); \ - } while (oldval != expval); \ - oldval; \ - }) -#define atomic_exchange_explicit(OBJ, DES, MO) \ - atomic_exchange((OBJ), (DES)) -#define atomic_compare_exchange_strong(OBJ, EXP, DES) \ - ({ \ - typeof(OBJ) obj = (OBJ); \ - typeof(EXP) exp = (EXP); \ - typeof(*obj) expval = *exp; \ - typeof(*obj) oldval = __sync_val_compare_and_swap( \ - obj, expval, (DES)); \ - *exp = oldval; \ - oldval == expval; \ - }) -#define atomic_compare_exchange_strong_explicit(OBJ, EXP, DES, MO) \ - atomic_compare_exchange_strong((OBJ), (EXP), (DES)) -#define atomic_compare_exchange_weak(OBJ, EXP, DES) \ - atomic_compare_exchange_strong((OBJ), (EXP), (DES)) -#define atomic_compare_exchange_weak_explicit(OBJ, EXP, DES, MO) \ - atomic_compare_exchange_weak((OBJ), (EXP), (DES)) -#define atomic_fetch_add(OBJ, VAL) \ - __sync_fetch_and_add((OBJ), (VAL)) -#define atomic_fetch_add_explicit(OBJ, VAL, MO) \ - atomic_fetch_add((OBJ), (VAL)) -#define atomic_fetch_sub(OBJ, VAL) \ - __sync_fetch_and_sub((OBJ), (VAL)) -#define atomic_fetch_sub_explicit(OBJ, VAL, MO) \ - atomic_fetch_sub((OBJ), (VAL)) -#define atomic_fetch_or(OBJ, VAL) \ - __sync_fetch_and_or((OBJ), (VAL)) -#define atomic_fetch_or_explicit(OBJ, VAL, MO) \ - atomic_fetch_or((OBJ), (VAL)) -#define atomic_fetch_xor(OBJ, VAL) \ - __sync_fetch_and_xor((OBJ), (VAL)) -#define atomic_fetch_xor_explicit(OBJ, VAL, MO) \ - atomic_fetch_xor((OBJ), (VAL)) -#define atomic_fetch_and(OBJ, VAL) \ - __sync_fetch_and_and((OBJ), (VAL)) -#define atomic_fetch_and_explicit(OBJ, VAL, MO) \ - atomic_fetch_and((OBJ), (VAL)) -#define atomic_thread_fence(MO) \ - __sync_synchronize() -#define atomic_signal_fence(MO) \ - __sync_synchronize() - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_GCC_ATOMIC__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file gcc/atomic.h + * @brief GCC specific atomic primitives for libmetal. + */ + +#ifndef __METAL_GCC_ATOMIC__H__ +#define __METAL_GCC_ATOMIC__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int atomic_flag; +typedef char atomic_char; +typedef unsigned char atomic_uchar; +typedef short atomic_short; +typedef unsigned short atomic_ushort; +typedef int atomic_int; +typedef unsigned int atomic_uint; +typedef atomic_uint atomic_uintptr_t; +typedef long atomic_long; +typedef unsigned long atomic_ulong; +typedef long long atomic_llong; +typedef unsigned long long atomic_ullong; + +#define ATOMIC_FLAG_INIT 0 +#define ATOMIC_VAR_INIT(VAL) (VAL) + +typedef enum { + memory_order_relaxed, + memory_order_consume, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst, +} memory_order; + +#define atomic_flag_test_and_set(FLAG) \ + __sync_lock_test_and_set((FLAG), 1) +#define atomic_flag_test_and_set_explicit(FLAG, MO) \ + atomic_flag_test_and_set(FLAG) +#define atomic_flag_clear(FLAG) \ + __sync_lock_release((FLAG)) +#define atomic_flag_clear_explicit(FLAG, MO) \ + atomic_flag_clear(FLAG) +#define atomic_init(OBJ, VAL) \ + do { *(OBJ) = (VAL); } while (0) +#define atomic_is_lock_free(OBJ) \ + (sizeof(*(OBJ)) <= sizeof(long)) +#define atomic_store(OBJ, VAL) \ + do { *(OBJ) = (VAL); __sync_synchronize(); } while (0) +#define atomic_store_explicit(OBJ, VAL, MO) \ + atomic_store((OBJ), (VAL)) +#define atomic_load(OBJ) \ + ({ __sync_synchronize(); *(OBJ); }) +#define atomic_load_explicit(OBJ, MO) \ + atomic_load(OBJ) +#define atomic_exchange(OBJ, DES) \ + ({ \ + __typeof__(OBJ) obj = (OBJ); \ + __typeof__(*obj) des = (DES); \ + __typeof__(*obj) expval; \ + __typeof__(*obj) oldval = atomic_load(obj); \ + do { \ + expval = oldval; \ + oldval = __sync_val_compare_and_swap( \ + obj, expval, des); \ + } while (oldval != expval); \ + oldval; \ + }) +#define atomic_exchange_explicit(OBJ, DES, MO) \ + atomic_exchange((OBJ), (DES)) +#define atomic_compare_exchange_strong(OBJ, EXP, DES) \ + ({ \ + __typeof__(OBJ) obj = (OBJ); \ + __typeof__(EXP) exp = (EXP); \ + __typeof__(*obj) expval = *exp; \ + __typeof__(*obj) oldval = __sync_val_compare_and_swap( \ + obj, expval, (DES)); \ + *exp = oldval; \ + oldval == expval; \ + }) +#define atomic_compare_exchange_strong_explicit(OBJ, EXP, DES, MO) \ + atomic_compare_exchange_strong((OBJ), (EXP), (DES)) +#define atomic_compare_exchange_weak(OBJ, EXP, DES) \ + atomic_compare_exchange_strong((OBJ), (EXP), (DES)) +#define atomic_compare_exchange_weak_explicit(OBJ, EXP, DES, MO) \ + atomic_compare_exchange_weak((OBJ), (EXP), (DES)) +#define atomic_fetch_add(OBJ, VAL) \ + __sync_fetch_and_add((OBJ), (VAL)) +#define atomic_fetch_add_explicit(OBJ, VAL, MO) \ + atomic_fetch_add((OBJ), (VAL)) +#define atomic_fetch_sub(OBJ, VAL) \ + __sync_fetch_and_sub((OBJ), (VAL)) +#define atomic_fetch_sub_explicit(OBJ, VAL, MO) \ + atomic_fetch_sub((OBJ), (VAL)) +#define atomic_fetch_or(OBJ, VAL) \ + __sync_fetch_and_or((OBJ), (VAL)) +#define atomic_fetch_or_explicit(OBJ, VAL, MO) \ + atomic_fetch_or((OBJ), (VAL)) +#define atomic_fetch_xor(OBJ, VAL) \ + __sync_fetch_and_xor((OBJ), (VAL)) +#define atomic_fetch_xor_explicit(OBJ, VAL, MO) \ + atomic_fetch_xor((OBJ), (VAL)) +#define atomic_fetch_and(OBJ, VAL) \ + __sync_fetch_and_and((OBJ), (VAL)) +#define atomic_fetch_and_explicit(OBJ, VAL, MO) \ + atomic_fetch_and((OBJ), (VAL)) +#define atomic_thread_fence(MO) \ + __sync_synchronize() +#define atomic_signal_fence(MO) \ + __sync_synchronize() + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GCC_ATOMIC__H__ */ diff --git a/libraries/openamp_arduino/src/metal/compiler/gcc/compiler.h b/libraries/openamp_arduino/src/metal/compiler/gcc/compiler.h index 7295ca8..e4d1bc9 100755 --- a/libraries/openamp_arduino/src/metal/compiler/gcc/compiler.h +++ b/libraries/openamp_arduino/src/metal/compiler/gcc/compiler.h @@ -1,27 +1,45 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file gcc/compiler.h - * @brief GCC specific primitives for libmetal. - */ - -#ifndef __METAL_GCC_COMPILER__H__ -#define __METAL_GCC_COMPILER__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define restrict __restrict__ -#define metal_align(n) __attribute__((aligned(n))) -#define metal_weak __attribute__((weak)) - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_GCC_COMPILER__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file gcc/compiler.h + * @brief GCC specific primitives for libmetal. + */ + +#ifndef __METAL_GCC_COMPILER__H__ +#define __METAL_GCC_COMPILER__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define restrict __restrict__ +#define metal_align(n) __attribute__((aligned(n))) +#define metal_weak __attribute__((weak)) + +#if defined(__STRICT_ANSI__) +#define metal_asm __asm__ +#else +/* + * Even though __asm__ is always available in mainline GCC, we use asm in + * the non-strict modes for compatibility with other compilers that define + * __GNUC__ + */ +#define metal_asm asm +#endif + +#define METAL_PACKED_BEGIN +#define METAL_PACKED_END __attribute__((__packed__)) + +#ifndef __deprecated +#define __deprecated __attribute__((deprecated)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GCC_COMPILER__H__ */ diff --git a/libraries/openamp_arduino/src/metal/condition.h b/libraries/openamp_arduino/src/metal/condition.h index 9532936..b5c7b2d 100755 --- a/libraries/openamp_arduino/src/metal/condition.h +++ b/libraries/openamp_arduino/src/metal/condition.h @@ -1,73 +1,74 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file condition.h - * @brief Condition variable for libmetal. - */ - -#ifndef __METAL_CONDITION__H__ -#define __METAL_CONDITION__H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup condition Condition Variable Interfaces - * @{ */ - -/** Opaque libmetal condition variable data structure. */ -struct metal_condition; - -/** - * @brief Initialize a libmetal condition variable. - * @param[in] cv condition variable to initialize. - */ -static inline void metal_condition_init(struct metal_condition *cv); - -/** - * @brief Notify one waiter. - * Before calling this function, the caller - * should have acquired the mutex. - * @param[in] cv condition variable - * @return zero on no errors, non-zero on errors - * @see metal_condition_wait, metal_condition_broadcast - */ -static inline int metal_condition_signal(struct metal_condition *cv); - -/** - * @brief Notify all waiters. - * Before calling this function, the caller - * should have acquired the mutex. - * @param[in] cv condition variable - * @return zero on no errors, non-zero on errors - * @see metal_condition_wait, metal_condition_signal - */ -static inline int metal_condition_broadcast(struct metal_condition *cv); - -/** - * @brief Block until the condition variable is notified. - * Before calling this function, the caller should - * have acquired the mutex. - * @param[in] cv condition variable - * @param[in] m mutex - * @return 0 on success, non-zero on failure. - * @see metal_condition_signal - */ -int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m); - -#include - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_CONDITION__H__ */ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file condition.h + * @brief Condition variable for libmetal. + */ + +#ifndef __METAL_CONDITION__H__ +#define __METAL_CONDITION__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup condition Condition Variable Interfaces + * @{ + */ + +/** Opaque libmetal condition variable data structure. */ +struct metal_condition; + +/** + * @brief Initialize a libmetal condition variable. + * @param[in] cv condition variable to initialize. + */ +static inline void metal_condition_init(struct metal_condition *cv); + +/** + * @brief Notify one waiter. + * Before calling this function, the caller + * should have acquired the mutex. + * @param[in] cv condition variable + * @return zero on no errors, non-zero on errors + * @see metal_condition_wait, metal_condition_broadcast + */ +static inline int metal_condition_signal(struct metal_condition *cv); + +/** + * @brief Notify all waiters. + * Before calling this function, the caller + * should have acquired the mutex. + * @param[in] cv condition variable + * @return zero on no errors, non-zero on errors + * @see metal_condition_wait, metal_condition_signal + */ +static inline int metal_condition_broadcast(struct metal_condition *cv); + +/** + * @brief Block until the condition variable is notified. + * Before calling this function, the caller should + * have acquired the mutex. + * @param[in] cv condition variable + * @param[in] m mutex + * @return 0 on success, non-zero on failure. + * @see metal_condition_signal + */ +int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* __METAL_CONDITION__H__ */ diff --git a/libraries/openamp_arduino/src/metal/config.h b/libraries/openamp_arduino/src/metal/config.h index ce08057..3de9060 100755 --- a/libraries/openamp_arduino/src/metal/config.h +++ b/libraries/openamp_arduino/src/metal/config.h @@ -20,13 +20,13 @@ extern "C" { #define METAL_VER_MAJOR 0 /** Library minor version number. */ -#define METAL_VER_MINOR 1 +#define METAL_VER_MINOR 5 /** Library patch level. */ #define METAL_VER_PATCH 0 /** Library version string. */ -#define METAL_VER "0.1.0" +#define METAL_VER "0.5.0" /** System type (linux, generic, ...). */ #define METAL_SYSTEM "generic" diff --git a/libraries/openamp_arduino/src/metal/cpu.h b/libraries/openamp_arduino/src/metal/cpu.h index 5537afb..26dbaa2 100755 --- a/libraries/openamp_arduino/src/metal/cpu.h +++ b/libraries/openamp_arduino/src/metal/cpu.h @@ -1,17 +1,17 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file cpu.h - * @brief CPU primitives for libmetal. - */ - -#ifndef __METAL_CPU__H__ -#define __METAL_CPU__H__ - -# include - -#endif /* __METAL_CPU__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cpu.h + * @brief CPU primitives for libmetal. + */ + +#ifndef __METAL_CPU__H__ +#define __METAL_CPU__H__ + +# include + +#endif /* __METAL_CPU__H__ */ diff --git a/libraries/openamp_arduino/src/metal/device.h b/libraries/openamp_arduino/src/metal/device.h index c78b50d..fab1c14 100755 --- a/libraries/openamp_arduino/src/metal/device.h +++ b/libraries/openamp_arduino/src/metal/device.h @@ -1,176 +1,177 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file device.h - * @brief Bus abstraction for libmetal. - */ - -#ifndef __METAL_BUS__H__ -#define __METAL_BUS__H__ - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup device Bus Abstraction - * @{ */ - -#ifndef METAL_MAX_DEVICE_REGIONS -#define METAL_MAX_DEVICE_REGIONS 32 -#endif - -struct metal_bus; -struct metal_device; - -/** Bus operations. */ -struct metal_bus_ops { - void (*bus_close)(struct metal_bus *bus); - int (*dev_open)(struct metal_bus *bus, - const char *dev_name, - struct metal_device **device); - void (*dev_close)(struct metal_bus *bus, - struct metal_device *device); - void (*dev_irq_ack)(struct metal_bus *bus, - struct metal_device *device, - int irq); - int (*dev_dma_map)(struct metal_bus *bus, - struct metal_device *device, - uint32_t dir, - struct metal_sg *sg_in, - int nents_in, - struct metal_sg *sg_out); - void (*dev_dma_unmap)(struct metal_bus *bus, - struct metal_device *device, - uint32_t dir, - struct metal_sg *sg, - int nents); -}; - -/** Libmetal bus structure. */ -struct metal_bus { - const char *name; - struct metal_bus_ops ops; - struct metal_list devices; - struct metal_list node; -}; - -/** Libmetal generic bus. */ -extern struct metal_bus metal_generic_bus; - -/** Libmetal device structure. */ -struct metal_device { - const char *name; /**< Device name */ - struct metal_bus *bus; /**< Bus that contains device */ - unsigned num_regions; /**< Number of I/O regions in - device */ - struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of - I/O regions in device*/ - struct metal_list node; /**< Node on bus' list of devices */ - int irq_num; /**< Number of IRQs per device */ - void *irq_info; /**< IRQ ID */ -}; - -/** - * @brief Register a libmetal bus. - * @param[in] bus Pre-initialized bus structure. - * @return 0 on success, or -errno on failure. - */ -extern int metal_bus_register(struct metal_bus *bus); - -/** - * @brief Unregister a libmetal bus. - * @param[in] bus Pre-registered bus structure. - * @return 0 on success, or -errno on failure. - */ -extern int metal_bus_unregister(struct metal_bus *bus); - -/** - * @brief Find a libmetal bus by name. - * @param[in] name Bus name. - * @param[out] bus Returned bus handle. - * @return 0 on success, or -errno on failure. - */ -extern int metal_bus_find(const char *name, struct metal_bus **bus); - -/** - * @brief Statically register a generic libmetal device. - * - * In non-Linux systems, devices are always required to be statically - * registered at application initialization. - * In Linux system, devices can be dynamically opened via sysfs or libfdt based - * enumeration at runtime. - * This interface is used for static registration of devices. Subsequent calls - * to metal_device_open() look up in this list of pre-registered devices on the - * "generic" bus. - * "generic" bus is used on non-Linux system to group the memory mapped devices. - * - * @param[in] device Generic device. - * @return 0 on success, or -errno on failure. - */ -extern int metal_register_generic_device(struct metal_device *device); - -/** - * @brief Open a libmetal device by name. - * @param[in] bus_name Bus name. - * @param[in] dev_name Device name. - * @param[out] device Returned device handle. - * @return 0 on success, or -errno on failure. - */ -extern int metal_device_open(const char *bus_name, const char *dev_name, - struct metal_device **device); - -/** - * @brief Close a libmetal device. - * @param[in] device Device handle. - */ -extern void metal_device_close(struct metal_device *device); - -/** - * @brief Get an I/O region accessor for a device region. - * - * @param[in] device Device handle. - * @param[in] index Region index. - * @return I/O accessor handle, or NULL on failure. - */ -static inline struct metal_io_region * -metal_device_io_region(struct metal_device *device, unsigned index) -{ - return (index < device->num_regions - ? &device->regions[index] - : NULL); -} - -/** @} */ - -#ifdef METAL_INTERNAL -extern int metal_generic_dev_sys_open(struct metal_device *dev); -extern int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name, - struct metal_device **device); -extern int metal_generic_dev_dma_map(struct metal_bus *bus, - struct metal_device *device, - uint32_t dir, - struct metal_sg *sg_in, - int nents_in, - struct metal_sg *sg_out); -extern void metal_generic_dev_dma_unmap(struct metal_bus *bus, - struct metal_device *device, - uint32_t dir, - struct metal_sg *sg, - int nents); -#endif /* METAL_INTERNAL */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_BUS__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file device.h + * @brief Bus abstraction for libmetal. + */ + +#ifndef __METAL_BUS__H__ +#define __METAL_BUS__H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup device Bus Abstraction + * @{ + */ + +#ifndef METAL_MAX_DEVICE_REGIONS +#define METAL_MAX_DEVICE_REGIONS 32 +#endif + +struct metal_bus; +struct metal_device; + +/** Bus operations. */ +struct metal_bus_ops { + void (*bus_close)(struct metal_bus *bus); + int (*dev_open)(struct metal_bus *bus, + const char *dev_name, + struct metal_device **device); + void (*dev_close)(struct metal_bus *bus, + struct metal_device *device); + void (*dev_irq_ack)(struct metal_bus *bus, + struct metal_device *device, + int irq); + int (*dev_dma_map)(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out); + void (*dev_dma_unmap)(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg, + int nents); +}; + +/** Libmetal bus structure. */ +struct metal_bus { + const char *name; + struct metal_bus_ops ops; + struct metal_list devices; + struct metal_list node; +}; + +/** Libmetal generic bus. */ +extern struct metal_bus metal_generic_bus; + +/** Libmetal device structure. */ +struct metal_device { + const char *name; /**< Device name */ + struct metal_bus *bus; /**< Bus that contains device */ + unsigned int num_regions; /**< Number of I/O regions in + device */ + struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of + I/O regions in device*/ + struct metal_list node; /**< Node on bus' list of devices */ + int irq_num; /**< Number of IRQs per device */ + void *irq_info; /**< IRQ ID */ +}; + +/** + * @brief Register a libmetal bus. + * @param[in] bus Pre-initialized bus structure. + * @return 0 on success, or -errno on failure. + */ +extern int metal_bus_register(struct metal_bus *bus); + +/** + * @brief Unregister a libmetal bus. + * @param[in] bus Pre-registered bus structure. + * @return 0 on success, or -errno on failure. + */ +extern int metal_bus_unregister(struct metal_bus *bus); + +/** + * @brief Find a libmetal bus by name. + * @param[in] name Bus name. + * @param[out] bus Returned bus handle. + * @return 0 on success, or -errno on failure. + */ +extern int metal_bus_find(const char *name, struct metal_bus **bus); + +/** + * @brief Statically register a generic libmetal device. + * + * In non-Linux systems, devices are always required to be statically + * registered at application initialization. + * In Linux system, devices can be dynamically opened via sysfs or libfdt based + * enumeration at runtime. + * This interface is used for static registration of devices. Subsequent calls + * to metal_device_open() look up in this list of pre-registered devices on the + * "generic" bus. + * "generic" bus is used on non-Linux system to group the memory mapped devices. + * + * @param[in] device Generic device. + * @return 0 on success, or -errno on failure. + */ +extern int metal_register_generic_device(struct metal_device *device); + +/** + * @brief Open a libmetal device by name. + * @param[in] bus_name Bus name. + * @param[in] dev_name Device name. + * @param[out] device Returned device handle. + * @return 0 on success, or -errno on failure. + */ +extern int metal_device_open(const char *bus_name, const char *dev_name, + struct metal_device **device); + +/** + * @brief Close a libmetal device. + * @param[in] device Device handle. + */ +extern void metal_device_close(struct metal_device *device); + +/** + * @brief Get an I/O region accessor for a device region. + * + * @param[in] device Device handle. + * @param[in] index Region index. + * @return I/O accessor handle, or NULL on failure. + */ +static inline struct metal_io_region * +metal_device_io_region(struct metal_device *device, unsigned int index) +{ + return (index < device->num_regions + ? &device->regions[index] + : NULL); +} + +/** @} */ + +#ifdef METAL_INTERNAL +extern int metal_generic_dev_sys_open(struct metal_device *dev); +extern int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name, + struct metal_device **device); +extern int metal_generic_dev_dma_map(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out); +extern void metal_generic_dev_dma_unmap(struct metal_bus *bus, + struct metal_device *device, + uint32_t dir, + struct metal_sg *sg, + int nents); +#endif /* METAL_INTERNAL */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_BUS__H__ */ diff --git a/libraries/openamp_arduino/src/metal/dma.h b/libraries/openamp_arduino/src/metal/dma.h index 1c8e8b1..9bb7e54 100755 --- a/libraries/openamp_arduino/src/metal/dma.h +++ b/libraries/openamp_arduino/src/metal/dma.h @@ -1,79 +1,80 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file dma.h - * @brief DMA primitives for libmetal. - */ - -#ifndef __METAL_DMA__H__ -#define __METAL_DMA__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup dma DMA Interfaces - * @{ */ - -#include -#include - -#define METAL_DMA_DEV_R 1 /**< DMA direction, device read */ -#define METAL_DMA_DEV_W 2 /**< DMA direction, device write */ -#define METAL_DMA_DEV_WR 3 /**< DMA direction, device read/write */ - -/** - * @brief scatter/gather list element structure - */ -struct metal_sg { - void *virt; /**< CPU virtual address */ - struct metal_io_region *io; /**< IO region */ - int len; /**< length */ -}; - -struct metal_device; - -/** - * @brief Map memory for DMA transaction. - * After the memory is DMA mapped, the memory should be - * accessed by the DMA device but not the CPU. - * - * @param[in] dev DMA device - * @param[in] dir DMA direction - * @param[in] sg_in sg list of memory to map - * @param[in] nents_in number of sg list entries of memory to map - * @param[out] sg_out sg list of mapped memory - * @return number of mapped sg entries, -error on failure. - */ -int metal_dma_map(struct metal_device *dev, - uint32_t dir, - struct metal_sg *sg_in, - int nents_in, - struct metal_sg *sg_out); - -/** - * @brief Unmap DMA memory - * After the memory is DMA unmapped, the memory should - * be accessed by the CPU but not the DMA device. - * - * @param[in] dev DMA device - * @param[in] dir DMA direction - * @param[in] sg sg list of mapped DMA memory - * @param[in] nents number of sg list entries of DMA memory - */ -void metal_dma_unmap(struct metal_device *dev, - uint32_t dir, - struct metal_sg *sg, - int nents); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_DMA__H__ */ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file dma.h + * @brief DMA primitives for libmetal. + */ + +#ifndef __METAL_DMA__H__ +#define __METAL_DMA__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup dma DMA Interfaces + * @{ + */ + +#define METAL_DMA_DEV_R 1 /**< DMA direction, device read */ +#define METAL_DMA_DEV_W 2 /**< DMA direction, device write */ +#define METAL_DMA_DEV_WR 3 /**< DMA direction, device read/write */ + +/** + * @brief scatter/gather list element structure + */ +struct metal_sg { + void *virt; /**< CPU virtual address */ + struct metal_io_region *io; /**< IO region */ + int len; /**< length */ +}; + +struct metal_device; + +/** + * @brief Map memory for DMA transaction. + * After the memory is DMA mapped, the memory should be + * accessed by the DMA device but not the CPU. + * + * @param[in] dev DMA device + * @param[in] dir DMA direction + * @param[in] sg_in sg list of memory to map + * @param[in] nents_in number of sg list entries of memory to map + * @param[out] sg_out sg list of mapped memory + * @return number of mapped sg entries, -error on failure. + */ +int metal_dma_map(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg_in, + int nents_in, + struct metal_sg *sg_out); + +/** + * @brief Unmap DMA memory + * After the memory is DMA unmapped, the memory should + * be accessed by the CPU but not the DMA device. + * + * @param[in] dev DMA device + * @param[in] dir DMA direction + * @param[in] sg sg list of mapped DMA memory + * @param[in] nents number of sg list entries of DMA memory + */ +void metal_dma_unmap(struct metal_device *dev, + uint32_t dir, + struct metal_sg *sg, + int nents); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_DMA__H__ */ diff --git a/libraries/openamp_arduino/src/metal/errno.h b/libraries/openamp_arduino/src/metal/errno.h index 2f200e8..e84a2bc 100755 --- a/libraries/openamp_arduino/src/metal/errno.h +++ b/libraries/openamp_arduino/src/metal/errno.h @@ -1,24 +1,23 @@ -/* - * * Copyright (c) 2019 STMicrolectonics , Xilinx Inc. and Contributors. All rights reserved. - * * - * * SPDX-License-Identifier: BSD-3-Clause - * */ - -/* - * * @file metal/errno.h - * * @brief error specific primitives for libmetal. - * */ - -#ifndef __METAL_ERRNO__H__ -#define __METAL_ERRNO__H__ - -#if defined (__CC_ARM) -# include -#elif defined (__ICCARM__) -# include -#else -#include -#endif - -#endif /* __METAL_ERRNO__H__ */ - +/* + * Copyright (c) 2020 STMicroelectronnics. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file metal/errno.h + * @brief error specific primitives for libmetal. + */ + +#ifndef __METAL_ERRNO__H__ +#define __METAL_ERRNO__H__ + +#if defined(__ICCARM__) +# include +#elif defined(__CC_ARM) +# include +#else +# include +#endif + +#endif /* __METAL_ERRNO__H__ */ diff --git a/libraries/openamp_arduino/src/metal/io.h b/libraries/openamp_arduino/src/metal/io.h index 95512d8..e534d17 100755 --- a/libraries/openamp_arduino/src/metal/io.h +++ b/libraries/openamp_arduino/src/metal/io.h @@ -1,354 +1,374 @@ -/* - * Copyright (c) 2015 - 2017, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file io.h - * @brief I/O access primitives for libmetal. - */ - -#ifndef __METAL_IO__H__ -#define __METAL_IO__H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup io IO Interfaces - * @{ */ - -#ifdef __MICROBLAZE__ -#define NO_ATOMIC_64_SUPPORT -#endif - -struct metal_io_region; - -/** Generic I/O operations. */ -struct metal_io_ops { - uint64_t (*read)(struct metal_io_region *io, - unsigned long offset, - memory_order order, - int width); - void (*write)(struct metal_io_region *io, - unsigned long offset, - uint64_t value, - memory_order order, - int width); - int (*block_read)(struct metal_io_region *io, - unsigned long offset, - void *restrict dst, - memory_order order, - int len); - int (*block_write)(struct metal_io_region *io, - unsigned long offset, - const void *restrict src, - memory_order order, - int len); - void (*block_set)(struct metal_io_region *io, - unsigned long offset, - unsigned char value, - memory_order order, - int len); - void (*close)(struct metal_io_region *io); -}; - -/** Libmetal I/O region structure. */ -struct metal_io_region { - void *virt; /**< base virtual address */ - const metal_phys_addr_t *physmap; /**< table of base physical address - of each of the pages in the I/O - region */ - size_t size; /**< size of the I/O region */ - unsigned long page_shift; /**< page shift of I/O region */ - metal_phys_addr_t page_mask; /**< page mask of I/O region */ - unsigned int mem_flags; /**< memory attribute of the - I/O region */ - struct metal_io_ops ops; /**< I/O region operations */ -}; - -/** - * @brief Open a libmetal I/O region. - * - * @param[in, out] io I/O region handle. - * @param[in] virt Virtual address of region. - * @param[in] physmap Array of physical addresses per page. - * @param[in] size Size of region. - * @param[in] page_shift Log2 of page size (-1 for single page). - * @param[in] mem_flags Memory flags - * @param[in] ops ops - */ -void -metal_io_init(struct metal_io_region *io, void *virt, - const metal_phys_addr_t *physmap, size_t size, - unsigned page_shift, unsigned int mem_flags, - const struct metal_io_ops *ops); - -/** - * @brief Close a libmetal shared memory segment. - * @param[in] io I/O region handle. - */ -static inline void metal_io_finish(struct metal_io_region *io) -{ - if (io->ops.close) - (*io->ops.close)(io); - memset(io, 0, sizeof(*io)); -} - -/** - * @brief Get size of I/O region. - * - * @param[in] io I/O region handle. - * @return Size of I/O region. - */ -static inline size_t metal_io_region_size(struct metal_io_region *io) -{ - return io->size; -} - -/** - * @brief Get virtual address for a given offset into the I/O region. - * @param[in] io I/O region handle. - * @param[in] offset Offset into shared memory segment. - * @return NULL if offset is out of range, or pointer to offset. - */ -static inline void * -metal_io_virt(struct metal_io_region *io, unsigned long offset) -{ - return (io->virt != METAL_BAD_VA && offset <= io->size - ? (uint8_t *)io->virt + offset - : NULL); -} - -/** - * @brief Convert a virtual address to offset within I/O region. - * @param[in] io I/O region handle. - * @param[in] virt Virtual address within segment. - * @return METAL_BAD_OFFSET if out of range, or offset. - */ -static inline unsigned long -metal_io_virt_to_offset(struct metal_io_region *io, void *virt) -{ - size_t offset = (uint8_t *)virt - (uint8_t *)io->virt; - return (offset < io->size ? offset : METAL_BAD_OFFSET); -} - -/** - * @brief Get physical address for a given offset into the I/O region. - * @param[in] io I/O region handle. - * @param[in] offset Offset into shared memory segment. - * @return METAL_BAD_PHYS if offset is out of range, or physical address - * of offset. - */ -static inline metal_phys_addr_t -metal_io_phys(struct metal_io_region *io, unsigned long offset) -{ - unsigned long page = (io->page_shift >= - sizeof(offset) * CHAR_BIT ? - 0 : offset >> io->page_shift); - return (io->physmap != NULL && offset <= io->size - ? io->physmap[page] + (offset & io->page_mask) - : METAL_BAD_PHYS); -} - -/** - * @brief Convert a physical address to offset within I/O region. - * @param[in] io I/O region handle. - * @param[in] phys Physical address within segment. - * @return METAL_BAD_OFFSET if out of range, or offset. - */ -static inline unsigned long -metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys) -{ - unsigned long offset = - (io->page_mask == (metal_phys_addr_t)(-1) ? - phys - io->physmap[0] : phys & io->page_mask); - do { - if (metal_io_phys(io, offset) == phys) - return offset; - offset += io->page_mask + 1; - } while (offset < io->size); - return METAL_BAD_OFFSET; -} - -/** - * @brief Convert a physical address to virtual address. - * @param[in] io Shared memory segment handle. - * @param[in] phys Physical address within segment. - * @return NULL if out of range, or corresponding virtual address. - */ -static inline void * -metal_io_phys_to_virt(struct metal_io_region *io, metal_phys_addr_t phys) -{ - return metal_io_virt(io, metal_io_phys_to_offset(io, phys)); -} - -/** - * @brief Convert a virtual address to physical address. - * @param[in] io Shared memory segment handle. - * @param[in] virt Virtual address within segment. - * @return METAL_BAD_PHYS if out of range, or corresponding - * physical address. - */ -static inline metal_phys_addr_t -metal_io_virt_to_phys(struct metal_io_region *io, void *virt) -{ - return metal_io_phys(io, metal_io_virt_to_offset(io, virt)); -} - -/** - * @brief Read a value from an I/O region. - * @param[in] io I/O region handle. - * @param[in] offset Offset into I/O region. - * @param[in] order Memory ordering. - * @param[in] width Width in bytes of datatype to read. This must be 1, 2, - * 4, or 8, and a compile time constant for this function - * to inline cleanly. - * @return Value. - */ -static inline uint64_t -metal_io_read(struct metal_io_region *io, unsigned long offset, - memory_order order, int width) -{ - void *ptr = metal_io_virt(io, offset); - - if (io->ops.read) - return (*io->ops.read)(io, offset, order, width); - else if (ptr && sizeof(atomic_uchar) == width) - return atomic_load_explicit((atomic_uchar *)ptr, order); - else if (ptr && sizeof(atomic_ushort) == width) - return atomic_load_explicit((atomic_ushort *)ptr, order); - else if (ptr && sizeof(atomic_uint) == width) - return atomic_load_explicit((atomic_uint *)ptr, order); - else if (ptr && sizeof(atomic_ulong) == width) - return atomic_load_explicit((atomic_ulong *)ptr, order); -#ifndef NO_ATOMIC_64_SUPPORT - else if (ptr && sizeof(atomic_ullong) == width) - return atomic_load_explicit((atomic_ullong *)ptr, order); -#endif - metal_assert(0); - return 0; /* quiet compiler */ -} - -/** - * @brief Write a value into an I/O region. - * @param[in] io I/O region handle. - * @param[in] offset Offset into I/O region. - * @param[in] value Value to write. - * @param[in] order Memory ordering. - * @param[in] width Width in bytes of datatype to read. This must be 1, 2, - * 4, or 8, and a compile time constant for this function - * to inline cleanly. - */ -static inline void -metal_io_write(struct metal_io_region *io, unsigned long offset, - uint64_t value, memory_order order, int width) -{ - void *ptr = metal_io_virt(io, offset); - if (io->ops.write) - (*io->ops.write)(io, offset, value, order, width); - else if (ptr && sizeof(atomic_uchar) == width) - atomic_store_explicit((atomic_uchar *)ptr, value, order); - else if (ptr && sizeof(atomic_ushort) == width) - atomic_store_explicit((atomic_ushort *)ptr, value, order); - else if (ptr && sizeof(atomic_uint) == width) - atomic_store_explicit((atomic_uint *)ptr, value, order); - else if (ptr && sizeof(atomic_ulong) == width) - atomic_store_explicit((atomic_ulong *)ptr, value, order); -#ifndef NO_ATOMIC_64_SUPPORT - else if (ptr && sizeof(atomic_ullong) == width) - atomic_store_explicit((atomic_ullong *)ptr, value, order); -#endif - else - metal_assert (0); -} - -#define metal_io_read8_explicit(_io, _ofs, _order) \ - metal_io_read((_io), (_ofs), (_order), 1) -#define metal_io_read8(_io, _ofs) \ - metal_io_read((_io), (_ofs), memory_order_seq_cst, 1) -#define metal_io_write8_explicit(_io, _ofs, _val, _order) \ - metal_io_write((_io), (_ofs), (_val), (_order), 1) -#define metal_io_write8(_io, _ofs, _val) \ - metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1) - -#define metal_io_read16_explicit(_io, _ofs, _order) \ - metal_io_read((_io), (_ofs), (_order), 2) -#define metal_io_read16(_io, _ofs) \ - metal_io_read((_io), (_ofs), memory_order_seq_cst, 2) -#define metal_io_write16_explicit(_io, _ofs, _val, _order) \ - metal_io_write((_io), (_ofs), (_val), (_order), 2) -#define metal_io_write16(_io, _ofs, _val) \ - metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2) - -#define metal_io_read32_explicit(_io, _ofs, _order) \ - metal_io_read((_io), (_ofs), (_order), 4) -#define metal_io_read32(_io, _ofs) \ - metal_io_read((_io), (_ofs), memory_order_seq_cst, 4) -#define metal_io_write32_explicit(_io, _ofs, _val, _order) \ - metal_io_write((_io), (_ofs), (_val), (_order), 4) -#define metal_io_write32(_io, _ofs, _val) \ - metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4) - -#define metal_io_read64_explicit(_io, _ofs, _order) \ - metal_io_read((_io), (_ofs), (_order), 8) -#define metal_io_read64(_io, _ofs) \ - metal_io_read((_io), (_ofs), memory_order_seq_cst, 8) -#define metal_io_write64_explicit(_io, _ofs, _val, _order) \ - metal_io_write((_io), (_ofs), (_val), (_order), 8) -#define metal_io_write64(_io, _ofs, _val) \ - metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8) - -/** - * @brief Read a block from an I/O region. - * @param[in] io I/O region handle. - * @param[in] offset Offset into I/O region. - * @param[in] dst destination to store the read data. - * @param[in] len length in bytes to read. - * @return On success, number of bytes read. On failure, negative value - */ -int metal_io_block_read(struct metal_io_region *io, unsigned long offset, - void *restrict dst, int len); - -/** - * @brief Write a block into an I/O region. - * @param[in] io I/O region handle. - * @param[in] offset Offset into I/O region. - * @param[in] src source to write. - * @param[in] len length in bytes to write. - * @return On success, number of bytes written. On failure, negative value - */ -int metal_io_block_write(struct metal_io_region *io, unsigned long offset, - const void *restrict src, int len); - -/** - * @brief fill a block of an I/O region. - * @param[in] io I/O region handle. - * @param[in] offset Offset into I/O region. - * @param[in] value value to fill into the block - * @param[in] len length in bytes to fill. - * @return On success, number of bytes filled. On failure, negative value - */ -int metal_io_block_set(struct metal_io_region *io, unsigned long offset, - unsigned char value, int len); - -#include - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_IO__H__ */ +/* + * Copyright (c) 2015 - 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file io.h + * @brief I/O access primitives for libmetal. + */ + +#ifndef __METAL_IO__H__ +#define __METAL_IO__H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup io IO Interfaces + * @{ + */ + +#ifdef __MICROBLAZE__ +#define NO_ATOMIC_64_SUPPORT +#endif + +struct metal_io_region; + +/** Generic I/O operations. */ +struct metal_io_ops { + uint64_t (*read)(struct metal_io_region *io, + unsigned long offset, + memory_order order, + int width); + void (*write)(struct metal_io_region *io, + unsigned long offset, + uint64_t value, + memory_order order, + int width); + int (*block_read)(struct metal_io_region *io, + unsigned long offset, + void *restrict dst, + memory_order order, + int len); + int (*block_write)(struct metal_io_region *io, + unsigned long offset, + const void *restrict src, + memory_order order, + int len); + void (*block_set)(struct metal_io_region *io, + unsigned long offset, + unsigned char value, + memory_order order, + int len); + void (*close)(struct metal_io_region *io); + metal_phys_addr_t (*offset_to_phys)(struct metal_io_region *io, + unsigned long offset); + unsigned long (*phys_to_offset)(struct metal_io_region *io, + metal_phys_addr_t phys); +}; + +/** Libmetal I/O region structure. */ +struct metal_io_region { + void *virt; /**< base virtual address */ + const metal_phys_addr_t *physmap; /**< table of base physical address + of each of the pages in the I/O + region */ + size_t size; /**< size of the I/O region */ + unsigned long page_shift; /**< page shift of I/O region */ + metal_phys_addr_t page_mask; /**< page mask of I/O region */ + unsigned int mem_flags; /**< memory attribute of the + I/O region */ + struct metal_io_ops ops; /**< I/O region operations */ +}; + +/** + * @brief Open a libmetal I/O region. + * + * @param[in, out] io I/O region handle. + * @param[in] virt Virtual address of region. + * @param[in] physmap Array of physical addresses per page. + * @param[in] size Size of region. + * @param[in] page_shift Log2 of page size (-1 for single page). + * @param[in] mem_flags Memory flags + * @param[in] ops ops + */ +void +metal_io_init(struct metal_io_region *io, void *virt, + const metal_phys_addr_t *physmap, size_t size, + unsigned int page_shift, unsigned int mem_flags, + const struct metal_io_ops *ops); + +/** + * @brief Close a libmetal shared memory segment. + * @param[in] io I/O region handle. + */ +static inline void metal_io_finish(struct metal_io_region *io) +{ + if (io->ops.close) + (*io->ops.close)(io); + memset(io, 0, sizeof(*io)); +} + +/** + * @brief Get size of I/O region. + * + * @param[in] io I/O region handle. + * @return Size of I/O region. + */ +static inline size_t metal_io_region_size(struct metal_io_region *io) +{ + return io->size; +} + +/** + * @brief Get virtual address for a given offset into the I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into shared memory segment. + * @return NULL if offset is out of range, or pointer to offset. + */ +static inline void * +metal_io_virt(struct metal_io_region *io, unsigned long offset) +{ + return (io->virt != METAL_BAD_VA && offset < io->size + ? (void *)((uintptr_t)io->virt + offset) + : NULL); +} + +/** + * @brief Convert a virtual address to offset within I/O region. + * @param[in] io I/O region handle. + * @param[in] virt Virtual address within segment. + * @return METAL_BAD_OFFSET if out of range, or offset. + */ +static inline unsigned long +metal_io_virt_to_offset(struct metal_io_region *io, void *virt) +{ + size_t offset = (uintptr_t)virt - (uintptr_t)io->virt; + + return (offset < io->size ? offset : METAL_BAD_OFFSET); +} + +/** + * @brief Get physical address for a given offset into the I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into shared memory segment. + * @return METAL_BAD_PHYS if offset is out of range, or physical address + * of offset. + */ +static inline metal_phys_addr_t +metal_io_phys(struct metal_io_region *io, unsigned long offset) +{ + if (!io->ops.offset_to_phys) { + unsigned long page = (io->page_shift >= + sizeof(offset) * CHAR_BIT ? + 0 : offset >> io->page_shift); + return (io->physmap && offset < io->size + ? io->physmap[page] + (offset & io->page_mask) + : METAL_BAD_PHYS); + } + + return io->ops.offset_to_phys(io, offset); +} + +/** + * @brief Convert a physical address to offset within I/O region. + * @param[in] io I/O region handle. + * @param[in] phys Physical address within segment. + * @return METAL_BAD_OFFSET if out of range, or offset. + */ +static inline unsigned long +metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys) +{ + if (!io->ops.phys_to_offset) { + unsigned long offset = + (io->page_mask == (metal_phys_addr_t)(-1) ? + phys - io->physmap[0] : phys & io->page_mask); + do { + if (metal_io_phys(io, offset) == phys) + return offset; + offset += io->page_mask + 1; + } while (offset < io->size); + return METAL_BAD_OFFSET; + } + + return (*io->ops.phys_to_offset)(io, phys); +} + +/** + * @brief Convert a physical address to virtual address. + * @param[in] io Shared memory segment handle. + * @param[in] phys Physical address within segment. + * @return NULL if out of range, or corresponding virtual address. + */ +static inline void * +metal_io_phys_to_virt(struct metal_io_region *io, metal_phys_addr_t phys) +{ + return metal_io_virt(io, metal_io_phys_to_offset(io, phys)); +} + +/** + * @brief Convert a virtual address to physical address. + * @param[in] io Shared memory segment handle. + * @param[in] virt Virtual address within segment. + * @return METAL_BAD_PHYS if out of range, or corresponding + * physical address. + */ +static inline metal_phys_addr_t +metal_io_virt_to_phys(struct metal_io_region *io, void *virt) +{ + return metal_io_phys(io, metal_io_virt_to_offset(io, virt)); +} + +/** + * @brief Read a value from an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] order Memory ordering. + * @param[in] width Width in bytes of datatype to read. This must be 1, 2, + * 4, or 8, and a compile time constant for this function + * to inline cleanly. + * @return Value. + */ +static inline uint64_t +metal_io_read(struct metal_io_region *io, unsigned long offset, + memory_order order, int width) +{ + void *ptr = metal_io_virt(io, offset); + + if (io->ops.read) + return (*io->ops.read)(io, offset, order, width); + else if (ptr && sizeof(atomic_uchar) == width) + return atomic_load_explicit((atomic_uchar *)ptr, order); + else if (ptr && sizeof(atomic_ushort) == width) + return atomic_load_explicit((atomic_ushort *)ptr, order); + else if (ptr && sizeof(atomic_uint) == width) + return atomic_load_explicit((atomic_uint *)ptr, order); + else if (ptr && sizeof(atomic_ulong) == width) + return atomic_load_explicit((atomic_ulong *)ptr, order); +#ifndef NO_ATOMIC_64_SUPPORT + else if (ptr && sizeof(atomic_ullong) == width) + return atomic_load_explicit((atomic_ullong *)ptr, order); +#endif + metal_assert(0); + return 0; /* quiet compiler */ +} + +/** + * @brief Write a value into an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] value Value to write. + * @param[in] order Memory ordering. + * @param[in] width Width in bytes of datatype to read. This must be 1, 2, + * 4, or 8, and a compile time constant for this function + * to inline cleanly. + */ +static inline void +metal_io_write(struct metal_io_region *io, unsigned long offset, + uint64_t value, memory_order order, int width) +{ + void *ptr = metal_io_virt(io, offset); + + if (io->ops.write) + (*io->ops.write)(io, offset, value, order, width); + else if (ptr && sizeof(atomic_uchar) == width) + atomic_store_explicit((atomic_uchar *)ptr, (unsigned char)value, + order); + else if (ptr && sizeof(atomic_ushort) == width) + atomic_store_explicit((atomic_ushort *)ptr, + (unsigned short)value, order); + else if (ptr && sizeof(atomic_uint) == width) + atomic_store_explicit((atomic_uint *)ptr, (unsigned int)value, + order); + else if (ptr && sizeof(atomic_ulong) == width) + atomic_store_explicit((atomic_ulong *)ptr, (unsigned long)value, + order); +#ifndef NO_ATOMIC_64_SUPPORT + else if (ptr && sizeof(atomic_ullong) == width) + atomic_store_explicit((atomic_ullong *)ptr, + (unsigned long long)value, order); +#endif + else + metal_assert(0); +} + +#define metal_io_read8_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 1) +#define metal_io_read8(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 1) +#define metal_io_write8_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 1) +#define metal_io_write8(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1) + +#define metal_io_read16_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 2) +#define metal_io_read16(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 2) +#define metal_io_write16_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 2) +#define metal_io_write16(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2) + +#define metal_io_read32_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 4) +#define metal_io_read32(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 4) +#define metal_io_write32_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 4) +#define metal_io_write32(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4) + +#define metal_io_read64_explicit(_io, _ofs, _order) \ + metal_io_read((_io), (_ofs), (_order), 8) +#define metal_io_read64(_io, _ofs) \ + metal_io_read((_io), (_ofs), memory_order_seq_cst, 8) +#define metal_io_write64_explicit(_io, _ofs, _val, _order) \ + metal_io_write((_io), (_ofs), (_val), (_order), 8) +#define metal_io_write64(_io, _ofs, _val) \ + metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8) + +/** + * @brief Read a block from an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] dst destination to store the read data. + * @param[in] len length in bytes to read. + * @return On success, number of bytes read. On failure, negative value + */ +int metal_io_block_read(struct metal_io_region *io, unsigned long offset, + void *restrict dst, int len); + +/** + * @brief Write a block into an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] src source to write. + * @param[in] len length in bytes to write. + * @return On success, number of bytes written. On failure, negative value + */ +int metal_io_block_write(struct metal_io_region *io, unsigned long offset, + const void *restrict src, int len); + +/** + * @brief fill a block of an I/O region. + * @param[in] io I/O region handle. + * @param[in] offset Offset into I/O region. + * @param[in] value value to fill into the block + * @param[in] len length in bytes to fill. + * @return On success, number of bytes filled. On failure, negative value + */ +int metal_io_block_set(struct metal_io_region *io, unsigned long offset, + unsigned char value, int len); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* __METAL_IO__H__ */ diff --git a/libraries/openamp_arduino/src/metal/irq.h b/libraries/openamp_arduino/src/metal/irq.h index 9f0344e..43562ab 100755 --- a/libraries/openamp_arduino/src/metal/irq.h +++ b/libraries/openamp_arduino/src/metal/irq.h @@ -1,116 +1,104 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file irq.h - * @brief Interrupt handling primitives for libmetal. - */ - -#ifndef __METAL_IRQ__H__ -#define __METAL_IRQ__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup irq Interrupt Handling Interfaces - * @{ */ - -#include - -/** IRQ handled status */ -#define METAL_IRQ_NOT_HANDLED 0 -#define METAL_IRQ_HANDLED 1 - -/** - * @brief type of interrupt handler - * @param[in] irq interrupt id - * @param[in] priv private data - * @return irq handled status - */ -typedef int (*metal_irq_handler) (int irq, void *priv); - -struct metal_device; - -/** - * @brief Register interrupt handler for driver ID/device. - * - * @param[in] irq interrupt id - * @param[in] irq_handler interrupt handler - * @param[in] dev metal device this irq belongs to (can be NULL). - * @param[in] drv_id driver id is a unique interrupt handler identifier. - * It can also be used for driver data. - * @return 0 for success, non-zero on failure - */ -int metal_irq_register(int irq, - metal_irq_handler irq_handler, - struct metal_device *dev, - void *drv_id); - -/** - * @brief Unregister interrupt handler for driver ID and/or device. - * - * If interrupt handler (hd), driver ID (drv_id) and device (dev) - * are NULL, unregister all handlers for this interrupt. - * - * If interrupt handler (hd), device (dev) or driver ID (drv_id), - * are not NULL, unregister handlers matching non NULL criterias. - * e.g: when call is made with drv_id and dev non NULL, - * all handlers matching both are unregistered. - * - * If interrupt is not found, or other criterias not matching, - * return -ENOENT - * - * @param[in] irq interrupt id - * @param[in] irq_handler interrupt handler - * @param[in] dev metal device this irq belongs to - * @param[in] drv_id driver id. It can be used for driver data. - * @return 0 for success, non-zero on failure - */ -int metal_irq_unregister(int irq, - metal_irq_handler irq_handler, - struct metal_device *dev, - void *drv_id); - -/** - * @brief disable interrupts - * @return interrupts state - */ -unsigned int metal_irq_save_disable(void); - -/** - * @brief restore interrupts to their previous state - * @param[in] flags previous interrupts state - */ -void metal_irq_restore_enable(unsigned int flags); - -/** - * @brief metal_irq_enable - * - * Enables the given interrupt - * - * @param vector - interrupt vector number - */ -void metal_irq_enable(unsigned int vector); - -/** - * @brief metal_irq_disable - * - * Disables the given interrupt - * - * @param vector - interrupt vector number - */ -void metal_irq_disable(unsigned int vector); - -#include - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_IRQ__H__ */ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file irq.h + * @brief Interrupt handling primitives for libmetal. + */ + +#ifndef __METAL_IRQ__H__ +#define __METAL_IRQ__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup irq Interrupt Handling Interfaces + * @{ + */ + +/** IRQ handled status */ +#define METAL_IRQ_NOT_HANDLED 0 +#define METAL_IRQ_HANDLED 1 + +/** + * @brief type of interrupt handler + * @param[in] irq interrupt id + * @param[in] arg argument to pass to the handler + * @return irq handled status + */ +typedef int (*metal_irq_handler) (int irq, void *arg); + +/** + * @brief Register interrupt handler for interrupt. + * Only allow single interrupt handler for a interrupt. + * + * If irq_handler is NULL, it will unregister interrupt + * handler from interrupt + * + * @param[in] irq interrupt id + * @param[in] irq_handler interrupt handler + * @param[in] arg arg is the argument pointing to the data which + * will be passed to the interrupt handler. + * @return 0 for success, non-zero on failure + */ +int metal_irq_register(int irq, + metal_irq_handler irq_handler, + void *arg); + +/** + * @brief Unregister interrupt handler for interrupt. + * + * @param[in] irq interrupt id + */ +static inline +void metal_irq_unregister(int irq) +{ + metal_irq_register(irq, 0, NULL); +} + +/** + * @brief disable interrupts + * @return interrupts state + */ +unsigned int metal_irq_save_disable(void); + +/** + * @brief restore interrupts to their previous state + * @param[in] flags previous interrupts state + */ +void metal_irq_restore_enable(unsigned int flags); + +/** + * @brief metal_irq_enable + * + * Enables the given interrupt + * + * @param vector - interrupt vector number + */ +void metal_irq_enable(unsigned int vector); + +/** + * @brief metal_irq_disable + * + * Disables the given interrupt + * + * @param vector - interrupt vector number + */ +void metal_irq_disable(unsigned int vector); + +#include + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_IRQ__H__ */ diff --git a/libraries/openamp_arduino/src/metal/irq_controller.h b/libraries/openamp_arduino/src/metal/irq_controller.h new file mode 100644 index 0000000..c821ef4 --- /dev/null +++ b/libraries/openamp_arduino/src/metal/irq_controller.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file irq.h + * @brief Interrupt handling primitives for libmetal. + */ + +#ifndef __METAL_IRQ_CONTROLLER__H__ +#define __METAL_IRQ_CONTROLLER__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup irq Interrupt Handling Interfaces + * @{ + */ + +#include +#include +#include + +/** IRQ ANY ID */ +#define METAL_IRQ_ANY (-1) + +/** IRQ state macro which will be passed to metal irq set state function + * to indicate which state the caller want the IRQ to change to. + */ +#define METAL_IRQ_DISABLE 0U +#define METAL_IRQ_ENABLE 1U + +struct metal_irq_controller; + +/** + * @brief type of interrupt controller to set irq enable + * @param[in] irq_cntr pointer to interrupt controller + * @param[in] irq interrupt id + * @param[in] enable IRQ state + */ +typedef void (*metal_irq_set_enable) (struct metal_irq_controller *irq_cntr, + int irq, unsigned int enable); + +/** + * @brief type of controller specific registering interrupt function + * @param[in] irq_cntr pointer to interrupt controller + * @param[in] irq interrupt id + * @param[in] hd interrupt handler + * @param[in] arg argument which will be passed to the interrupt handler + * @return 0 for success, negative value for failure + */ +typedef int (*metal_cntr_irq_register) (struct metal_irq_controller *irq_cntr, + int irq, metal_irq_handler hd, + void *arg); + +/** Libmetal interrupt structure */ +struct metal_irq { + metal_irq_handler hd; /**< Interrupt handler */ + void *arg; /**< Argument to pass to the interrupt handler */ +}; + +/** Libmetal interrupt controller structure */ +struct metal_irq_controller { + int irq_base; /**< Start of IRQ number of the range managed by + * the IRQ controller + */ + int irq_num; /**< Number of IRQs managed by the IRQ controller */ + void *arg; /**< Argument to pass to interrupt controller function */ + metal_irq_set_enable irq_set_enable; /**< function to set IRQ enable */ + metal_cntr_irq_register irq_register; /**< function to register IRQ + * handler + */ + struct metal_list node; /**< list node */ + struct metal_irq *irqs; /**< Array of IRQs managed by the controller */ +}; + +#define METAL_IRQ_CONTROLLER_DECLARE(_irq_controller, \ + _irq_base, _irq_num, \ + _arg, \ + _irq_set_enable, \ + _irq_register, \ + _irqs) \ + struct metal_irq_controller _irq_controller = { \ + .irq_base = _irq_base, \ + .irq_num = _irq_num, \ + .arg = _arg, \ + .irq_set_enable = _irq_set_enable, \ + .irq_register = _irq_register, \ + .irqs = _irqs,\ + } + +/** + * @brief metal_irq_register_controller + * + * Register IRQ controller + * This function will allocate IRQ ids if it was + * not predefined in the irq controller. There is no + * locking in the function, it is not supposed to be + * called by multiple threads. + * + * @param[in] cntr Interrupt controller to register + * @return 0 on success, or negative value for failure. + */ +int metal_irq_register_controller(struct metal_irq_controller *cntr); + +/** + * @brief metal_irq_handle + * + * Call registered IRQ handler + * + * @param[in] irq_data metal IRQ structure + * @param[in] irq IRQ id which will be passed to handler + * @return IRQ handler status + */ +static inline +int metal_irq_handle(struct metal_irq *irq_data, int irq) +{ + if (irq_data && irq_data->hd) { + return irq_data->hd(irq, irq_data->arg); + } else { + return METAL_IRQ_NOT_HANDLED; + } +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_IRQ__H__ */ diff --git a/libraries/openamp_arduino/src/metal/list.h b/libraries/openamp_arduino/src/metal/list.h index a9395ba..eb0e7b3 100755 --- a/libraries/openamp_arduino/src/metal/list.h +++ b/libraries/openamp_arduino/src/metal/list.h @@ -1,102 +1,118 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file list.h - * @brief List primitives for libmetal. - */ - -#ifndef __METAL_LIST__H__ -#define __METAL_LIST__H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup list List Primitives - * @{ */ - -struct metal_list { - struct metal_list *next, *prev; -}; - -/* - * METAL_INIT_LIST - used for initializing an list elmenet in a static struct - * or global - */ -#define METAL_INIT_LIST(name) { .next = &name, .prev = &name } -/* - * METAL_DECLARE_LIST - used for defining and initializing a global or - * static singleton list - */ -#define METAL_DECLARE_LIST(name) \ - struct metal_list name = METAL_INIT_LIST(name) - -static inline void metal_list_init(struct metal_list *list) -{ - list->next = list->prev = list; -} - -static inline void metal_list_add_before(struct metal_list *node, - struct metal_list *new_node) -{ - new_node->prev = node->prev; - new_node->next = node; - new_node->next->prev = new_node; - new_node->prev->next = new_node; -} - -static inline void metal_list_add_after(struct metal_list *node, - struct metal_list *new_node) -{ - new_node->prev = node; - new_node->next = node->next; - new_node->next->prev = new_node; - new_node->prev->next = new_node; -} - -static inline void metal_list_add_head(struct metal_list *list, - struct metal_list *node) -{ - metal_list_add_after(list, node); -} - -static inline void metal_list_add_tail(struct metal_list *list, - struct metal_list *node) -{ - metal_list_add_before(list, node); -} - -static inline int metal_list_is_empty(struct metal_list *list) -{ - return list->next == list; -} - -static inline void metal_list_del(struct metal_list *node) -{ - node->next->prev = node->prev; - node->prev->next = node->next; - node->next = node->prev = node; -} - -static inline struct metal_list *metal_list_first(struct metal_list *list) -{ - return metal_list_is_empty(list) ? NULL : list->next; -} - -#define metal_list_for_each(list, node) \ - for ((node) = (list)->next; \ - (node) != (list); \ - (node) = (node)->next) -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_LIST__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file list.h + * @brief List primitives for libmetal. + */ + +#ifndef __METAL_LIST__H__ +#define __METAL_LIST__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup list List Primitives + * @{ + */ + +struct metal_list { + struct metal_list *next, *prev; +}; + +/* + * METAL_INIT_LIST - used for initializing an list element in a static struct + * or global + */ +#define METAL_INIT_LIST(name) { .next = &name, .prev = &name } +/* + * METAL_DECLARE_LIST - used for defining and initializing a global or + * static singleton list + */ +#define METAL_DECLARE_LIST(name) \ + struct metal_list name = METAL_INIT_LIST(name) + +static inline void metal_list_init(struct metal_list *list) +{ + list->prev = list; + list->next = list; +} + +static inline void metal_list_add_before(struct metal_list *node, + struct metal_list *new_node) +{ + new_node->prev = node->prev; + new_node->next = node; + new_node->next->prev = new_node; + new_node->prev->next = new_node; +} + +static inline void metal_list_add_after(struct metal_list *node, + struct metal_list *new_node) +{ + new_node->prev = node; + new_node->next = node->next; + new_node->next->prev = new_node; + new_node->prev->next = new_node; +} + +static inline void metal_list_add_head(struct metal_list *list, + struct metal_list *node) +{ + metal_list_add_after(list, node); +} + +static inline void metal_list_add_tail(struct metal_list *list, + struct metal_list *node) +{ + metal_list_add_before(list, node); +} + +static inline int metal_list_is_empty(struct metal_list *list) +{ + return list->next == list; +} + +static inline void metal_list_del(struct metal_list *node) +{ + node->next->prev = node->prev; + node->prev->next = node->next; + node->prev = node; + node->next = node; +} + +static inline struct metal_list *metal_list_first(struct metal_list *list) +{ + return metal_list_is_empty(list) ? NULL : list->next; +} + +#define metal_list_for_each(list, node) \ + for ((node) = (list)->next; \ + (node) != (list); \ + (node) = (node)->next) + +static inline bool metal_list_find_node(struct metal_list *list, + struct metal_list *node) +{ + struct metal_list *n; + + metal_list_for_each(list, n) { + if (n == node) + return true; + } + return false; +} +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_LIST__H__ */ diff --git a/libraries/openamp_arduino/src/metal/log.h b/libraries/openamp_arduino/src/metal/log.h index d439ef8..528e4c6 100755 --- a/libraries/openamp_arduino/src/metal/log.h +++ b/libraries/openamp_arduino/src/metal/log.h @@ -1,93 +1,116 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file log.h - * @brief Logging support for libmetal. - */ - -#ifndef __METAL_METAL_LOG__H__ -#define __METAL_METAL_LOG__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup logging Library Logging Interfaces - * @{ */ - -/** Log message priority levels for libmetal. */ -enum metal_log_level { - METAL_LOG_EMERGENCY, /**< system is unusable. */ - METAL_LOG_ALERT, /**< action must be taken immediately. */ - METAL_LOG_CRITICAL, /**< critical conditions. */ - METAL_LOG_ERROR, /**< error conditions. */ - METAL_LOG_WARNING, /**< warning conditions. */ - METAL_LOG_NOTICE, /**< normal but significant condition. */ - METAL_LOG_INFO, /**< informational messages. */ - METAL_LOG_DEBUG, /**< debug-level messages. */ -}; - -/** Log message handler type. */ -typedef void (*metal_log_handler)(enum metal_log_level level, - const char *format, ...); - -/** - * @brief Set libmetal log handler. - * @param[in] handler log message handler. - * @return 0 on success, or -errno on failure. - */ -extern void metal_set_log_handler(metal_log_handler handler); - -/** - * @brief Get the current libmetal log handler. - * @return Current log handler. - */ -extern metal_log_handler metal_get_log_handler(void); - -/** - * @brief Set the level for libmetal logging. - * @param[in] level log message level. - */ -extern void metal_set_log_level(enum metal_log_level level); - -/** - * @brief Get the current level for libmetal logging. - * @return Current log level. - */ -extern enum metal_log_level metal_get_log_level(void); - -/** - * @brief Default libmetal log handler. This handler prints libmetal log - * mesages to stderr. - * @param[in] level log message level. - * @param[in] format log message format string. - * @return 0 on success, or -errno on failure. - */ -extern void metal_default_log_handler(enum metal_log_level level, - const char *format, ...); - - -/** - * Emit a log message if the log level permits. - * - * @param level Log level. - * @param ... Format string and arguments. - */ -#define metal_log(level, ...) \ - ((level <= _metal.common.log_level && _metal.common.log_handler) \ - ? (void)_metal.common.log_handler(level, __VA_ARGS__) \ - : (void)0) - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#include - -#endif /* __METAL_METAL_LOG__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file log.h + * @brief Logging support for libmetal. + */ + +#ifndef __METAL_METAL_LOG__H__ +#define __METAL_METAL_LOG__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup logging Library Logging Interfaces + * @{ + */ + +/** Log message priority levels for libmetal. */ +enum metal_log_level { + METAL_LOG_EMERGENCY, /**< system is unusable. */ + METAL_LOG_ALERT, /**< action must be taken immediately. */ + METAL_LOG_CRITICAL, /**< critical conditions. */ + METAL_LOG_ERROR, /**< error conditions. */ + METAL_LOG_WARNING, /**< warning conditions. */ + METAL_LOG_NOTICE, /**< normal but significant condition. */ + METAL_LOG_INFO, /**< informational messages. */ + METAL_LOG_DEBUG, /**< debug-level messages. */ +}; + +/** Log message handler type. */ +typedef void (*metal_log_handler)(enum metal_log_level level, + const char *format, ...); + +/** + * @brief Set libmetal log handler. + * @param[in] handler log message handler. + * @return 0 on success, or -errno on failure. + */ +extern void metal_set_log_handler(metal_log_handler handler); + +/** + * @brief Get the current libmetal log handler. + * @return Current log handler. + */ +extern metal_log_handler metal_get_log_handler(void); + +/** + * @brief Set the level for libmetal logging. + * @param[in] level log message level. + */ +extern void metal_set_log_level(enum metal_log_level level); + +/** + * @brief Get the current level for libmetal logging. + * @return Current log level. + */ +extern enum metal_log_level metal_get_log_level(void); + +/** + * @brief Default libmetal log handler. This handler prints libmetal log + * messages to stderr. + * @param[in] level log message level. + * @param[in] format log message format string. + * @return 0 on success, or -errno on failure. + */ +extern void metal_default_log_handler(enum metal_log_level level, + const char *format, ...); + +/** + * @internal + * + * @brief used by the metal_log() macro to update the format string + * + * If ML_FUNC_LINE is defined this macro generates a unified format + * string for metal_log() and its convenience metal_*() macros, i.e. it + * adds function-name:line-number prefix to all log messages. + * + * @param[in] fmt format string passed from the metal_log() macro + */ +#if defined(ML_FUNC_LINE) +#define metal_fmt(fmt) "%s:%u " fmt, __func__, __LINE__ +#else /* ML_FUNC_LINE */ +#define metal_fmt(fmt) fmt +#endif /* ML_FUNC_LINE */ + +/** + * @brief Emit a log message if the log level permits. + * + * @param level Log level. + * @param fmt Format string. + * @param args... Variable number of arguments. + */ +#define metal_log(level, fmt, args...) ({ \ + if (_metal.common.log_handler && level <= _metal.common.log_level) \ + _metal.common.log_handler(level, metal_fmt(fmt), ##args); \ +}) + +#define metal_err(fmt, args...) metal_log(METAL_LOG_ERROR, fmt, ##args) +#define metal_warn(fmt, args...) metal_log(METAL_LOG_WARNING, fmt, ##args) +#define metal_info(fmt, args...) metal_log(METAL_LOG_INFO, fmt, ##args) +#define metal_dbg(fmt, args...) metal_log(METAL_LOG_DEBUG, fmt, ##args) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* __METAL_METAL_LOG__H__ */ diff --git a/libraries/openamp_arduino/src/metal/mutex.h b/libraries/openamp_arduino/src/metal/mutex.h index c241bd0..71d9eaa 100755 --- a/libraries/openamp_arduino/src/metal/mutex.h +++ b/libraries/openamp_arduino/src/metal/mutex.h @@ -1,87 +1,88 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file mutex.h - * @brief Mutex primitives for libmetal. - */ - -#ifndef __METAL_MUTEX__H__ -#define __METAL_MUTEX__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup mutex Mutex Interfaces - * @{ */ - -#include - -/** - * @brief Initialize a libmetal mutex. - * @param[in] mutex Mutex to initialize. - */ -static inline void metal_mutex_init(metal_mutex_t *mutex) -{ - __metal_mutex_init(mutex); -} - -/** - * @brief Deinitialize a libmetal mutex. - * @param[in] mutex Mutex to deinitialize. - */ -static inline void metal_mutex_deinit(metal_mutex_t *mutex) -{ - __metal_mutex_deinit(mutex); -} - -/** - * @brief Try to acquire a mutex - * @param[in] mutex Mutex to mutex. - * @return 0 on failure to acquire, non-zero on success. - */ -static inline int metal_mutex_try_acquire(metal_mutex_t *mutex) -{ - return __metal_mutex_try_acquire(mutex); -} - -/** - * @brief Acquire a mutex - * @param[in] mutex Mutex to mutex. - */ -static inline void metal_mutex_acquire(metal_mutex_t *mutex) -{ - __metal_mutex_acquire(mutex); -} - -/** - * @brief Release a previously acquired mutex. - * @param[in] mutex Mutex to mutex. - * @see metal_mutex_try_acquire, metal_mutex_acquire - */ -static inline void metal_mutex_release(metal_mutex_t *mutex) -{ - __metal_mutex_release(mutex); -} - -/** - * @brief Checked if a mutex has been acquired. - * @param[in] mutex mutex to check. - * @see metal_mutex_try_acquire, metal_mutex_acquire - */ -static inline int metal_mutex_is_acquired(metal_mutex_t *mutex) -{ - return __metal_mutex_is_acquired(mutex); -} - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_MUTEX__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file mutex.h + * @brief Mutex primitives for libmetal. + */ + +#ifndef __METAL_MUTEX__H__ +#define __METAL_MUTEX__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup mutex Mutex Interfaces + * @{ + */ + +/** + * @brief Initialize a libmetal mutex. + * @param[in] mutex Mutex to initialize. + */ +static inline void metal_mutex_init(metal_mutex_t *mutex) +{ + __metal_mutex_init(mutex); +} + +/** + * @brief Deinitialize a libmetal mutex. + * @param[in] mutex Mutex to deinitialize. + */ +static inline void metal_mutex_deinit(metal_mutex_t *mutex) +{ + __metal_mutex_deinit(mutex); +} + +/** + * @brief Try to acquire a mutex + * @param[in] mutex Mutex to mutex. + * @return 0 on failure to acquire, non-zero on success. + */ +static inline int metal_mutex_try_acquire(metal_mutex_t *mutex) +{ + return __metal_mutex_try_acquire(mutex); +} + +/** + * @brief Acquire a mutex + * @param[in] mutex Mutex to mutex. + */ +static inline void metal_mutex_acquire(metal_mutex_t *mutex) +{ + __metal_mutex_acquire(mutex); +} + +/** + * @brief Release a previously acquired mutex. + * @param[in] mutex Mutex to mutex. + * @see metal_mutex_try_acquire, metal_mutex_acquire + */ +static inline void metal_mutex_release(metal_mutex_t *mutex) +{ + __metal_mutex_release(mutex); +} + +/** + * @brief Checked if a mutex has been acquired. + * @param[in] mutex mutex to check. + * @see metal_mutex_try_acquire, metal_mutex_acquire + */ +static inline int metal_mutex_is_acquired(metal_mutex_t *mutex) +{ + return __metal_mutex_is_acquired(mutex); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_MUTEX__H__ */ diff --git a/libraries/openamp_arduino/src/metal/processor/arm/atomic.h b/libraries/openamp_arduino/src/metal/processor/arm/atomic.h index c5e25cd..ab5ee40 100755 --- a/libraries/openamp_arduino/src/metal/processor/arm/atomic.h +++ b/libraries/openamp_arduino/src/metal/processor/arm/atomic.h @@ -1,15 +1,15 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file arm/atomic.h - * @brief ARM specific atomic primitives for libmetal. - */ - -#ifndef __METAL_ARM_ATOMIC__H__ -#define __METAL_ARM_ATOMIC__H__ - -#endif /* __METAL_ARM_ATOMIC__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file arm/atomic.h + * @brief Arm specific atomic primitives for libmetal. + */ + +#ifndef __METAL_ARM_ATOMIC__H__ +#define __METAL_ARM_ATOMIC__H__ + +#endif /* __METAL_ARM_ATOMIC__H__ */ diff --git a/libraries/openamp_arduino/src/metal/processor/arm/cpu.h b/libraries/openamp_arduino/src/metal/processor/arm/cpu.h index 3e4f848..0ea9610 100755 --- a/libraries/openamp_arduino/src/metal/processor/arm/cpu.h +++ b/libraries/openamp_arduino/src/metal/processor/arm/cpu.h @@ -1,17 +1,17 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file cpu.h - * @brief CPU specific primatives - */ - -#ifndef __METAL_ARM_CPU__H__ -#define __METAL_ARM_CPU__H__ - -#define metal_cpu_yield() - -#endif /* __METAL_ARM_CPU__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cpu.h + * @brief CPU specific primitives + */ + +#ifndef __METAL_ARM_CPU__H__ +#define __METAL_ARM_CPU__H__ + +#define metal_cpu_yield() + +#endif /* __METAL_ARM_CPU__H__ */ diff --git a/libraries/openamp_arduino/src/metal/shmem.h b/libraries/openamp_arduino/src/metal/shmem.h index 19f282c..561a2c8 100755 --- a/libraries/openamp_arduino/src/metal/shmem.h +++ b/libraries/openamp_arduino/src/metal/shmem.h @@ -1,83 +1,84 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file shmem.h - * @brief Shared memory primitives for libmetal. - */ - -#ifndef __METAL_SHMEM__H__ -#define __METAL_SHMEM__H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup shmem Shared Memory Interfaces - * @{ */ - -/** Generic shared memory data structure. */ -struct metal_generic_shmem { - const char *name; - struct metal_io_region io; - struct metal_list node; -}; - -/** - * @brief Open a libmetal shared memory segment. - * - * Open a shared memory segment. - * - * @param[in] name Name of segment to open. - * @param[in] size Size of segment. - * @param[out] io I/O region handle, if successful. - * @return 0 on success, or -errno on failure. - * - * @see metal_shmem_create - */ -extern int metal_shmem_open(const char *name, size_t size, - struct metal_io_region **io); - -/** - * @brief Statically register a generic shared memory region. - * - * Shared memory regions may be statically registered at application - * initialization, or may be dynamically opened. This interface is used for - * static registration of regions. Subsequent calls to metal_shmem_open() look - * up in this list of pre-registered regions. - * - * @param[in] shmem Generic shmem structure. - * @return 0 on success, or -errno on failure. - */ -extern int metal_shmem_register_generic(struct metal_generic_shmem *shmem); - -#ifdef METAL_INTERNAL - -/** - * @brief Open a statically registered shmem segment. - * - * This interface is meant for internal libmetal use within system specific - * shmem implementations. - * - * @param[in] name Name of segment to open. - * @param[in] size Size of segment. - * @param[out] io I/O region handle, if successful. - * @return 0 on success, or -errno on failure. - */ -int metal_shmem_open_generic(const char *name, size_t size, - struct metal_io_region **result); - -#endif - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_SHMEM__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file shmem.h + * @brief Shared memory primitives for libmetal. + */ + +#ifndef __METAL_SHMEM__H__ +#define __METAL_SHMEM__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup shmem Shared Memory Interfaces + * @{ + */ + +/** Generic shared memory data structure. */ +struct metal_generic_shmem { + const char *name; + struct metal_io_region io; + struct metal_list node; +}; + +/** + * @brief Open a libmetal shared memory segment. + * + * Open a shared memory segment. + * + * @param[in] name Name of segment to open. + * @param[in] size Size of segment. + * @param[out] io I/O region handle, if successful. + * @return 0 on success, or -errno on failure. + * + * @see metal_shmem_create + */ +extern int metal_shmem_open(const char *name, size_t size, + struct metal_io_region **io); + +/** + * @brief Statically register a generic shared memory region. + * + * Shared memory regions may be statically registered at application + * initialization, or may be dynamically opened. This interface is used for + * static registration of regions. Subsequent calls to metal_shmem_open() look + * up in this list of pre-registered regions. + * + * @param[in] shmem Generic shmem structure. + * @return 0 on success, or -errno on failure. + */ +extern int metal_shmem_register_generic(struct metal_generic_shmem *shmem); + +#ifdef METAL_INTERNAL + +/** + * @brief Open a statically registered shmem segment. + * + * This interface is meant for internal libmetal use within system specific + * shmem implementations. + * + * @param[in] name Name of segment to open. + * @param[in] size Size of segment. + * @param[out] io I/O region handle, if successful. + * @return 0 on success, or -errno on failure. + */ +int metal_shmem_open_generic(const char *name, size_t size, + struct metal_io_region **result); + +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SHMEM__H__ */ diff --git a/libraries/openamp_arduino/src/metal/sleep.h b/libraries/openamp_arduino/src/metal/sleep.h index 0dad401..b366ee5 100755 --- a/libraries/openamp_arduino/src/metal/sleep.h +++ b/libraries/openamp_arduino/src/metal/sleep.h @@ -1,44 +1,45 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file sleep.h - * @brief Sleep primitives for libmetal. - */ - -#ifndef __METAL_SLEEP__H__ -#define __METAL_SLEEP__H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup sleep Sleep Interfaces - * @{ */ - -/** - * @brief delay in microseconds - * delay the next execution in the calling thread - * fo usec microseconds. - * - * @param[in] usec microsecond intervals - * @return 0 on success, non-zero for failures - */ -static inline int metal_sleep_usec(unsigned int usec) -{ - return __metal_sleep_usec(usec); -} - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_SLEEP__H__ */ - +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file sleep.h + * @brief Sleep primitives for libmetal. + */ + +#ifndef __METAL_SLEEP__H__ +#define __METAL_SLEEP__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup sleep Sleep Interfaces + * @{ + */ + +/** + * @brief delay in microseconds + * delay the next execution in the calling thread + * fo usec microseconds. + * + * @param[in] usec microsecond intervals + * @return 0 on success, non-zero for failures + */ +static inline int metal_sleep_usec(unsigned int usec) +{ + return __metal_sleep_usec(usec); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SLEEP__H__ */ + diff --git a/libraries/openamp_arduino/src/metal/softirq.h b/libraries/openamp_arduino/src/metal/softirq.h new file mode 100644 index 0000000..52ea00f --- /dev/null +++ b/libraries/openamp_arduino/src/metal/softirq.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file softirq.h + * @brief Soft Interrupt handling primitives for libmetal. + */ + +#ifndef __METAL_SOFTIRQ__H__ +#define __METAL_SOFTIRQ__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup soft irq Interrupt Handling Interfaces + * @{ + */ + +/** + * @brief metal_softirq_init + * + * Initialize libmetal soft IRQs controller + * + * @return 0 on success, or negative value for failure + */ +int metal_softirq_init(void); + +/** + * @brief metal_softirq_dispatch + * + * Dispatch the pending soft IRQs + */ +void metal_softirq_dispatch(void); + +/** + * @brief metal_softirq_allocate + * + * Allocate soft IRQs + * + * This function doesn't have any locking, it is not supposed + * to be called by multiple threads. + * + * @param[in] num number of soft irqs requested + * @return soft irq base for success, or negative value for failure + */ +int metal_softirq_allocate(int num); + +/** + * @brief metal_softirq_set + * + * Set soft IRQ to pending + * + * @param[in] irq soft IRQ ID to set + */ +void metal_softirq_set(int irq); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SOFTIRQ__H__ */ diff --git a/libraries/openamp_arduino/src/metal/spinlock.h b/libraries/openamp_arduino/src/metal/spinlock.h index f6a711e..6992267 100755 --- a/libraries/openamp_arduino/src/metal/spinlock.h +++ b/libraries/openamp_arduino/src/metal/spinlock.h @@ -1,71 +1,70 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file spinlock.h - * @brief Spinlock primitives for libmetal. - */ - -#ifndef __METAL_SPINLOCK__H__ -#define __METAL_SPINLOCK__H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup spinlock Spinlock Interfaces - * @{ */ -struct metal_spinlock { - union{ - atomic_int v; - atomic_flag w; - }; -}; - -/** Static metal spinlock initialization. */ -#define METAL_SPINLOCK_INIT {ATOMIC_VAR_INIT(0)} - -/** - * @brief Initialize a libmetal spinlock. - * @param[in] slock Spinlock to initialize. - */ -static inline void metal_spinlock_init(struct metal_spinlock *slock) -{ - atomic_store(&slock->v, 0); -} - -/** - * @brief Acquire a spinlock. - * @param[in] slock Spinlock to acquire. - * @see metal_spinlock_release - */ -static inline void metal_spinlock_acquire(struct metal_spinlock *slock) -{ - while (atomic_flag_test_and_set(&slock->w)) { - metal_cpu_yield(); - } -} - -/** - * @brief Release a previously acquired spinlock. - * @param[in] slock Spinlock to release. - * @see metal_spinlock_acquire - */ -static inline void metal_spinlock_release(struct metal_spinlock *slock) -{ - atomic_flag_clear(&slock->w); -} - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_SPINLOCK__H__ */ +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file spinlock.h + * @brief Spinlock primitives for libmetal. + */ + +#ifndef __METAL_SPINLOCK__H__ +#define __METAL_SPINLOCK__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup spinlock Spinlock Interfaces + * @{ + */ + +struct metal_spinlock { + atomic_flag v; +}; + +/** Static metal spinlock initialization. */ +#define METAL_SPINLOCK_INIT {ATOMIC_FLAG_INIT} + +/** + * @brief Initialize a libmetal spinlock. + * @param[in] slock Spinlock to initialize. + */ +static inline void metal_spinlock_init(struct metal_spinlock *slock) +{ + atomic_flag_clear(&slock->v); +} + +/** + * @brief Acquire a spinlock. + * @param[in] slock Spinlock to acquire. + * @see metal_spinlock_release + */ +static inline void metal_spinlock_acquire(struct metal_spinlock *slock) +{ + while (atomic_flag_test_and_set(&slock->v)) { + metal_cpu_yield(); + } +} + +/** + * @brief Release a previously acquired spinlock. + * @param[in] slock Spinlock to release. + * @see metal_spinlock_acquire + */ +static inline void metal_spinlock_release(struct metal_spinlock *slock) +{ + atomic_flag_clear(&slock->v); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SPINLOCK__H__ */ diff --git a/libraries/openamp_arduino/src/metal/sys.h b/libraries/openamp_arduino/src/metal/sys.h index 12f7f69..24822ca 100755 --- a/libraries/openamp_arduino/src/metal/sys.h +++ b/libraries/openamp_arduino/src/metal/sys.h @@ -1,148 +1,152 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file sys.h - * @brief System primitives for libmetal. - * @brief Top level include internal to libmetal library code. - */ - -#ifndef __METAL_SYS__H__ -#define __METAL_SYS__H__ - -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup system Top Level Interfaces - * @{ */ - -/** Physical address type. */ -typedef unsigned long metal_phys_addr_t; - -/** Interrupt request number. */ -typedef int metal_irq_t; - -/** Bad offset into shared memory or I/O region. */ -#define METAL_BAD_OFFSET ((unsigned long)-1) - -/** Bad physical address value. */ -#define METAL_BAD_PHYS ((metal_phys_addr_t)-1) - -/** Bad virtual address value. */ -#define METAL_BAD_VA ((void *)-1) - -/** Bad IRQ. */ -#define METAL_BAD_IRQ ((metal_irq_t)-1) - -/** - * Initialization configuration for libmetal. - */ -struct metal_init_params { - - /** log message handler (defaults to stderr). */ - metal_log_handler log_handler; - - /** default log message level (defaults to emergency). */ - enum metal_log_level log_level; -}; - -/** - * System independent runtime state for libmetal. This is part of a system - * specific singleton data structure (@see _metal). - */ -struct metal_common_state { - /** Current log level. */ - enum metal_log_level log_level; - - /** Current log handler (null for none). */ - metal_log_handler log_handler; - - /** List of registered buses. */ - struct metal_list bus_list; - - /** Generic statically defined shared memory segments. */ - struct metal_list generic_shmem_list; - - /** Generic statically defined devices. */ - struct metal_list generic_device_list; -}; - -struct metal_state; - -#include - -#ifndef METAL_INIT_DEFAULTS -#define METAL_INIT_DEFAULTS \ -{ \ - .log_handler = metal_default_log_handler, \ - .log_level = METAL_LOG_INFO, \ -} -#endif - -/** System specific runtime data. */ -extern struct metal_state _metal; - -/** - * @brief Initialize libmetal. - * - * Initialize the libmetal library. - * - * @param[in] params Initialization params (@see metal_init_params). - * - * @return 0 on success, or -errno on failure. - * - * @see metal_finish - */ -extern int metal_init(const struct metal_init_params *params); - -/** - * @brief Shutdown libmetal. - * - * Shutdown the libmetal library, and release all reserved resources. - * - * @see metal_init - */ -extern void metal_finish(void); - -#ifdef METAL_INTERNAL - -/** - * @brief libmetal system initialization. - * - * This function initializes libmetal on Linux or Generic platforms. This - * involves obtaining necessary pieces of system information (sysfs mount path, - * page size, etc.). - * - * @param[in] params Initialization parameters (@see metal_init_params). - * @return 0 on success, or -errno on failure. - */ -extern int metal_sys_init(const struct metal_init_params *params); - -/** - * @brief libmetal system shutdown. - * - * This function shuts down and releases resources held by libmetal Linux or - * Generic platform layers. - * - * @see metal_sys_init - */ -extern void metal_sys_finish(void); - -#endif - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_SYS__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file sys.h + * @brief System primitives for libmetal. + * @brief Top level include internal to libmetal library code. + */ + +#ifndef __METAL_SYS__H__ +#define __METAL_SYS__H__ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup system Top Level Interfaces + * @{ + */ + +/** Physical address type. */ +typedef unsigned long metal_phys_addr_t; + +/** Interrupt request number. */ +typedef int metal_irq_t; + +/** Bad offset into shared memory or I/O region. */ +#define METAL_BAD_OFFSET ((unsigned long)-1) + +/** Bad physical address value. */ +#define METAL_BAD_PHYS ((metal_phys_addr_t)-1) + +/** Bad virtual address value. */ +#define METAL_BAD_VA ((void *)-1) + +/** Bad IRQ. */ +#define METAL_BAD_IRQ ((metal_irq_t)-1) + +/** + * Initialization configuration for libmetal. + */ +struct metal_init_params { + + /** log message handler (defaults to stderr). */ + metal_log_handler log_handler; + + /** default log message level (defaults to emergency). */ + enum metal_log_level log_level; +}; + +/** + * System independent runtime state for libmetal. This is part of a system + * specific singleton data structure (@see _metal). + */ +struct metal_common_state { + /** reference count to track metal_init/metal_finish. */ + int ref_count; + + /** Current log level. */ + enum metal_log_level log_level; + + /** Current log handler (null for none). */ + metal_log_handler log_handler; + + /** List of registered buses. */ + struct metal_list bus_list; + + /** Generic statically defined shared memory segments. */ + struct metal_list generic_shmem_list; + + /** Generic statically defined devices. */ + struct metal_list generic_device_list; +}; + +struct metal_state; + +#include + +#ifndef METAL_INIT_DEFAULTS +#define METAL_INIT_DEFAULTS \ +{ \ + .log_handler = metal_default_log_handler, \ + .log_level = METAL_LOG_INFO, \ +} +#endif + +/** System specific runtime data. */ +extern struct metal_state _metal; + +/** + * @brief Initialize libmetal. + * + * Initialize the libmetal library. + * + * @param[in] params Initialization params (@see metal_init_params). + * + * @return 0 on success, or -errno on failure. + * + * @see metal_finish + */ +extern int metal_init(const struct metal_init_params *params); + +/** + * @brief Shutdown libmetal. + * + * Shutdown the libmetal library, and release all reserved resources. + * + * @see metal_init + */ +extern void metal_finish(void); + +#ifdef METAL_INTERNAL + +/** + * @brief libmetal system initialization. + * + * This function initializes libmetal on Linux or Generic platforms. This + * involves obtaining necessary pieces of system information (sysfs mount path, + * page size, etc.). + * + * @param[in] params Initialization parameters (@see metal_init_params). + * @return 0 on success, or -errno on failure. + */ +extern int metal_sys_init(const struct metal_init_params *params); + +/** + * @brief libmetal system shutdown. + * + * This function shuts down and releases resources held by libmetal Linux or + * Generic platform layers. + * + * @see metal_sys_init + */ +extern void metal_sys_finish(void); + +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_SYS__H__ */ diff --git a/libraries/openamp_arduino/src/metal/system/generic/alloc.h b/libraries/openamp_arduino/src/metal/system/generic/alloc.h index 5338dd7..6dc767f 100755 --- a/libraries/openamp_arduino/src/metal/system/generic/alloc.h +++ b/libraries/openamp_arduino/src/metal/system/generic/alloc.h @@ -22,12 +22,12 @@ extern "C" { #endif -static inline void *metal_allocate_memory(unsigned int size) +static inline void *__metal_allocate_memory(unsigned int size) { return (malloc(size)); } -static inline void metal_free_memory(void *ptr) +static inline void __metal_free_memory(void *ptr) { free(ptr); } diff --git a/libraries/openamp_arduino/src/metal/system/generic/cortexm/sys.h b/libraries/openamp_arduino/src/metal/system/generic/cortexm/sys.h deleted file mode 100755 index 35597d6..0000000 --- a/libraries/openamp_arduino/src/metal/system/generic/cortexm/sys.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of Xilinx nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * @file generic/mp1_m4/sys.h - * @brief generic mp1_m4 system primitives for libmetal. - */ - -#ifndef __METAL_GENERIC_SYS__H__ -#error "Include metal/sys.h instead of metal/generic/cortexm/sys.h" -#endif - -#ifndef __METAL_GENERIC_MP1_M4_SYS__H__ -#define __METAL_GENERIC_MP1_M4_SYS__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(MAX_IRQS) -#define MAX_IRQS 8 /**< maximum number of irqs */ -#endif - -static inline void sys_irq_enable(unsigned int vector) -{ - (void)vector; -} - -static inline void sys_irq_disable(unsigned int vector) -{ - (void)vector; -} - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_GENERIC_MP1_M4_SYS__H__ */ diff --git a/libraries/openamp_arduino/src/metal/system/generic/sys.h b/libraries/openamp_arduino/src/metal/system/generic/sys.h index f5a2368..0a19b23 100755 --- a/libraries/openamp_arduino/src/metal/system/generic/sys.h +++ b/libraries/openamp_arduino/src/metal/system/generic/sys.h @@ -25,8 +25,6 @@ #include #include -#include "./cortexm/sys.h" - #ifdef __cplusplus extern "C" { #endif diff --git a/libraries/openamp_arduino/src/metal/time.h b/libraries/openamp_arduino/src/metal/time.h index b05e679..bc24e61 100755 --- a/libraries/openamp_arduino/src/metal/time.h +++ b/libraries/openamp_arduino/src/metal/time.h @@ -1,41 +1,42 @@ -/* - * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file time.h - * @brief Time primitives for libmetal. - */ - -#ifndef __METAL_TIME__H__ -#define __METAL_TIME__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup time TIME Interfaces - * @{ */ - -#include -#include - -/** - * @brief get timestamp - * This function returns the timestampe as unsigned long long - * value. - * - * @return timestamp - */ -unsigned long long metal_get_timestamp(void); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_TIME__H__ */ - +/* + * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file time.h + * @brief Time primitives for libmetal. + */ + +#ifndef __METAL_TIME__H__ +#define __METAL_TIME__H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup time TIME Interfaces + * @{ + */ + +/** + * @brief get timestamp + * This function returns the timestampe as unsigned long long + * value. + * + * @return timestamp + */ +unsigned long long metal_get_timestamp(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_TIME__H__ */ + diff --git a/libraries/openamp_arduino/src/metal/utilities.h b/libraries/openamp_arduino/src/metal/utilities.h index 95a6670..6b592e0 100755 --- a/libraries/openamp_arduino/src/metal/utilities.h +++ b/libraries/openamp_arduino/src/metal/utilities.h @@ -1,152 +1,165 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file utilities.h - * @brief Utility routines for libmetal. - */ - -#ifndef __METAL_UTILITIES__H__ -#define __METAL_UTILITIES__H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup utilities Simple Utilities - * @{ */ - -/** Marker for unused function arguments/variables. */ -#define metal_unused(x) do { (x) = (x); } while (0) - -/** Figure out number of elements in an array. */ -#define metal_dim(x) (sizeof(x) / sizeof(x[0])) - -/** Minimum of two numbers (warning: multiple evaluation!). */ -#define metal_min(x, y) ((x) < (y) ? (x) : (y)) - -/** Maximum of two numbers (warning: multiple evaluation!). */ -#define metal_max(x, y) ((x) > (y) ? (x) : (y)) - -/** Sign of a number [-1, 0, or 1] (warning: multiple evaluation!). */ -#define metal_sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) - -/** Align 'size' down to a multiple of 'align' (must be a power of two). */ -#define metal_align_down(size, align) \ - ((size) & ~((align) - 1)) - -/** Align 'size' up to a multiple of 'align' (must be a power of two). */ -#define metal_align_up(size, align) \ - metal_align_down((size) + (align) - 1, align) - -/** Divide (and round down). */ -#define metal_div_round_down(num, den) \ - ((num) / (den)) - -/** Divide (and round up). */ -#define metal_div_round_up(num, den) \ - metal_div_round_down((num) + (den) - 1, (den)) - -/** Align 'ptr' down to a multiple of 'align' (must be a power of two). */ -#define metal_ptr_align_down(ptr, align) \ - (void *)(metal_align_down((uintptr_t)(ptr), (uintptr_t)(align))) - -/** Align 'ptr' up to a multiple of 'align' (must be a power of two). */ -#define metal_ptr_align_up(ptr, align) \ - (void *)(metal_align_up((uintptr_t)(ptr), (uintptr_t)(align))) - -/** Compute offset of a field within a structure. */ -#define metal_offset_of(structure, member) \ - ((uintptr_t) &(((structure *) 0)->member)) - -/** Compute pointer to a structure given a pointer to one of its fields. */ -#define metal_container_of(ptr, structure, member) \ - (void *)((uintptr_t)(ptr) - metal_offset_of(structure, member)) - -#define METAL_BITS_PER_ULONG (8 * sizeof(unsigned long)) - -#define metal_bit(bit) (1UL << (bit)) - -#define metal_bitmap_longs(x) metal_div_round_up((x), METAL_BITS_PER_ULONG) - -static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit) -{ - bitmap[bit / METAL_BITS_PER_ULONG] |= - metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); -} - -static inline int metal_bitmap_is_bit_set(unsigned long *bitmap, int bit) -{ - return bitmap[bit / METAL_BITS_PER_ULONG] & - metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); -} - -static inline void metal_bitmap_clear_bit(unsigned long *bitmap, int bit) -{ - bitmap[bit / METAL_BITS_PER_ULONG] &= - ~metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); -} - -static inline int metal_bitmap_is_bit_clear(unsigned long *bitmap, int bit) -{ - return !metal_bitmap_is_bit_set(bitmap, bit); -} - -static inline unsigned int -metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start, - unsigned int max) -{ - unsigned int bit; - for (bit = start; - bit < max && !metal_bitmap_is_bit_set(bitmap, bit); - bit ++) - ; - return bit; -} - -#define metal_bitmap_for_each_set_bit(bitmap, bit, max) \ - for ((bit) = metal_bitmap_next_set_bit((bitmap), 0, (max)); \ - (bit) < (max); \ - (bit) = metal_bitmap_next_set_bit((bitmap), (bit), (max))) - -static inline unsigned int -metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start, - unsigned int max) -{ - unsigned int bit; - for (bit = start; - bit < max && !metal_bitmap_is_bit_clear(bitmap, bit); - bit ++) - ; - return bit; -} - -#define metal_bitmap_for_each_clear_bit(bitmap, bit, max) \ - for ((bit) = metal_bitmap_next_clear_bit((bitmap), 0, (max)); \ - (bit) < (max); \ - (bit) = metal_bitmap_next_clear_bit((bitmap), (bit), (max))) - -static inline unsigned long metal_log2(unsigned long in) -{ - unsigned long result; - - metal_assert((in & (in - 1)) == 0); - - for (result = 0; (1UL << result) < in; result ++) - ; - return result; -} - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_UTILITIES__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file utilities.h + * @brief Utility routines for libmetal. + */ + +#ifndef __METAL_UTILITIES__H__ +#define __METAL_UTILITIES__H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup utilities Simple Utilities + * @{ + */ + +#ifndef MB +#define MB (1024UL << 10UL) +#endif + +#ifndef GB +#define GB (MB << 10UL) +#endif + +/** Marker for unused function arguments/variables. */ +#define metal_unused(x) do { (x) = (x); } while (0) + +/** Figure out number of elements in an array. */ +#define metal_dim(x) (sizeof(x) / sizeof(x[0])) + +/** Minimum of two numbers (warning: multiple evaluation!). */ +#define metal_min(x, y) ((x) < (y) ? (x) : (y)) + +/** Maximum of two numbers (warning: multiple evaluation!). */ +#define metal_max(x, y) ((x) > (y) ? (x) : (y)) + +/** Sign of a number [-1, 0, or 1] (warning: multiple evaluation!). */ +#define metal_sign(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0)) + +/** Align 'size' down to a multiple of 'align' (must be a power of two). */ +#define metal_align_down(size, align) \ + ((size) & ~((align) - 1)) + +/** Align 'size' up to a multiple of 'align' (must be a power of two). */ +#define metal_align_up(size, align) \ + metal_align_down((size) + (align) - 1, align) + +/** Divide (and round down). */ +#define metal_div_round_down(num, den) \ + ((num) / (den)) + +/** Divide (and round up). */ +#define metal_div_round_up(num, den) \ + metal_div_round_down((num) + (den) - 1, (den)) + +/** Align 'ptr' down to a multiple of 'align' (must be a power of two). */ +#define metal_ptr_align_down(ptr, align) \ + (void *)(metal_align_down((uintptr_t)(ptr), (uintptr_t)(align))) + +/** Align 'ptr' up to a multiple of 'align' (must be a power of two). */ +#define metal_ptr_align_up(ptr, align) \ + (void *)(metal_align_up((uintptr_t)(ptr), (uintptr_t)(align))) + +/** Compute offset of a field within a structure. */ +#define metal_offset_of(structure, member) \ + ((uintptr_t)&(((structure *)0)->member)) + +/** Compute pointer to a structure given a pointer to one of its fields. */ +#define metal_container_of(ptr, structure, member) \ + (void *)((uintptr_t)(ptr) - metal_offset_of(structure, member)) + +#define METAL_BITS_PER_ULONG (CHAR_BIT * sizeof(unsigned long)) + +#define metal_bit(bit) (1UL << (bit)) + +#define metal_bitmap_longs(x) metal_div_round_up((x), METAL_BITS_PER_ULONG) + +static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit) +{ + bitmap[bit / METAL_BITS_PER_ULONG] |= + metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); +} + +static inline int metal_bitmap_is_bit_set(unsigned long *bitmap, int bit) +{ + return ((bitmap[bit / METAL_BITS_PER_ULONG] & + metal_bit(bit & (METAL_BITS_PER_ULONG - 1))) == 0) ? 0 : 1; +} + +static inline void metal_bitmap_clear_bit(unsigned long *bitmap, int bit) +{ + bitmap[bit / METAL_BITS_PER_ULONG] &= + ~metal_bit(bit & (METAL_BITS_PER_ULONG - 1)); +} + +static inline int metal_bitmap_is_bit_clear(unsigned long *bitmap, int bit) +{ + return !metal_bitmap_is_bit_set(bitmap, bit); +} + +static inline unsigned int +metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start, + unsigned int max) +{ + unsigned int bit; + + for (bit = start; + bit < max && !metal_bitmap_is_bit_set(bitmap, bit); + bit++) + ; + return bit; +} + +#define metal_bitmap_for_each_set_bit(bitmap, bit, max) \ + for ((bit) = metal_bitmap_next_set_bit((bitmap), 0, (max)); \ + (bit) < (max); \ + (bit) = metal_bitmap_next_set_bit((bitmap), (bit + 1), (max))) + +static inline unsigned int +metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start, + unsigned int max) +{ + unsigned int bit; + + for (bit = start; + bit < max && !metal_bitmap_is_bit_clear(bitmap, bit); + bit++) + ; + return bit; +} + +#define metal_bitmap_for_each_clear_bit(bitmap, bit, max) \ + for ((bit) = metal_bitmap_next_clear_bit((bitmap), 0, (max)); \ + (bit) < (max); \ + (bit) = metal_bitmap_next_clear_bit((bitmap), (bit + 1), (max))) + +static inline unsigned long metal_log2(unsigned long in) +{ + unsigned long result; + + metal_assert((in & (in - 1)) == 0); + + for (result = 0; (1UL << result) < in; result++) + ; + return result; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_UTILITIES__H__ */ diff --git a/libraries/openamp_arduino/src/metal/version.h b/libraries/openamp_arduino/src/metal/version.h index 96666b3..32be7ae 100755 --- a/libraries/openamp_arduino/src/metal/version.h +++ b/libraries/openamp_arduino/src/metal/version.h @@ -1,76 +1,77 @@ -/* - * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * @file version.h - * @brief Library version information for libmetal. - */ - -#ifndef __METAL_VERSION__H__ -#define __METAL_VERSION__H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \defgroup versions Library Version Interfaces - * @{ */ - -/** - * @brief Library major version number. - * - * Return the major version number of the library linked into the application. - * This is required to match the value of METAL_VER_MAJOR, which is the major - * version of the library that the application was compiled against. - * - * @return Library major version number. - * @see METAL_VER_MAJOR - */ -extern int metal_ver_major(void); - -/** - * @brief Library minor version number. - * - * Return the minor version number of the library linked into the application. - * This could differ from the value of METAL_VER_MINOR, which is the minor - * version of the library that the application was compiled against. - * - * @return Library minor version number. - * @see METAL_VER_MINOR - */ -extern int metal_ver_minor(void); - -/** - * @brief Library patch level. - * - * Return the patch level of the library linked into the application. This - * could differ from the value of METAL_VER_PATCH, which is the patch level of - * the library that the application was compiled against. - * - * @return Library patch level. - * @see METAL_VER_PATCH - */ -extern int metal_ver_patch(void); - -/** - * @brief Library version string. - * - * Return the version string of the library linked into the application. This - * could differ from the value of METAL_VER, which is the version string of - * the library that the application was compiled against. - * - * @return Library version string. - * @see METAL_VER - */ -extern const char *metal_ver(void); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* __METAL_VERSION__H__ */ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file version.h + * @brief Library version information for libmetal. + */ + +#ifndef __METAL_VERSION__H__ +#define __METAL_VERSION__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup versions Library Version Interfaces + * @{ + */ + +/** + * @brief Library major version number. + * + * Return the major version number of the library linked into the application. + * This is required to match the value of METAL_VER_MAJOR, which is the major + * version of the library that the application was compiled against. + * + * @return Library major version number. + * @see METAL_VER_MAJOR + */ +extern int metal_ver_major(void); + +/** + * @brief Library minor version number. + * + * Return the minor version number of the library linked into the application. + * This could differ from the value of METAL_VER_MINOR, which is the minor + * version of the library that the application was compiled against. + * + * @return Library minor version number. + * @see METAL_VER_MINOR + */ +extern int metal_ver_minor(void); + +/** + * @brief Library patch level. + * + * Return the patch level of the library linked into the application. This + * could differ from the value of METAL_VER_PATCH, which is the patch level of + * the library that the application was compiled against. + * + * @return Library patch level. + * @see METAL_VER_PATCH + */ +extern int metal_ver_patch(void); + +/** + * @brief Library version string. + * + * Return the version string of the library linked into the application. This + * could differ from the value of METAL_VER, which is the version string of + * the library that the application was compiled against. + * + * @return Library version string. + * @see METAL_VER + */ +extern const char *metal_ver(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_VERSION__H__ */ diff --git a/libraries/openamp_arduino/src/openamp.c b/libraries/openamp_arduino/src/openamp.c index 6ce6b5a..554b063 100644 --- a/libraries/openamp_arduino/src/openamp.c +++ b/libraries/openamp_arduino/src/openamp.c @@ -59,25 +59,19 @@ static int OPENAMP_shmem_init(int RPMsgRole) status = metal_register_generic_device(&shm_device); if (status != 0) { - printf("metal_register_generic_device failed\n"); return status; } status = metal_device_open("generic", SHM_DEVICE_NAME, &device); if (status != 0) { - printf("metal_device_open failed\n"); return status; } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpointer-arith" metal_io_init(&device->regions[0], (void *)SHM_START_ADDRESS, shm_physmap, SHM_SIZE, -1U, 0, NULL); -#pragma GCC diagnostic pop shm_io = metal_device_io_region(device, 0); if (shm_io == NULL) { - printf("metal_device_io_region failed\n"); return -1; } @@ -86,7 +80,6 @@ static int OPENAMP_shmem_init(int RPMsgRole) rsc_table = (struct shared_resource_table *)rsc_tab_addr; if (!rsc_table) { - printf("resource_table_init failed\n"); return -1; } @@ -96,7 +89,6 @@ static int OPENAMP_shmem_init(int RPMsgRole) rsc_io = metal_device_io_region(device, 1); if (rsc_io == NULL) { - printf("metal_device_io_region 2 failed\n"); return -1; } @@ -142,12 +134,8 @@ int MX_OPENAMP_Init(int RPMsgRole, rpmsg_ns_bind_cb ns_bind_cb) return status; } - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpointer-arith" rpmsg_virtio_init_shm_pool(&shpool, (void *)VRING_BUFF_ADDRESS, - (size_t)SHM_SIZE); -#pragma GCC diagnostic pop + (size_t)VRING_BUFF_SIZE); rpmsg_init_vdev(&rvdev, vdev, ns_bind_cb, shm_io, &shpool); @@ -163,7 +151,7 @@ void OPENAMP_DeInit() void OPENAMP_init_ept(struct rpmsg_endpoint *ept) { - rpmsg_init_ept(ept, "", RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, NULL, NULL); + //rpmsg_init_ept(ept, "", RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, NULL, NULL); } int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name, @@ -174,21 +162,23 @@ int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name, unbind_cb); } -void OPENAMP_check_for_message(void) +int OPENAMP_check_for_message(void) { - MAILBOX_Poll(rvdev.vdev); + return MAILBOX_Poll(rvdev.vdev); } -uint32_t HAL_GetTick(void); +unsigned long millis(); -void OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept, size_t timeout) +int OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept, size_t deadline) { - while(!is_rpmsg_ept_ready(rp_ept) && (HAL_GetTick() < timeout)) { + while(!is_rpmsg_ept_ready(rp_ept) && (millis() < deadline)) { MAILBOX_Poll(rvdev.vdev); } - if (HAL_GetTick() >= timeout) { - printf("OPENAMP_Wait_EndPointready %X timed out\n\r", (unsigned int)rp_ept); + if (millis() >= deadline) { + //printf("OPENAMP_Wait_EndPointready %X timed out\n\r", (unsigned int)rp_ept); + return -1; } + return 0; } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/openamp_arduino/src/openamp.h b/libraries/openamp_arduino/src/openamp.h index ca4e111..e604c0c 100644 --- a/libraries/openamp_arduino/src/openamp.h +++ b/libraries/openamp_arduino/src/openamp.h @@ -1,59 +1,59 @@ -/** - ****************************************************************************** - * @file OpenAMP/OpenAMP_PingPong/Common/Inc/openamp.h - * @author MCD Application Team - * @brief Header file for openamp module - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __openamp_H -#define __openamp_H -#ifdef __cplusplus - extern "C" { -#endif - -#include "openamp/open_amp.h" -#include "openamp_conf.h" - - -#define OPENAMP_send rpmsg_send -#define OPENAMP_destroy_ept rpmsg_destroy_ept - -/* Initialize the openamp framework*/ -int MX_OPENAMP_Init(int RPMsgRole, rpmsg_ns_bind_cb ns_bind_cb); - -/* Deinitialize the openamp framework*/ -void OPENAMP_DeInit(void); - -/* Initialize the endpoint struct*/ -void OPENAMP_init_ept(struct rpmsg_endpoint *ept); - -/* Create and register the endpoint */ -int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name, - uint32_t dest, rpmsg_ept_cb cb, - rpmsg_ns_unbind_cb unbind_cb); - -/* Check for new rpmsg reception */ -void OPENAMP_check_for_message(void); - -/* Wait loop on endpoint ready ( message dest address is know)*/ -void OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept, size_t timeout); - -#ifdef __cplusplus -} -#endif -#endif /*__openamp_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file OpenAMP/OpenAMP_PingPong/Common/Inc/openamp.h + * @author MCD Application Team + * @brief Header file for openamp module + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __openamp_H +#define __openamp_H +#ifdef __cplusplus + extern "C" { +#endif + +#include "openamp/open_amp.h" +#include "openamp_conf.h" + + +#define OPENAMP_send rpmsg_send +#define OPENAMP_destroy_ept rpmsg_destroy_ept + +/* Initialize the openamp framework*/ +int MX_OPENAMP_Init(int RPMsgRole, rpmsg_ns_bind_cb ns_bind_cb); + +/* Deinitialize the openamp framework*/ +void OPENAMP_DeInit(void); + +/* Initialize the endpoint struct*/ +void OPENAMP_init_ept(struct rpmsg_endpoint *ept); + +/* Create and register the endpoint */ +int OPENAMP_create_endpoint(struct rpmsg_endpoint *ept, const char *name, + uint32_t dest, rpmsg_ept_cb cb, + rpmsg_ns_unbind_cb unbind_cb); + +/* Check for new rpmsg reception */ +int OPENAMP_check_for_message(void); + +/* Wait loop on endpoint ready ( message dest address is know)*/ +int OPENAMP_Wait_EndPointready(struct rpmsg_endpoint *rp_ept, size_t deadline); + +#ifdef __cplusplus +} +#endif +#endif /*__openamp_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/openamp_arduino/src/openamp/elf_loader.h b/libraries/openamp_arduino/src/openamp/elf_loader.h index acf3d29..a2950f8 100755 --- a/libraries/openamp_arduino/src/openamp/elf_loader.h +++ b/libraries/openamp_arduino/src/openamp/elf_loader.h @@ -1,428 +1,445 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef ELF_LOADER_H_ -#define ELF_LOADER_H_ - -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* ELF32 base types - 32-bit. */ -typedef uint32_t Elf32_Addr; -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Off; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf32_Word; - -/* ELF64 base types - 64-bit. */ -typedef uint64_t Elf64_Addr; -typedef uint16_t Elf64_Half; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* Size of ELF identifier field in the ELF file header. */ -#define EI_NIDENT 16 - -/* ELF32 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; - -/* ELF64 file header */ -typedef struct { - unsigned char e_ident[EI_NIDENT]; - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; - Elf64_Off e_phoff; - Elf64_Off e_shoff; - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -} Elf64_Ehdr; - -/* e_ident */ -#define ET_NONE 0 -#define ET_REL 1 /* Re-locatable file */ -#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] */ -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -/* - * 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 - -/* ELF32 program header */ -typedef struct elf32_phdr{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -} Elf32_Phdr; - -/* ELF64 program header */ -typedef struct elf64_phdr { - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; - Elf64_Addr p_vaddr; - Elf64_Addr p_paddr; - Elf64_Xword p_filesz; - Elf64_Xword p_memsz; - Elf64_Xword p_align; -} Elf64_Phdr; - -/* segment types */ -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_TLS 7 /* Thread local storage segment */ -#define PT_LOOS 0x60000000 /* OS-specific */ -#define PT_HIOS 0x6fffffff /* OS-specific */ -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7fffffff - -/* ELF32 section header. */ -typedef struct { - Elf32_Word sh_name; - Elf32_Word sh_type; - 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; - -/* ELF64 section header. */ -typedef struct { - Elf64_Word sh_name; - Elf64_Word sh_type; - Elf64_Xword sh_flags; - Elf64_Addr sh_addr; - Elf64_Off sh_offset; - Elf64_Xword sh_size; - Elf64_Word sh_link; - Elf64_Word sh_info; - Elf64_Xword sh_addralign; - Elf64_Xword sh_entsize; -} Elf64_Shdr; - -/* sh_type */ -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#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; - -typedef struct { - Elf64_Addr r_offset; - Elf64_Xword r_info; - -} Elf64_Rel; - -/* Relocation entry with addend */ -typedef struct { - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; - -} Elf32_Rela; - -typedef struct elf64_rela { - Elf64_Addr r_offset; - Elf64_Xword r_info; - Elf64_Sxword r_addend; -} Elf64_Rela; - -/* Macros to extract information from 'r_info' field of relocation entries */ -#define ELF32_R_SYM(i) ((i) >> 8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) - -/* 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; - -typedef struct elf64_sym { - Elf64_Word st_name; - unsigned char st_info; - unsigned char st_other; - Elf64_Half st_shndx; - Elf64_Addr st_value; - Elf64_Xword st_size; -} Elf64_Sym; - -/* ARM specific dynamic relocation codes */ -#define R_ARM_GLOB_DAT 21 /* 0x15 */ -#define R_ARM_JUMP_SLOT 22 /* 0x16 */ -#define R_ARM_RELATIVE 23 /* 0x17 */ -#define R_ARM_ABS32 2 /* 0x02 */ - -/* ELF decoding information */ -struct elf32_info { - Elf32_Ehdr ehdr; - unsigned int load_state; - Elf32_Phdr *phdrs; - Elf32_Shdr *shdrs; - void *shstrtab; -}; - -struct elf64_info { - Elf64_Ehdr ehdr; - unsigned int load_state; - Elf64_Phdr *phdrs; - Elf64_Shdr *shdrs; - void *shstrtab; -}; - -#define ELF_STATE_INIT 0x0UL -#define ELF_STATE_WAIT_FOR_PHDRS 0x100UL -#define ELF_STATE_WAIT_FOR_SHDRS 0x200UL -#define ELF_STATE_WAIT_FOR_SHSTRTAB 0x400UL -#define ELF_STATE_HDRS_COMPLETE 0x800UL -#define ELF_STATE_MASK 0xFF00UL -#define ELF_NEXT_SEGMENT_MASK 0x00FFUL - -extern struct loader_ops elf_ops; - -/** - * elf_identify - check if it is an ELF file - * - * It will check if the input image header is an ELF header. - * - * @img_data: firmware private data which will be passed to user defined loader - * operations - * @len: firmware header length - * - * return 0 for success or negative value for failure. - */ -int elf_identify(const void *img_data, size_t len); - -/** - * elf_load_header - Load ELF headers - * - * It will get the ELF header, the program header, and the section header. - * - * @img_data: image data - * @offset: input image data offset to the start of image file - * @len: input image data length - * @img_info: pointer to store image information data - * @last_load_state: last state return by this function - * @noffset: pointer to next offset required by loading ELF header - * @nlen: pointer to next data length required by loading ELF header - * - * return ELF loading header state, or negative value for failure - */ -int elf_load_header(const void *img_data, size_t offset, size_t len, - void **img_info, int last_load_state, - size_t *noffset, size_t *nlen); - -/** - * elf_load - load ELF data - * - * It will parse the ELF image and return the target device address, - * offset to the start of the ELF image of the data to load and the - * length of the data to load. - * - * @rproc: pointer to remoteproc instance - * @img_data: image data which will passed to the function. - * it can be NULL, if image data doesn't need to be handled - * by the load function. E.g. binary data which was - * loaded to the target memory. - * @offset: last loaded image data offset to the start of image file - * @len: last loaded image data length - * @img_info: pointer to store image information data - * @last_load_state: the returned state of the last function call. - * @da: target device address, if the data to load is not for target memory - * the da will be set to ANY. - * @noffset: pointer to next offset required by loading ELF header - * @nlen: pointer to next data length required by loading ELF header - * @padding: value to pad it is possible that a size of a segment in memory - * is larger than what it is in the ELF image. e.g. a segment - * can have stack section .bss. It doesn't need to copy image file - * space, in this case, it will be packed with 0. - * @nmemsize: pointer to next data target memory size. The size of a segment - * in the target memory can be larger than the its size in the - * image file. - * - * return 0 for success, otherwise negative value for failure - */ -int elf_load(struct remoteproc *rproc, const void *img_data, - size_t offset, size_t len, - void **img_info, int last_load_state, - metal_phys_addr_t *da, - size_t *noffset, size_t *nlen, - unsigned char *padding, size_t *nmemsize); - -/** - * elf_release - Release ELF image information - * - * It will release ELF image information data. - * - * @img_info: pointer to ELF image information - */ -void elf_release(void *img_info); - -/** - * elf_get_entry - Get entry point - * - * It will return entry point specified in the ELF file. - * - * @img_info: pointer to ELF image information - * - * return entry address - */ -metal_phys_addr_t elf_get_entry(void *img_info); - -/** - * elf_locate_rsc_table - locate the resource table information - * - * It will return the length of the resource table, and the device address of - * the resource table. - * - * @img_info: pointer to ELF image information - * @da: pointer to the device address - * @offset: pointer to the offset to in the ELF image of the resource - * table section. - * @size: pointer to the size of the resource table section. - * - * return 0 if successfully locate the resource table, negative value for - * failure. - */ -int elf_locate_rsc_table(void *img_info, metal_phys_addr_t *da, - size_t *offset, size_t *size); - -#if defined __cplusplus -} -#endif - -#endif /* ELF_LOADER_H_ */ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ELF_LOADER_H_ +#define ELF_LOADER_H_ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* ELF32 base types - 32-bit. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* ELF64 base types - 64-bit. */ +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Size of ELF identifier field in the ELF file header. */ +#define EI_NIDENT 16 + +/* ELF32 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; + +/* ELF64 file header */ +typedef struct { + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* e_ident */ +#define ET_NONE 0 +#define ET_REL 1 /* Re-locatable file */ +#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] */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +/* + * 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 + +/* ELF32 program header */ +typedef struct elf32_phdr { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +/* ELF64 program header */ +typedef struct elf64_phdr { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + +/* segment types */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* ELF32 section header. */ +typedef struct { + Elf32_Word sh_name; + Elf32_Word sh_type; + 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; + +/* ELF64 section header. */ +typedef struct { + Elf64_Word sh_name; + Elf64_Word sh_type; + Elf64_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf64_Xword sh_size; + Elf64_Word sh_link; + Elf64_Word sh_info; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; +} Elf64_Shdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#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; + +typedef struct { + Elf64_Addr r_offset; + Elf64_Xword r_info; +} Elf64_Rel; + +/* Relocation entry with addend */ +typedef struct { + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela { + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +} Elf64_Rela; + +/* Macros to extract information from 'r_info' field of relocation entries */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) + +/* 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; + +typedef struct elf64_sym { + Elf64_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf64_Half st_shndx; + Elf64_Addr st_value; + Elf64_Xword st_size; +} Elf64_Sym; + +/* ARM specific dynamic relocation codes */ +#define R_ARM_GLOB_DAT 21 /* 0x15 */ +#define R_ARM_JUMP_SLOT 22 /* 0x16 */ +#define R_ARM_RELATIVE 23 /* 0x17 */ +#define R_ARM_ABS32 2 /* 0x02 */ + +/* ELF decoding information */ +struct elf32_info { + Elf32_Ehdr ehdr; + int load_state; + Elf32_Phdr *phdrs; + Elf32_Shdr *shdrs; + void *shstrtab; +}; + +struct elf64_info { + Elf64_Ehdr ehdr; + int load_state; + Elf64_Phdr *phdrs; + Elf64_Shdr *shdrs; + void *shstrtab; +}; + +#define ELF_STATE_INIT 0x0L +#define ELF_STATE_WAIT_FOR_PHDRS 0x100L +#define ELF_STATE_WAIT_FOR_SHDRS 0x200L +#define ELF_STATE_WAIT_FOR_SHSTRTAB 0x400L +#define ELF_STATE_HDRS_COMPLETE 0x800L +#define ELF_STATE_MASK 0xFF00L +#define ELF_NEXT_SEGMENT_MASK 0x00FFL + +extern const struct loader_ops elf_ops; + +/** + * @internal + * + * @brief Check if it is an ELF file + * + * It will check if the input image header is an ELF header. + * + * @param img_data Firmware private data which will be passed to user + * defined loader operations + * @param len Firmware header length + * + * @return 0 for success or negative value for failure. + */ +int elf_identify(const void *img_data, size_t len); + +/** + * @internal + * + * @brief Load ELF headers + * + * It will get the ELF header, the program header, and the section header. + * + * @param img_data Image data + * @param offset Input image data offset to the start of image + * file + * @param len Input image data length + * @param img_info Pointer to store image information data + * @param last_load_state Last state return by this function + * @param noffset Pointer to next offset required by loading ELF + * header + * @param nlen Pointer to next data length required by loading + * ELF header + * + * @return ELF loading header state, or negative value for failure + */ +int elf_load_header(const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + size_t *noffset, size_t *nlen); + +/** + * @internal + * + * @brief Load ELF data + * + * It will parse the ELF image and return the target device address, + * offset to the start of the ELF image of the data to load and the + * length of the data to load. + * + * @param rproc Pointer to remoteproc instance + * @param img_data Image data which will passed to the function. + * it can be NULL, if image data doesn't need to + * be handled by the load function. E.g. binary + * data which was loaded to the target memory. + * @param offset Last loaded image data offset to the start of + * image file + * @param len Last loaded image data length + * @param img_info Pointer to store image information data + * @param last_load_state The returned state of the last function call. + * @param da Target device address, if the data to load is + * not for target memory the da will be set to + * ANY. + * @param noffset Pointer to next offset required by loading ELF + * header + * @param nlen Pointer to next data length required by loading + * ELF header + * @param padding Value to pad it is possible that a size of a + * segment in memory is larger than what it is in + * the ELF image. e.g. a segment can have stack + * section .bss. It doesn't need to copy image + * file space, in this case, it will be packed + * with 0. + * @param nmemsize Pointer to next data target memory size. The + * size of a segment in the target memory can be + * larger than the its size in the image file. + * + * @return 0 for success, otherwise negative value for failure + */ +int elf_load(struct remoteproc *rproc, const void *img_data, + size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize); + +/** + * @internal + * + * @brief Release ELF image information + * + * It will release ELF image information data. + * + * @param img_info Pointer to ELF image information + */ +void elf_release(void *img_info); + +/** + * @internal + * + * @brief Get entry point + * + * It will return entry point specified in the ELF file. + * + * @param img_info Pointer to ELF image information + * + * @return Entry address + */ +metal_phys_addr_t elf_get_entry(void *img_info); + +/** + * @internal + * + * @brief Locate the resource table information + * + * It will return the length of the resource table, and the device address of + * the resource table. + * + * @param img_info Pointer to ELF image information + * @param da Pointer to the device address + * @param offset Pointer to the offset to in the ELF image of the + * resource table section. + * @param size Pointer to the size of the resource table section. + * + * @return 0 if successfully locate the resource table, negative value for + * failure. + */ +int elf_locate_rsc_table(void *img_info, metal_phys_addr_t *da, + size_t *offset, size_t *size); + +#if defined __cplusplus +} +#endif + +#endif /* ELF_LOADER_H_ */ diff --git a/libraries/openamp_arduino/src/openamp/open_amp.h b/libraries/openamp_arduino/src/openamp/open_amp.h index 1b0eeac..f5d93ed 100755 --- a/libraries/openamp_arduino/src/openamp/open_amp.h +++ b/libraries/openamp_arduino/src/openamp/open_amp.h @@ -1,17 +1,16 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef OPEN_AMP_H_ -#define OPEN_AMP_H_ - -#include "rpmsg.h" -#include "rpmsg_virtio.h" -#include "remoteproc.h" -#include "remoteproc_virtio.h" - - -#endif /* OPEN_AMP_H_ */ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef OPEN_AMP_H_ +#define OPEN_AMP_H_ + +#include +#include +#include +#include + +#endif /* OPEN_AMP_H_ */ diff --git a/libraries/openamp_arduino/src/openamp/remoteproc.h b/libraries/openamp_arduino/src/openamp/remoteproc.h index daa2c5f..23f9178 100755 --- a/libraries/openamp_arduino/src/openamp/remoteproc.h +++ b/libraries/openamp_arduino/src/openamp/remoteproc.h @@ -1,880 +1,858 @@ -/* - * Remoteproc Framework - * - * Copyright(c) 2018 Xilinx Ltd. - * Copyright(c) 2011 Texas Instruments, Inc. - * Copyright(c) 2011 Google, Inc. - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef REMOTEPROC_H -#define REMOTEPROC_H - -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -#define RSC_NOTIFY_ID_ANY 0xFFFFFFFFUL - -/** - * struct resource_table - firmware resource table header - * @ver: version number - * @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). - */ -OPENAMP_PACKED_BEGIN -struct resource_table { - uint32_t ver; - uint32_t num; - uint32_t reserved[2]; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - uint32_t offset[0]; -#pragma GCC diagnostic pop -} OPENAMP_PACKED_END; - -/** - * 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. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_hdr { - uint32_t type; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - uint8_t data[0]; -#pragma GCC diagnostic pop -} OPENAMP_PACKED_END; - -/** - * 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_VENDOR_START: start of the vendor specific resource types range - * @RSC_VENDOR_END : end of the vendor specific resource types range - * @RSC_LAST: just keep this one at the end - * - * For more details regarding a specific resource type, please see its - * 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_RPROC_MEM = 4, - RSC_FW_CHKSUM = 5, - RSC_LAST = 6, - RSC_VENDOR_START = 128, - RSC_VENDOR_END = 512, -}; - -#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) -#define FW_RSC_U32_ADDR_ANY (0xFFFFFFFF) - -/** - * struct fw_rsc_carveout - physically contiguous memory request - * @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). - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_carveout { - uint32_t type; - uint32_t da; - uint32_t pa; - uint32_t len; - uint32_t flags; - uint32_t reserved; - uint8_t name[32]; -} OPENAMP_PACKED_END; - -/** - * 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. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_devmem { - uint32_t type; - uint32_t da; - uint32_t pa; - uint32_t len; - uint32_t flags; - uint32_t reserved; - uint8_t name[32]; -} OPENAMP_PACKED_END; - -/** - * 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..). - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_trace { - uint32_t type; - uint32_t da; - uint32_t len; - uint32_t reserved; - uint8_t name[32]; -} OPENAMP_PACKED_END; - -/** - * 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. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_vdev_vring { - uint32_t da; - uint32_t align; - uint32_t num; - uint32_t notifyid; - uint32_t reserved; -} OPENAMP_PACKED_END; - -/** - * 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. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_vdev { - uint32_t type; - uint32_t id; - uint32_t notifyid; - uint32_t dfeatures; - uint32_t gfeatures; - uint32_t config_len; - uint8_t status; - uint8_t num_of_vrings; - uint8_t reserved[2]; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - struct fw_rsc_vdev_vring vring[0]; -#pragma GCC diagnostic pop -} OPENAMP_PACKED_END; - -/** - * struct fw_rsc_vendor - remote processor vendor specific resource - * @len: length of the resource - * - * This resource entry tells the host the vendor specific resource - * required by the remote. - * - * These request entries should precede other shared resource entries - * such as vdevs, vrings. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_vendor { - uint32_t type; - uint32_t len; -} OPENAMP_PACKED_END; - -/** - * struct fw_rsc_rproc_mem - remote processor memory - * @da: device address - * @pa: physical address - * @len: length (in bytes) - * @reserved: reserved (must be zero) - * - * This resource entry tells the host to the remote processor - * memory that the host can be used as shared memory. - * - * These request entries should precede other shared resource entries - * such as vdevs, vrings. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_rproc_mem { - uint32_t type; - uint32_t da; - uint32_t pa; - uint32_t len; - uint32_t reserved; -} OPENAMP_PACKED_END; - -/* - * struct fw_rsc_fw_chksum - firmware checksum - * @algo: algorithm to generate the cheksum - * @chksum: checksum of the firmware loadable sections. - * - * This resource entry provides checksum for the firmware loadable sections. - * It is used to check if the remote already runs with the expected firmware to - * decide if it needs to start the remote if the remote is already running. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_fw_chksum { - uint32_t type; - uint8_t algo[16]; - uint8_t chksum[64]; -} OPENAMP_PACKED_END; - -struct loader_ops; -struct image_store_ops; -struct remoteproc_ops; - -/** - * struct remoteproc_mem - * - * This structure presents the memory used by the remote processor - * - * @da: device memory - * @pa: physical memory - * @size: size of the memory - * @io: pointer to the I/O region - * @node: list node - */ -struct remoteproc_mem { - metal_phys_addr_t da; - metal_phys_addr_t pa; - size_t size; - char name[32]; - struct metal_io_region *io; - struct metal_list node; -}; - -/** - * struct remoteproc - * - * This structure is maintained by the remoteproc to represent the remote - * processor instance. This structure acts as a prime parameter to use - * the remoteproc APIs. - * - * @bootadd: boot address - * @loader: executable loader - * @lock: mutext lock - * @ops: remoteproc operations - * @rsc_table: pointer to resource table - * @rsc_len: length of resource table - * @rsc_io: metal I/O region of resource table - * @mems: remoteproc memories - * @vdevs: remoteproc virtio devices - * @bitmap: bitmap for notify IDs for remoteproc subdevices - * @state: remote processor state - * @priv: private data - */ -struct remoteproc { - metal_mutex_t lock; - void *rsc_table; - size_t rsc_len; - struct metal_io_region *rsc_io; - struct metal_list mems; - struct metal_list vdevs; - unsigned long bitmap; - struct remoteproc_ops *ops; - metal_phys_addr_t bootaddr; - struct loader_ops *loader; - unsigned int state; - void *priv; -}; - -/** - * struct remoteproc_ops - * - * remoteproc operations needs to be implemented by each remoteproc driver - * - * @init: initialize the remoteproc instance - * @remove: remove the remoteproc instance - * @mmap: memory mapped the mempory with physical address or destination - * address as input. - * @handle_rsc: handle the vendor specific resource - * @config: configure the remoteproc to make it ready to load and run - * executable - * @start: kick the remoteproc to run application - * @stop: stop the remoteproc from running application, the resource such as - * memory may not be off. - * @shutdown: shutdown the remoteproc and release its resources. - * @notify: notify the remote - */ -struct remoteproc_ops { - struct remoteproc *(*init)(struct remoteproc *rproc, - struct remoteproc_ops *ops, void *arg); - void (*remove)(struct remoteproc *rproc); - void *(*mmap)(struct remoteproc *rproc, - metal_phys_addr_t *pa, metal_phys_addr_t *da, - size_t size, unsigned int attribute, - struct metal_io_region **io); - int (*handle_rsc)(struct remoteproc *rproc, void *rsc, size_t len); - int (*config)(struct remoteproc *rproc, void *data); - int (*start)(struct remoteproc *rproc); - int (*stop)(struct remoteproc *rproc); - int (*shutdown)(struct remoteproc *rproc); - int (*notify)(struct remoteproc *rproc, uint32_t id); -}; - -/* Remoteproc error codes */ -#define RPROC_EBASE 0 -#define RPROC_ENOMEM (RPROC_EBASE + 1) -#define RPROC_EINVAL (RPROC_EBASE + 2) -#define RPROC_ENODEV (RPROC_EBASE + 3) -#define RPROC_EAGAIN (RPROC_EBASE + 4) -#define RPROC_ERR_RSC_TAB_TRUNC (RPROC_EBASE + 5) -#define RPROC_ERR_RSC_TAB_VER (RPROC_EBASE + 6) -#define RPROC_ERR_RSC_TAB_RSVD (RPROC_EBASE + 7) -#define RPROC_ERR_RSC_TAB_VDEV_NRINGS (RPROC_EBASE + 9) -#define RPROC_ERR_RSC_TAB_NP (RPROC_EBASE + 10) -#define RPROC_ERR_RSC_TAB_NS (RPROC_EBASE + 11) -#define RPROC_ERR_LOADER_STATE (RPROC_EBASE + 12) -#define RPROC_EMAX (RPROC_EBASE + 16) -#define RPROC_EPTR (void *)(-1) -#define RPROC_EOF (void *)(-1) - -static inline long RPROC_PTR_ERR(const void *ptr) -{ - return (long)ptr; -} - -static inline int RPROC_IS_ERR(const void *ptr) -{ - if ((unsigned long)ptr >= (unsigned long)(-RPROC_EMAX)) - return 1; - else - return 0; -} - -static inline void *RPROC_ERR_PTR(long error) -{ - return (void *)error; -} - -/** - * enum rproc_state - remote processor states - * @RPROC_OFFLINE: remote is offline - * @RPROC_READY: remote is ready to start - * @RPROC_RUNNING: remote is up and running - * @RPROC_SUSPENDED: remote is suspended - * @RPROC_ERROR: remote has error; need to recover - * @RPROC_STOPPED: remote is stopped - * @RPROC_LAST: just keep this one at the end - */ -enum remoteproc_state { - RPROC_OFFLINE = 0, - RPROC_CONFIGURED = 1, - RPROC_READY = 2, - RPROC_RUNNING = 3, - RPROC_SUSPENDED = 4, - RPROC_ERROR = 5, - RPROC_STOPPED = 6, - RPROC_LAST = 7, -}; - -/** - * remoteproc_init - * - * Initializes remoteproc resource. - * - * @rproc - pointer to remoteproc instance - * @ops - pointer to remoteproc operations - * @priv - pointer to private data - * - * @returns created remoteproc pointer - */ -struct remoteproc *remoteproc_init(struct remoteproc *rproc, - struct remoteproc_ops *ops, void *priv); - -/** - * remoteproc_remove - * - * Remove remoteproc resource - * - * @rproc - pointer to remoteproc instance - * - * returns 0 for success, negative value for failure - */ -int remoteproc_remove(struct remoteproc *rproc); - -/** - * remoteproc_init_mem - * - * Initialize remoteproc memory - * - * @mem - pointer to remoteproc memory - * @char - memory name - * @pa - physcial address - * @da - device address - * @size - memory size - * @io - pointer to the I/O region - */ -static inline void -remoteproc_init_mem(struct remoteproc_mem *mem, const char *name, - metal_phys_addr_t pa, metal_phys_addr_t da, - size_t size, struct metal_io_region *io) -{ - if (!mem) - return; - if (name) - strncpy(mem->name, name, sizeof(mem->name)); - else - mem->name[0] = 0; - mem->pa = pa; - mem->da = da; - mem->io = io; - mem->size = size; -} - -/** - * remoteproc_add_mem - * - * Add remoteproc memory - * - * @rproc - pointer to remoteproc - * @mem - pointer to remoteproc memory - */ -static inline void -remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem) -{ - if (!rproc || !mem) - return; - metal_list_add_tail(&rproc->mems, &mem->node); -} - -/** - * remoteproc_get_io_with_name - * - * get remoteproc memory I/O region with name - * - * @rproc - pointer to the remote processor - * @name - name of the shared memory - * @io - pointer to the pointer of the I/O region - * - * returns metal I/O region pointer, NULL for failure - */ -struct metal_io_region * -remoteproc_get_io_with_name(struct remoteproc *rproc, - const char *name); - -/** - * remoteproc_get_io_with_pa - * - * get remoteproc memory I/O region with physical address - * - * @rproc - pointer to the remote processor - * @pa - physical address - * - * returns metal I/O region pointer, NULL for failure - */ -struct metal_io_region * -remoteproc_get_io_with_pa(struct remoteproc *rproc, - metal_phys_addr_t pa); - -/** - * remoteproc_get_io_with_da - * - * get remoteproc memory I/O region with device address - * - * @rproc - pointer to the remote processor - * @da - device address - * @offset - I/O region offset of the device address - * - * returns metal I/O region pointer, NULL for failure - */ -struct metal_io_region * -remoteproc_get_io_with_da(struct remoteproc *rproc, - metal_phys_addr_t da, - unsigned long *offset); - -/** - * remoteproc_get_io_with_va - * - * get remoteproc memory I/O region with virtual address - * - * @rproc - pointer to the remote processor - * @va - virtual address - * - * returns metal I/O region pointer, NULL for failure - */ -struct metal_io_region * -remoteproc_get_io_with_va(struct remoteproc *rproc, - void *va); - -/** - * remoteproc_mmap - * - * remoteproc mmap memory - * - * @rproc - pointer to the remote processor - * @pa - physical address pointer - * @da - device address pointer - * @size - size of the memory - * @attribute - memory attribute - * @io - pointer to the I/O region - * - * returns pointer to the memory - */ -void *remoteproc_mmap(struct remoteproc *rproc, - metal_phys_addr_t *pa, metal_phys_addr_t *da, - size_t size, unsigned int attribute, - struct metal_io_region **io); - -/** - * remoteproc_parse_rsc_table - * - * Parse resource table of remoteproc - * - * @rproc - pointer to remoteproc instance - * @rsc_table - pointer to resource table - * @rsc_size - resource table size - * - * returns 0 for success and negative value for errors - */ -int remoteproc_parse_rsc_table(struct remoteproc *rproc, - struct resource_table *rsc_table, - size_t rsc_size); - -/** - * remoteproc_set_rsc_table - * - * Parse and set resource table of remoteproc - * - * @rproc - pointer to remoteproc instance - * @rsc_table - pointer to resource table - * @rsc_size - resource table size - * - * returns 0 for success and negative value for errors - */ -int remoteproc_set_rsc_table(struct remoteproc *rproc, - struct resource_table *rsc_table, - size_t rsc_size); - -/** - * remoteproc_config - * - * This function configures the remote processor to get it - * ready to load and run executable. - * - * @rproc - pointer to remoteproc instance to start - * @data - configuration data - * - * returns 0 for success and negative value for errors - */ -int remoteproc_config(struct remoteproc *rproc, void *data); - -/** - * remoteproc_start - * - * This function starts the remote processor. - * It assumes the firmware is already loaded, - * - * @rproc - pointer to remoteproc instance to start - * - * returns 0 for success and negative value for errors - */ -int remoteproc_start(struct remoteproc *rproc); - -/** - * remoteproc_stop - * - * This function stops the remote processor but it - * will not release its resource. - * - * @rproc - pointer to remoteproc instance - * - * returns 0 for success and negative value for errors - */ -int remoteproc_stop(struct remoteproc *rproc); - -/** - * remoteproc_shutdown - * - * This function shutdown the remote processor and - * release its resources. - * - * @rproc - pointer to remoteproc instance - * - * returns 0 for success and negative value for errors - */ -int remoteproc_shutdown(struct remoteproc *rproc); - -/** - * remoteproc_load - * - * load executable, it expects the user application defines how to - * open the executable file and how to get data from the executable file - * and how to load data to the target memory. - * - * @rproc: pointer to the remoteproc instance - * @path: optional path to the image file - * @store: pointer to user defined image store argument - * @store_ops: pointer to image store operations - * @image_info: pointer to memory which stores image information used - * by remoteproc loader - * - * return 0 for success and negative value for failure - */ -int remoteproc_load(struct remoteproc *rproc, const char *path, - void *store, struct image_store_ops *store_ops, - void **img_info); - -/** - * remoteproc_load_noblock - * - * load executable, it expects the caller has loaded image data to local - * memory and passed to the this function. If the function needs more - * image data it will return the next expected image data offset and - * the next expected image data length. If the function requires the - * caller to download image data to the target memory, it will also - * return the target physical address besides the offset and length. - * This function can be used to load firmware in stream mode. In this - * mode, you cannot do seek to the executable file. If the executable - * is ELF, it cannot get the resource table section before it loads - * the full ELF file. Furthermore, application usually don't store - * the data which is loaded to local memory in streaming mode, and - * thus, in this mode, it will load the binrary to the target memory - * before it gets the resource table. And thus, when calling this funciton - * don't put the target exectuable memory in the resource table, as - * this function will parse the resource table after it loads the binary - * to target memory. - * - * @rproc: pointer to the remoteproc instance - * @img_data: pointer to image data for remoteproc loader to parse - * @offset: image data offset to the beginning of the image file - * @len: image data length - * @image_info: pointer to memory which stores image information used - * by remoteproc loader - * @pa: pointer to the target memory physical address. If the next expected - * data doesn't need to load to the target memory, the function will - * set it to ANY. - * @io: pointer to the target memory physical address. If the next expected - * data doesn't need to load to the target memory, the function will - * set it to ANY. - * @noffset: pointer to the next image data offset to the beginning of - * the image file needs to load to local or to the target - * memory. - * @nlen: pointer to the next image data length needs to load to local - * or to the target memory. - * @nmlen: pointer to the memory size. It is only used when the next - * expected data is going to be loaded to the target memory. E.g. - * in ELF, it is possible that loadable segment in memory is - * larger that the segment data in the ELF file. In this case, - * application will need to pad the rest of the memory with - * padding. - * @padding: pointer to the padding value. It is only used when the next - * expected data is going to be loaded to the target memory. - * and the target memory size is larger than the segment data in - * the executable file. - * - * return 0 for success and negative value for failure - */ -int remoteproc_load_noblock(struct remoteproc *rproc, - const void *img_data, size_t offset, size_t len, - void **img_info, - metal_phys_addr_t *pa, struct metal_io_region **io, - size_t *noffset, size_t *nlen, - size_t *nmlen, unsigned char *padding); - -/** - * remoteproc_allocate_id - * - * allocate notifyid for resource - * - * @rproc - pointer to the remoteproc instance - * @start - start of the id range - * @end - end of the id range - * - * return allocated notify id - */ -unsigned int remoteproc_allocate_id(struct remoteproc *rproc, - unsigned int start, - unsigned int end); - -/* remoteproc_create_virtio - * - * create virtio device, it returns pointer to the created virtio device. - * - * @rproc: pointer to the remoteproc instance - * @vdev_id: virtio device ID - * @role: virtio device role - * @rst_cb: virtio device reset callback - * - * return pointer to the created virtio device, NULL for failure. - */ -struct virtio_device * -remoteproc_create_virtio(struct remoteproc *rproc, - int vdev_id, unsigned int role, - void (*rst_cb)(struct virtio_device *vdev)); - -/* remoteproc_remove_virtio - * - * Remove virtio device - * - * @rproc: pointer to the remoteproc instance - * @vdev: pointer to the virtio device - * - */ -void remoteproc_remove_virtio(struct remoteproc *rproc, - struct virtio_device *vdev); - -/* remoteproc_get_notification - * - * remoteproc is got notified, it will check its subdevices - * for the notification - * - * @rproc - pointer to the remoteproc instance - * @notifyid - notificatin id - * - * return 0 for succeed, negative value for failure - */ -int remoteproc_get_notification(struct remoteproc *rproc, - uint32_t notifyid); -#if defined __cplusplus -} -#endif - -#endif /* REMOTEPROC_H_ */ +/* + * Remoteproc Framework + * + * Copyright(c) 2018 Xilinx Ltd. + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, Inc. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef REMOTEPROC_H +#define REMOTEPROC_H + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#define RSC_NOTIFY_ID_ANY 0xFFFFFFFFU + +#define RPROC_MAX_NAME_LEN 32 + +/** + * @brief Resource table header + * + * A resource table is essentially a list of system resources required + * by the remote remoteproc. It may also include configuration entries. + * If needed, the remote remoteproc firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * Some resource entries are mere announcements, where the host is informed + * of specific remoteproc configurations. 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. + */ +METAL_PACKED_BEGIN +struct resource_table { + /** Version number */ + uint32_t ver; + + /** Number of resource entries */ + uint32_t num; + + /** Reserved (must be zero) */ + uint32_t reserved[2]; + + /** Array of offsets pointing at the various resource entries */ + uint32_t offset[0]; +} METAL_PACKED_END; + +/** + * @brief Resource table entry header + * + * Every resource entry begins with this firmware resource header providing + * its \ref type. The content of the entry itself will immediately follow + * this header, and it should be parsed according to the resource type. + */ +METAL_PACKED_BEGIN +struct fw_rsc_hdr { + /** Resource type matching the type field of the structure in \ref data */ + uint32_t type; + + /** Resource data */ + uint8_t data[0]; +} METAL_PACKED_END; + +/** + * 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 remoteproc will be writing logs. + * @RSC_VDEV: declare support for a virtio device, and serve as its + * virtio header. + * @RSC_VENDOR_START: start of the vendor specific resource types range + * @RSC_VENDOR_END : end of the vendor specific resource types range + * @RSC_LAST: just keep this one at the end + * + * For more details regarding a specific resource type, please see its + * 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, + RSC_VENDOR_START = 128, + RSC_VENDOR_END = 512, +}; + +#define FW_RSC_U64_ADDR_ANY 0xFFFFFFFFFFFFFFFFUL +#define FW_RSC_U32_ADDR_ANY 0xFFFFFFFFUL + +/** + * @brief Resource table physically contiguous memory request entry + * + * 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 \ref da should specify + * the expected device address of this memory region. If \ref da is set to + * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then + * overwrite \ref da with the dynamically allocated address. + * + * We will always use \ref 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 remoteprocs need 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 \ref pa with the dynamically allocated physical address. + * Generally we don't want to expose physical addresses if we don't have to + * (remote remoteprocs are generally _not_ trusted), so we might want to + * change this to happen _only_ when explicitly required by the hardware. + */ +METAL_PACKED_BEGIN +struct fw_rsc_carveout { + /** Resource carveout has type 0 */ + uint32_t type; + + /** Device address */ + uint32_t da; + + /** Physical address */ + uint32_t pa; + + /** Length in bytes */ + uint32_t len; + + /** IOMMU protection flags */ + uint32_t flags; + + /** Reserved (must be zero) */ + uint32_t reserved; + + /** Optional human-readable name of the requested memory region used for debugging */ + uint8_t name[RPROC_MAX_NAME_LEN]; +} METAL_PACKED_END; + +/** + * @brief Resource table IOMMU mapping request entry + * + * This resource entry requests the host to IOMMU map a physically contiguous + * memory region. This is needed in case the remote remoteproc requires + * access to certain memory-based peripherals; _never_ use it to access + * regular memory. + * + * This is obviously only needed if the remote remoteproc is accessing memory + * via an IOMMU. + * + * 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. + */ +METAL_PACKED_BEGIN +struct fw_rsc_devmem { + /** IOMMU mapping request has type 1 */ + uint32_t type; + + /** Device address */ + uint32_t da; + + /** Physical address to map */ + uint32_t pa; + + /** Length of the mapping in bytes */ + uint32_t len; + + /** IOMMU protection flags */ + uint32_t flags; + + /** Reserved (must be zero) */ + uint32_t reserved; + + /** Optional human-readable name of the requested memory region used for debugging */ + uint8_t name[RPROC_MAX_NAME_LEN]; +} METAL_PACKED_END; + +/** + * @brief Resource table trace buffer declaration entry + * + * This resource entry provides the host information about a trace buffer + * into which the remote remoteproc will write log messages. + * + * After booting the remote remoteproc, the trace buffers are exposed to the + * user via debugfs entries (called trace0, trace1, etc..). + */ +METAL_PACKED_BEGIN +struct fw_rsc_trace { + /** Trace buffer entry has type 2 */ + uint32_t type; + + /** Device address of the buffer */ + uint32_t da; + + /** Length of the buffer in bytes */ + uint32_t len; + + /** Reserved (must be zero) */ + uint32_t reserved; + + /** Optional human-readable name of the requested memory region used for debugging */ + uint8_t name[RPROC_MAX_NAME_LEN]; +} METAL_PACKED_END; + +/** + * @brief Resource table vring descriptor entry + * + * This descriptor is not a resource entry by itself; it is part of the + * \ref fw_rsc_vdev resource type. + */ +METAL_PACKED_BEGIN +struct fw_rsc_vdev_vring { + /** + * The device address where the remoteproc is expecting the vring, or + * FW_RSC_U32_ADDR_ANY/FW_RSC_U64_ADDR_ANY to indicate that dynamic + * allocation of the vring's device address is supported + */ + uint32_t da; + + /** The alignment between the consumer and producer parts of the vring */ + uint32_t align; + + /** Number of buffers supported by this vring (must be power of two) */ + uint32_t num; + + /** + * A unique rproc-wide notify index for this vring. This notify index is + * used when kicking a remote remoteproc, to let it know that this vring + * is triggered + */ + uint32_t notifyid; + + /** Reserved (must be zero) */ + uint32_t reserved; +} METAL_PACKED_END; + +/** + * @brief Resource table virtio device entry + * + * This resource is a virtio device header: it provides information about + * the vdev, and is then used by the host and its peer remote remoteprocs + * 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 + * remoteprocs. 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. + * + * 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). + */ +METAL_PACKED_BEGIN +struct fw_rsc_vdev { + /** Virtio device header has type 3 */ + uint32_t type; + + /** Virtio device id (as in virtio_ids.h) */ + uint32_t id; + + /** + * A unique rproc-wide notify index for this vdev. This notify index is + * used when kicking a remote remoteproc, to let it know that the + * status/features of this vdev have changes. + */ + uint32_t notifyid; + + /** The virtio device features supported by the firmware */ + uint32_t dfeatures; + + /** + * A place holder used by the host to write back the negotiated features + * that are supported by both sides + */ + uint32_t gfeatures; + + /** + * The size of the virtio config space of this vdev. The config space lies + * in the resource table immediate after this vdev header + */ + uint32_t config_len; + + /** A place holder where the host will indicate its virtio progress */ + uint8_t status; + + /** Number of vrings described in this vdev header */ + uint8_t num_of_vrings; + + /** Reserved (must be zero) */ + uint8_t reserved[2]; + + /** An array of \ref num_of_vrings entries of \ref fw_rsc_vdev_vring */ + struct fw_rsc_vdev_vring vring[0]; +} METAL_PACKED_END; + +/** + * @brief Resource table remote processor vendor specific entry + * + * This resource entry tells the host the vendor specific resource + * required by the remote. + * + * These request entries should precede other shared resource entries + * such as vdevs, vrings. + */ +METAL_PACKED_BEGIN +struct fw_rsc_vendor { + /** Vendor specific resource type can be values 128-512 */ + uint32_t type; + + /** Length of the resource */ + uint32_t len; +} METAL_PACKED_END; + +struct loader_ops; +struct image_store_ops; +struct remoteproc_ops; + +/** @brief Memory used by the remote processor */ +struct remoteproc_mem { + /** Device memory */ + metal_phys_addr_t da; + + /** Physical memory */ + metal_phys_addr_t pa; + + /** Size of the memory */ + size_t size; + + /** Optional human-readable name of the memory region */ + char name[RPROC_MAX_NAME_LEN]; + + /** Pointer to the I/O region */ + struct metal_io_region *io; + + /** List node */ + struct metal_list node; +}; + +/** + * @brief A remote processor instance + * + * 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. + */ +struct remoteproc { + /** Mutex lock */ + metal_mutex_t lock; + + /** Pointer to the resource table */ + void *rsc_table; + + /** Length of the resource table */ + size_t rsc_len; + + /** Metal I/O region of the resource table */ + struct metal_io_region *rsc_io; + + /** Remoteproc memories */ + struct metal_list mems; + + /** Remoteproc virtio devices */ + struct metal_list vdevs; + + /** Bitmap for notify IDs for remoteproc subdevices */ + unsigned long bitmap; + + /** Remoteproc operations */ + const struct remoteproc_ops *ops; + + /** Boot address */ + metal_phys_addr_t bootaddr; + + /** Executable loader */ + const struct loader_ops *loader; + + /** Remote processor state */ + unsigned int state; + + /** Private data */ + void *priv; +}; + +/** + * @brief Remoteproc operations to manage a remoteproc instance + * + * Remoteproc operations need to be implemented by each remoteproc driver + */ +struct remoteproc_ops { + /** Initialize the remoteproc instance */ + struct remoteproc *(*init)(struct remoteproc *rproc, + const struct remoteproc_ops *ops, void *arg); + + /** Remove the remoteproc instance */ + void (*remove)(struct remoteproc *rproc); + + /** Memory map the memory with physical address or destination address as input */ + void *(*mmap)(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io); + + /** Handle the vendor specific resource */ + int (*handle_rsc)(struct remoteproc *rproc, void *rsc, size_t len); + + /** Configure the remoteproc to make it ready to load and run the executable */ + int (*config)(struct remoteproc *rproc, void *data); + + /** Kick the remoteproc to run the application */ + int (*start)(struct remoteproc *rproc); + + /** + * Stop the remoteproc from running the application, the resource such as + * memory may not be off + */ + int (*stop)(struct remoteproc *rproc); + + /** Shutdown the remoteproc and release its resources */ + int (*shutdown)(struct remoteproc *rproc); + + /** Notify the remote */ + int (*notify)(struct remoteproc *rproc, uint32_t id); + + /** + * @brief Get remoteproc memory I/O region by either name, virtual + * address, physical address or device address. + * + * @param rproc Pointer to remoteproc instance + * @param name Memory name + * @param pa Physical address + * @param da Device address + * @param va Virtual address + * @param size Memory size + * @param buf Pointer to remoteproc_mem struct object to store result + * + * @return remoteproc memory pointed by buf if success, otherwise NULL + */ + struct remoteproc_mem *(*get_mem)(struct remoteproc *rproc, + const char *name, + metal_phys_addr_t pa, + metal_phys_addr_t da, + void *va, size_t size, + struct remoteproc_mem *buf); +}; + +/* Remoteproc error codes */ +#define RPROC_EBASE 0 +#define RPROC_ENOMEM (RPROC_EBASE + 1) +#define RPROC_EINVAL (RPROC_EBASE + 2) +#define RPROC_ENODEV (RPROC_EBASE + 3) +#define RPROC_EAGAIN (RPROC_EBASE + 4) +#define RPROC_ERR_RSC_TAB_TRUNC (RPROC_EBASE + 5) +#define RPROC_ERR_RSC_TAB_VER (RPROC_EBASE + 6) +#define RPROC_ERR_RSC_TAB_RSVD (RPROC_EBASE + 7) +#define RPROC_ERR_RSC_TAB_VDEV_NRINGS (RPROC_EBASE + 9) +#define RPROC_ERR_RSC_TAB_NP (RPROC_EBASE + 10) +#define RPROC_ERR_RSC_TAB_NS (RPROC_EBASE + 11) +#define RPROC_ERR_LOADER_STATE (RPROC_EBASE + 12) +#define RPROC_EMAX (RPROC_EBASE + 16) +#define RPROC_EPTR (void *)(-1) +#define RPROC_EOF (void *)(-1) + +static inline long RPROC_PTR_ERR(const void *ptr) +{ + return (long)ptr; +} + +static inline int RPROC_IS_ERR(const void *ptr) +{ + if ((unsigned long)ptr >= (unsigned long)(-RPROC_EMAX)) + return 1; + else + return 0; +} + +static inline void *RPROC_ERR_PTR(long error) +{ + return (void *)error; +} + +/** + * enum rproc_state - remote processor states + * @RPROC_OFFLINE: remote is offline + * @RPROC_CONFIGURED: remote is configured + * @RPROC_READY: remote is ready to start + * @RPROC_RUNNING: remote is up and running + * @RPROC_SUSPENDED: remote is suspended + * @RPROC_ERROR: remote has error; need to recover + * @RPROC_STOPPED: remote is stopped + * @RPROC_LAST: just keep this one at the end + */ +enum remoteproc_state { + RPROC_OFFLINE = 0, + RPROC_CONFIGURED = 1, + RPROC_READY = 2, + RPROC_RUNNING = 3, + RPROC_SUSPENDED = 4, + RPROC_ERROR = 5, + RPROC_STOPPED = 6, + RPROC_LAST = 7, +}; + +/** + * @brief Initializes remoteproc resource. + * + * @param rproc Pointer to remoteproc instance + * @param ops Pointer to remoteproc operations + * @param priv Pointer to private data + * + * @return Created remoteproc pointer + */ +struct remoteproc *remoteproc_init(struct remoteproc *rproc, + const struct remoteproc_ops *ops, + void *priv); + +/** + * @brief Remove remoteproc resource + * + * @param rproc Pointer to remoteproc instance + * + * @return 0 for success, negative value for failure + */ +int remoteproc_remove(struct remoteproc *rproc); + +/** + * @brief Initialize remoteproc memory + * + * @param mem Pointer to remoteproc memory + * @param name Memory name + * @param pa Physical address + * @param da Device address + * @param size Memory size + * @param io Pointer to the I/O region + */ +static inline void +remoteproc_init_mem(struct remoteproc_mem *mem, const char *name, + metal_phys_addr_t pa, metal_phys_addr_t da, + size_t size, struct metal_io_region *io) +{ + if (!mem || !io || size == 0) + return; + if (name) + strncpy(mem->name, name, sizeof(mem->name)); + else + mem->name[0] = 0; + mem->pa = pa; + mem->da = da; + mem->io = io; + mem->size = size; +} + +/** + * @brief Add remoteproc memory + * + * @param rproc Pointer to remoteproc + * @param mem Pointer to remoteproc memory + */ +static inline void +remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem) +{ + if (!rproc || !mem) + return; + metal_list_add_tail(&rproc->mems, &mem->node); +} + +/** + * @brief Get remoteproc memory I/O region with name + * + * @param rproc Pointer to the remote processor + * @param name Name of the shared memory + * + * @return Metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_name(struct remoteproc *rproc, + const char *name); + +/** + * @brief Get remoteproc memory I/O region with physical address + * + * @param rproc Pointer to the remote processor + * @param pa Physical address + * + * @return Metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_pa(struct remoteproc *rproc, + metal_phys_addr_t pa); + +/** + * @brief Get remoteproc memory I/O region with device address + * + * @param rproc Pointer to the remote processor + * @param da Device address + * @param offset I/O region offset of the device address + * + * @return Metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_da(struct remoteproc *rproc, + metal_phys_addr_t da, + unsigned long *offset); + +/** + * @brief Get remoteproc memory I/O region with virtual address + * + * @param rproc Pointer to the remote processor + * @param va Virtual address + * + * @return Metal I/O region pointer, NULL for failure + */ +struct metal_io_region * +remoteproc_get_io_with_va(struct remoteproc *rproc, + void *va); + +/** + * @brief Remoteproc mmap memory + * + * @param rproc Pointer to the remote processor + * @param pa Physical address pointer + * @param da Device address pointer + * @param size Size of the memory + * @param attribute Memory attribute + * @param io Pointer to the I/O region + * + * @return Pointer to the memory + */ +void *remoteproc_mmap(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io); + +/** + * @brief Parse and set resource table of remoteproc + * + * @param rproc Pointer to remoteproc instance + * @param rsc_table Pointer to resource table + * @param rsc_size Resource table size + * + * @return 0 for success and negative value for errors + */ +int remoteproc_set_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size); + +/** + * @brief This function configures the remote processor to get it + * ready to load and run executable. + * + * @param rproc Pointer to remoteproc instance to start + * @param data Configuration data + * + * @return 0 for success and negative value for errors + */ +int remoteproc_config(struct remoteproc *rproc, void *data); + +/** + * @brief This function starts the remote processor. + * It assumes the firmware is already loaded. + * + * @param rproc Pointer to remoteproc instance to start + * + * @return 0 for success and negative value for errors + */ +int remoteproc_start(struct remoteproc *rproc); + +/** + * @brief This function stops the remote processor but it + * will not release its resource. + * + * @param rproc Pointer to remoteproc instance + * + * @return 0 for success and negative value for errors + */ +int remoteproc_stop(struct remoteproc *rproc); + +/** + * @brief This function shuts down the remote processor and + * releases its resources. + * + * @param rproc Pointer to remoteproc instance + * + * @return 0 for success and negative value for errors + */ +int remoteproc_shutdown(struct remoteproc *rproc); + +/** + * @brief Loads the executable + * + * Expects the user application defines how to open the executable file and how + * to get data from the executable file and how to load data to the target + * memory. + * + * @param rproc Pointer to the remoteproc instance + * @param path Optional path to the image file + * @param store Pointer to user defined image store argument + * @param store_ops Pointer to image store operations + * @param img_info Pointer to memory which stores image information used + * by remoteproc loader + * + * @return 0 for success and negative value for failure + */ +int remoteproc_load(struct remoteproc *rproc, const char *path, + void *store, const struct image_store_ops *store_ops, + void **img_info); + +/** + * @brief Loads the executable + * + * Expects the caller has loaded image data to local + * memory and passed to the this function. If the function needs more + * image data it will return the next expected image data offset and + * the next expected image data length. If the function requires the + * caller to download image data to the target memory, it will also + * return the target physical address besides the offset and length. + * This function can be used to load firmware in stream mode. In this + * mode, you cannot do seek to the executable file. If the executable + * is ELF, it cannot get the resource table section before it loads + * the full ELF file. Furthermore, application usually don't store + * the data which is loaded to local memory in streaming mode, and + * thus, in this mode, it will load the binary to the target memory + * before it gets the resource table. And thus, when calling this function + * don't put the target executable memory in the resource table, as + * this function will parse the resource table after it loads the binary + * to target memory. + * + * @param rproc Pointer to the remoteproc instance + * @param img_data Pointer to image data for remoteproc loader to parse + * @param offset Image data offset to the beginning of the image file + * @param len Image data length + * @param img_info Pointer to memory which stores image information used + * by remoteproc loader + * @param pa Pointer to the target memory physical address. If the + * next expected data doesn't need to load to the target + * memory, the function will set it to ANY. + * @param io Pointer to the io region. If the next expected data + * doesn't need to load to the target memory, the function + * will set it to NULL. + * @param noffset Pointer to the next image data offset to the beginning + * of the image file needs to load to local or to the + * target memory. + * @param nlen Pointer to the next image data length needs to load to + * local or to the target memory. + * @param nmlen Pointer to the memory size. It is only used when the + * next expected data is going to be loaded to the target + * memory. E.g. in ELF, it is possible that loadable + * segment in memory is larger that the segment data in + * the ELF file. In this case, application will need to + * pad the rest of the memory with padding. + * @param padding Pointer to the padding value. It is only used when the + * next expected data is going to be loaded to the target + * memory and the target memory size is larger than the + * segment data in the executable file. + * + * @return 0 for success and negative value for failure + */ +int remoteproc_load_noblock(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, + metal_phys_addr_t *pa, struct metal_io_region **io, + size_t *noffset, size_t *nlen, + size_t *nmlen, unsigned char *padding); + +/** + * @brief Allocate notifyid for resource + * + * @param rproc Pointer to the remoteproc instance + * @param start Start of the id range + * @param end End of the id range + * + * @return Allocated notify id + */ +unsigned int remoteproc_allocate_id(struct remoteproc *rproc, + unsigned int start, + unsigned int end); + +/** + * @brief Create virtio device, it returns pointer to the created virtio + * device. + * + * @param rproc Pointer to the remoteproc instance + * @param vdev_id virtio device ID + * @param role virtio device role + * @param rst_cb virtio device reset callback + * + * @return Pointer to the created virtio device, NULL for failure. + */ +struct virtio_device * +remoteproc_create_virtio(struct remoteproc *rproc, + int vdev_id, unsigned int role, + void (*rst_cb)(struct virtio_device *vdev)); + +/** + * @brief Remove virtio device + * + * @param rproc Pointer to the remoteproc instance + * @param vdev Pointer to the virtio device + */ +void remoteproc_remove_virtio(struct remoteproc *rproc, + struct virtio_device *vdev); + +/** + * @brief remoteproc is got notified, it will check its subdevices + * for the notification + * + * @param rproc Pointer to the remoteproc instance + * @param notifyid Notification id + * + * @return 0 for succeed, negative value for failure + */ +int remoteproc_get_notification(struct remoteproc *rproc, + uint32_t notifyid); +#if defined __cplusplus +} +#endif + +#endif /* REMOTEPROC_H_ */ diff --git a/libraries/openamp_arduino/src/openamp/remoteproc_loader.h b/libraries/openamp_arduino/src/openamp/remoteproc_loader.h index dce3dbb..d928fcf 100755 --- a/libraries/openamp_arduino/src/openamp/remoteproc_loader.h +++ b/libraries/openamp_arduino/src/openamp/remoteproc_loader.h @@ -1,108 +1,111 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/************************************************************************** - * 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 -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* Loader feature macros */ -#define SUPPORT_SEEK 1UL - -/* Remoteproc loader any address */ -#define RPROC_LOAD_ANYADDR ((metal_phys_addr_t)-1) - -/* Remoteproc loader Exectuable Image Parsing States */ -/* Remoteproc loader parser intial state */ -#define RPROC_LOADER_NOT_READY 0x0UL -/* Remoteproc loader ready to load, even it can be not finish parsing */ -#define RPROC_LOADER_READY_TO_LOAD 0x10000UL -/* Remoteproc loader post data load */ -#define RPROC_LOADER_POST_DATA_LOAD 0x20000UL -/* Remoteproc loader finished loading */ -#define RPROC_LOADER_LOAD_COMPLETE 0x40000UL -/* Remoteproc loader state mask */ -#define RPROC_LOADER_MASK 0x00FF0000UL -/* Remoteproc loader private mask */ -#define RPROC_LOADER_PRIVATE_MASK 0x0000FFFFUL -/* Remoteproc loader reserved mask */ -#define RPROC_LOADER_RESERVED_MASK 0x0F000000UL - -/** - * struct image_store_ops - user defined image store operations - * @open: user defined callback to open the "firmware" to prepare loading - * @close: user defined callback to close the "firmware" to clean up - * after loading - * @load: user defined callback to load the firmware contents to target - * memory or local memory - * @features: loader supported features. e.g. seek - */ -struct image_store_ops { - int (*open)(void *store, const char *path, const void **img_data); - void (*close)(void *store); - int (*load)(void *store, size_t offset, size_t size, - const void **data, - metal_phys_addr_t pa, - struct metal_io_region *io, char is_blocking); - unsigned int features; -}; - -/** - * struct loader_ops - loader oeprations - * @load_header: define how to get the executable headers - * @load_data: define how to load the target data - * @locate_rsc_table: define how to get the resource table target address, - * offset to the ELF image file and size of the resource - * table. - * @release: define how to release the loader - * @get_entry: get entry address - * @get_load_state: get load state from the image information - */ -struct loader_ops { - int (*load_header)(const void *img_data, size_t offset, size_t len, - void **img_info, int last_state, - size_t *noffset, size_t *nlen); - int (*load_data)(struct remoteproc *rproc, - const void *img_data, size_t offset, size_t len, - void **img_info, int last_load_state, - metal_phys_addr_t *da, - size_t *noffset, size_t *nlen, - unsigned char *padding, size_t *nmemsize); - int (*locate_rsc_table)(void *img_info, metal_phys_addr_t *da, - size_t *offset, size_t *size); - void (*release)(void *img_info); - metal_phys_addr_t (*get_entry)(void *img_info); - int (*get_load_state)(void *img_info); -}; - -#if defined __cplusplus -} -#endif - -#endif /* REMOTEPROC_LOADER_H_ */ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/************************************************************************** + * 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 +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* Loader feature macros */ +#define SUPPORT_SEEK 1UL + +/* Remoteproc loader any address */ +#define RPROC_LOAD_ANYADDR ((metal_phys_addr_t)-1) + +/* Remoteproc loader Executable Image Parsing States */ +/* Remoteproc loader parser initial state */ +#define RPROC_LOADER_NOT_READY 0x0L +/* Remoteproc loader ready to load, even it can be not finish parsing */ +#define RPROC_LOADER_READY_TO_LOAD 0x10000L +/* Remoteproc loader post data load */ +#define RPROC_LOADER_POST_DATA_LOAD 0x20000L +/* Remoteproc loader finished loading */ +#define RPROC_LOADER_LOAD_COMPLETE 0x40000L +/* Remoteproc loader state mask */ +#define RPROC_LOADER_MASK 0x00FF0000L +/* Remoteproc loader private mask */ +#define RPROC_LOADER_PRIVATE_MASK 0x0000FFFFL +/* Remoteproc loader reserved mask */ +#define RPROC_LOADER_RESERVED_MASK 0x0F000000L + +/** @brief User-defined image store operations */ +struct image_store_ops { + /** User-defined callback to open the "firmware" to prepare loading */ + int (*open)(void *store, const char *path, const void **img_data); + + /** User-defined callback to close the "firmware" to clean up after loading */ + void (*close)(void *store); + + /** User-defined callback to load the firmware contents to target memory or local memory */ + int (*load)(void *store, size_t offset, size_t size, + const void **data, + metal_phys_addr_t pa, + struct metal_io_region *io, char is_blocking); + + /** Loader supported features. e.g. seek */ + unsigned int features; +}; + +/** @brief Loader operations */ +struct loader_ops { + /** Define how to get the executable headers */ + int (*load_header)(const void *img_data, size_t offset, size_t len, + void **img_info, int last_state, + size_t *noffset, size_t *nlen); + + /** Define how to load the target data */ + int (*load_data)(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, int last_load_state, + metal_phys_addr_t *da, + size_t *noffset, size_t *nlen, + unsigned char *padding, size_t *nmemsize); + + /** + * Define how to get the resource table target address, offset to the ELF + * image file and size of the resource table + */ + int (*locate_rsc_table)(void *img_info, metal_phys_addr_t *da, + size_t *offset, size_t *size); + + /** Define how to release the loader */ + void (*release)(void *img_info); + + /** Get entry address */ + metal_phys_addr_t (*get_entry)(void *img_info); + + /** Get load state from the image information */ + int (*get_load_state)(void *img_info); +}; + +#if defined __cplusplus +} +#endif + +#endif /* REMOTEPROC_LOADER_H_ */ diff --git a/libraries/openamp_arduino/src/openamp/remoteproc_virtio.h b/libraries/openamp_arduino/src/openamp/remoteproc_virtio.h index fc1627e..0b747ca 100755 --- a/libraries/openamp_arduino/src/openamp/remoteproc_virtio.h +++ b/libraries/openamp_arduino/src/openamp/remoteproc_virtio.h @@ -1,150 +1,133 @@ -/* - * Remoteproc Virtio Framework - * - * Copyright(c) 2018 Xilinx Ltd. - * Copyright(c) 2011 Texas Instruments, Inc. - * Copyright(c) 2011 Google, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Texas Instruments nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef REMOTEPROC_VIRTIO_H -#define REMOTEPROC_VIRTIO_H - -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* define vdev notification funciton user should implement */ -typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); - -/** - * struct remoteproc_virtio - * @priv pointer to private data - * @notifyid notification id - * @vdev_rsc address of vdev resource - * @vdev_rsc_io metal I/O region of vdev_info, can be NULL - * @notify notification function - * @vdev virtio device - * @node list node - */ -struct remoteproc_virtio { - void *priv; - uint32_t notify_id; - void *vdev_rsc; - struct metal_io_region *vdev_rsc_io; - rpvdev_notify_func notify; - struct virtio_device vdev; - struct metal_list node; -}; - -/** - * rproc_virtio_create_vdev - * - * Create rproc virtio vdev - * - * @role: 0 - virtio master, 1 - virtio slave - * @notifyid: virtio device notification id - * @rsc: pointer to the virtio device resource - * @rsc_io: pointer to the virtio device resource I/O region - * @priv: pointer to the private data - * @notify: vdev and virtqueue notification function - * @rst_cb: reset virtio device callback - * - * return pointer to the created virtio device for success, - * NULL for failure. - */ -struct virtio_device * -rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, - void *rsc, struct metal_io_region *rsc_io, - void *priv, - rpvdev_notify_func notify, - virtio_dev_reset_cb rst_cb); - -/** - * rproc_virtio_remove_vdev - * - * Create rproc virtio vdev - * - * @vdev - pointer to the virtio device - */ -void rproc_virtio_remove_vdev(struct virtio_device *vdev); - -/** - * rproc_virtio_create_vring - * - * Create rproc virtio vring - * - * @vdev: pointer to the virtio device - * @index: vring index in the virtio device - * @notifyid: remoteproc vring notification id - * @va: vring virtual address - * @io: pointer to vring I/O region - * @num_desc: number of descriptors - * @align: vring alignment - * - * return 0 for success, negative value for failure. - */ -int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, - unsigned int notifyid, void *va, - struct metal_io_region *io, - unsigned int num_descs, unsigned int align); - -/** - * rproc_virtio_notified - * - * remoteproc virtio is got notified - * - * @vdev - pointer to the virtio device - * @notifyid - notify id - * - * return 0 for successful, negative value for failure - */ -int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid); - -/** - * rproc_virtio_wait_remote_ready - * - * Blocking function, waiting for the remote core is ready to start - * communications. - * - * @vdev - pointer to the virtio device - * - * return true when remote processor is ready. - */ -void rproc_virtio_wait_remote_ready(struct virtio_device *vdev); - -#if defined __cplusplus -} -#endif - -#endif /* REMOTEPROC_VIRTIO_H */ +/* + * Remoteproc Virtio Framework + * + * Copyright(c) 2018 Xilinx Ltd. + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, Inc. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef REMOTEPROC_VIRTIO_H +#define REMOTEPROC_VIRTIO_H + +#include +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* maximum number of vring descriptors for a vdev limited by 16-bit data type */ +#define RPROC_MAX_VRING_DESC USHRT_MAX + +/* cache invalidation helpers for resource table */ +#ifdef VIRTIO_CACHED_RSC_TABLE +#warning "VIRTIO_CACHED_RSC_TABLE is deprecated, please use VIRTIO_USE_DCACHE" +#endif +#if defined(VIRTIO_CACHED_RSC_TABLE) || defined(VIRTIO_USE_DCACHE) +#define RSC_TABLE_FLUSH(x, s) CACHE_FLUSH(x, s) +#define RSC_TABLE_INVALIDATE(x, s) CACHE_INVALIDATE(x, s) +#else +#define RSC_TABLE_FLUSH(x, s) do { } while (0) +#define RSC_TABLE_INVALIDATE(x, s) do { } while (0) +#endif /* VIRTIO_CACHED_RSC_TABLE || VIRTIO_USE_DCACHE */ + +/* define vdev notification function user should implement */ +typedef int (*rpvdev_notify_func)(void *priv, uint32_t id); + +/** @brief Virtio structure for remoteproc instance */ +struct remoteproc_virtio { + /** Pointer to private data */ + void *priv; + + /** Address of vdev resource */ + void *vdev_rsc; + + /** Metal I/O region of vdev_info, can be NULL */ + struct metal_io_region *vdev_rsc_io; + + /** Notification function */ + rpvdev_notify_func notify; + + /** Virtio device */ + struct virtio_device vdev; + + /** List node */ + struct metal_list node; +}; + +/** + * @brief Create rproc virtio vdev + * + * @param role VIRTIO_DEV_DRIVER or VIRTIO_DEV_DEVICE + * @param notifyid Virtio device notification id + * @param rsc Pointer to the virtio device resource + * @param rsc_io Pointer to the virtio device resource I/O region + * @param priv Pointer to the private data + * @param notify vdev and virtqueue notification function + * @param rst_cb Reset virtio device callback + * + * @return pointer to the created virtio device for success, + * NULL for failure. + */ +struct virtio_device * +rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, + void *rsc, struct metal_io_region *rsc_io, + void *priv, + rpvdev_notify_func notify, + virtio_dev_reset_cb rst_cb); + +/** + * @brief Remove rproc virtio vdev + * + * @param vdev Pointer to the virtio device + */ +void rproc_virtio_remove_vdev(struct virtio_device *vdev); + +/** + * @brief Initialize rproc virtio vring + * + * @param vdev Pointer to the virtio device + * @param index vring index in the virtio device + * @param notifyid remoteproc vring notification id + * @param va vring virtual address + * @param io Pointer to vring I/O region + * @param num_descs Number of descriptors + * @param align vring alignment + * + * @return 0 for success, negative value for failure. + */ +int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, + unsigned int notifyid, void *va, + struct metal_io_region *io, + unsigned int num_descs, unsigned int align); + +/** + * @brief remoteproc virtio is got notified + * + * @param vdev Pointer to the virtio device + * @param notifyid Notify id + * + * @return 0 for successful, negative value for failure + */ +int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid); + +/** + * @brief Blocking function, waiting for the remote core is ready to start + * communications. + * + * @param vdev Pointer to the virtio device + * + * @return true when remote processor is ready. + */ +void rproc_virtio_wait_remote_ready(struct virtio_device *vdev); + +#if defined __cplusplus +} +#endif + +#endif /* REMOTEPROC_VIRTIO_H */ diff --git a/libraries/openamp_arduino/src/openamp/rpmsg.h b/libraries/openamp_arduino/src/openamp/rpmsg.h index 56247f4..9cf1e74 100755 --- a/libraries/openamp_arduino/src/openamp/rpmsg.h +++ b/libraries/openamp_arduino/src/openamp/rpmsg.h @@ -12,9 +12,10 @@ #ifndef _RPMSG_H_ #define _RPMSG_H_ -#include "compiler.h" +#include #include #include +#include #include #include #include @@ -24,26 +25,29 @@ extern "C" { #endif /* Configurable parameters */ -#define RPMSG_NAME_SIZE (32) -#define RPMSG_ADDR_BMP_SIZE (4) +#define RPMSG_NAME_SIZE (32) +#define RPMSG_ADDR_BMP_SIZE (128) -#define RPMSG_NS_EPT_ADDR (0x35) -#define RPMSG_ADDR_ANY 0xFFFFFFFF +#define RPMSG_NS_EPT_ADDR (0x35) +#define RPMSG_RESERVED_ADDRESSES (1024) +#define RPMSG_ADDR_ANY 0xFFFFFFFF /* Error macros. */ -#define RPMSG_SUCCESS 0 -#define RPMSG_ERROR_BASE -2000 -#define RPMSG_ERR_NO_MEM (RPMSG_ERROR_BASE - 1) -#define RPMSG_ERR_NO_BUFF (RPMSG_ERROR_BASE - 2) -#define RPMSG_ERR_PARAM (RPMSG_ERROR_BASE - 3) -#define RPMSG_ERR_DEV_STATE (RPMSG_ERROR_BASE - 4) -#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERROR_BASE - 5) -#define RPMSG_ERR_INIT (RPMSG_ERROR_BASE - 6) -#define RPMSG_ERR_ADDR (RPMSG_ERROR_BASE - 7) +#define RPMSG_SUCCESS 0 +#define RPMSG_ERROR_BASE -2000 +#define RPMSG_ERR_NO_MEM (RPMSG_ERROR_BASE - 1) +#define RPMSG_ERR_NO_BUFF (RPMSG_ERROR_BASE - 2) +#define RPMSG_ERR_PARAM (RPMSG_ERROR_BASE - 3) +#define RPMSG_ERR_DEV_STATE (RPMSG_ERROR_BASE - 4) +#define RPMSG_ERR_BUFF_SIZE (RPMSG_ERROR_BASE - 5) +#define RPMSG_ERR_INIT (RPMSG_ERROR_BASE - 6) +#define RPMSG_ERR_ADDR (RPMSG_ERROR_BASE - 7) +#define RPMSG_ERR_PERM (RPMSG_ERROR_BASE - 8) struct rpmsg_endpoint; struct rpmsg_device; +/* Returns positive value on success or negative error value on failure */ typedef int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv); typedef void (*rpmsg_ns_unbind_cb)(struct rpmsg_endpoint *ept); @@ -51,88 +55,117 @@ typedef void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev, const char *name, uint32_t dest); /** - * struct rpmsg_endpoint - binds a local rpmsg address to its user - * @name:name of the service supported - * @rdev: pointer to the rpmsg device - * @addr: local address of the endpoint - * @dest_addr: address of the default remote endpoint binded. - * @cb: user rx callback, return value of this callback is reserved - * for future use, for now, only allow RPMSG_SUCCESS as return value. - * @ns_unbind_cb: end point service service unbind callback, called when remote - * ept is destroyed. - * @node: end point node. - * @addr: local rpmsg address - * @priv: private data for the driver's use + * @brief Structure that binds a local RPMsg address to its user * - * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as - * it binds an rpmsg address with an rx callback handler. + * In essence, an RPMsg endpoint represents a listener on the RPMsg bus, as + * it binds an RPMsg address with an rx callback handler. */ struct rpmsg_endpoint { + /** Name of the service supported */ char name[RPMSG_NAME_SIZE]; + + /** Pointer to the RPMsg device */ struct rpmsg_device *rdev; + + /** Local address of the endpoint */ uint32_t addr; + + /** Address of the default remote endpoint binded */ uint32_t dest_addr; + + /** + * User rx callback, return value of this callback is reserved for future + * use, for now, only allow RPMSG_SUCCESS as return value + */ rpmsg_ept_cb cb; + + /** Endpoint service unbind callback, called when remote ept is destroyed */ rpmsg_ns_unbind_cb ns_unbind_cb; + + /** Endpoint node */ struct metal_list node; + + /** Private data for the driver's use */ void *priv; }; -/** - * struct rpmsg_device_ops - RPMsg device operations - * @send_offchannel_raw: send RPMsg data - */ +/** @brief RPMsg device operations */ struct rpmsg_device_ops { + /** Send RPMsg data */ int (*send_offchannel_raw)(struct rpmsg_device *rdev, uint32_t src, uint32_t dst, - const void *data, int size, int wait); + const void *data, int len, int wait); + + /** Hold RPMsg RX buffer */ + void (*hold_rx_buffer)(struct rpmsg_device *rdev, void *rxbuf); + + /** Release RPMsg RX buffer */ + void (*release_rx_buffer)(struct rpmsg_device *rdev, void *rxbuf); + + /** Get RPMsg TX buffer */ + void *(*get_tx_payload_buffer)(struct rpmsg_device *rdev, + uint32_t *len, int wait); + + /** Send RPMsg data without copy */ + int (*send_offchannel_nocopy)(struct rpmsg_device *rdev, + uint32_t src, uint32_t dst, + const void *data, int len); + + /** Release RPMsg TX buffer */ + int (*release_tx_buffer)(struct rpmsg_device *rdev, void *txbuf); }; -/** - * struct rpmsg_device - representation of a RPMsg device - * @endpoints: list of endpoints - * @ns_ept: name service endpoint - * @bitmap: table endpoin address allocation. - * @lock: mutex lock for rpmsg management - * @ns_bind_cb: callback handler for name service announcement without local - * endpoints waiting to bind. - * @ops: RPMsg device operations - */ +/** @brief Representation of a RPMsg device */ struct rpmsg_device { + /** List of endpoints */ struct metal_list endpoints; + + /** Name service endpoint */ struct rpmsg_endpoint ns_ept; - unsigned long bitmap[RPMSG_ADDR_BMP_SIZE]; + + /** Table endpoint address allocation */ + unsigned long bitmap[metal_bitmap_longs(RPMSG_ADDR_BMP_SIZE)]; + + /** Mutex lock for RPMsg management */ metal_mutex_t lock; + + /** Callback handler for name service announcement without local epts waiting to bind */ rpmsg_ns_bind_cb ns_bind_cb; + + /** Callback handler for name service announcement, called when remote ept is destroyed */ + rpmsg_ns_bind_cb ns_unbind_cb; + + /** RPMsg device operations */ struct rpmsg_device_ops ops; + + /** Create/destroy namespace message */ + bool support_ns; }; /** - * rpmsg_send_offchannel_raw() - send a message across to the remote processor, + * @brief Send a message across to the remote processor, * specifying source and destination address. - * @ept: the rpmsg endpoint - * @data: payload of the message - * @len: length of the payload * * This function sends @data of length @len to the remote @dst address from * the source @src address. * The message will be sent to the remote processor which the channel belongs * to. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. * - * Returns number of bytes it has sent or negative error value on failure. + * @param ept The rpmsg endpoint + * @param src Source endpoint address of the message + * @param dst Destination endpoint address of the message + * @param data Payload of the message + * @param len Length of the payload + * @param wait Boolean value indicating whether to wait on buffers + * + * @return Number of bytes it has sent or negative error value on failure. */ int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, - uint32_t dst, const void *data, int size, + uint32_t dst, const void *data, int len, int wait); /** - * rpmsg_send() - send a message across to the remote processor - * @ept: the rpmsg endpoint - * @data: payload of the message - * @len: length of the payload + * @brief Send a message across to the remote processor * * This function sends @data of length @len based on the @ept. * The message will be sent to the remote processor which the channel belongs @@ -141,23 +174,24 @@ int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, * one becomes available, or a timeout of 15 seconds elapses. When the latter * happens, -ERESTARTSYS is returned. * - * Returns number of bytes it has sent or negative error value on failure. + * @param ept The rpmsg endpoint + * @param data Payload of the message + * @param len Length of the payload + * + * @return Number of bytes it has sent or negative error value on failure. */ static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, int len) { - if (ept->dest_addr == RPMSG_ADDR_ANY) - return RPMSG_ERR_ADDR; + if (!ept) + return RPMSG_ERR_PARAM; + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, len, true); } /** - * rpmsg_sendto() - send a message across to the remote processor, specify dst - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload - * @dst: destination address + * @brief Send a message across to the remote processor, specify dst * * This function sends @data of length @len to the remote @dst address. * The message will be sent to the remote processor which the @ept @@ -166,21 +200,24 @@ static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, * one becomes available, or a timeout of 15 seconds elapses. When the latter * happens, -ERESTARTSYS is returned. * - * Returns number of bytes it has sent or negative error value on failure. + * @param ept The rpmsg endpoint + * @param data Payload of message + * @param len Length of payload + * @param dst Destination address + * + * @return Number of bytes it has sent or negative error value on failure. */ static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data, int len, uint32_t dst) { + if (!ept) + return RPMSG_ERR_PARAM; + return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, true); } /** - * rpmsg_send_offchannel() - send a message using explicit src/dst addresses - * @ept: the rpmsg endpoint - * @src: source address - * @dst: destination address - * @data: payload of message - * @len: length of payload + * @brief Send a message using explicit src/dst addresses * * This function sends @data of length @len to the remote @dst address, * and uses @src as the source address. @@ -190,7 +227,13 @@ static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data, * one becomes available, or a timeout of 15 seconds elapses. When the latter * happens, -ERESTARTSYS is returned. * - * Returns number of bytes it has sent or negative error value on failure. + * @param ept The rpmsg endpoint + * @param src Source address + * @param dst Destination address + * @param data Payload of message + * @param len Length of payload + * + * @return Number of bytes it has sent or negative error value on failure. */ static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, uint32_t src, uint32_t dst, @@ -200,10 +243,7 @@ static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, } /** - * rpmsg_trysend() - send a message across to the remote processor - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload + * @brief Send a message across to the remote processor * * This function sends @data of length @len on the @ept channel. * The message will be sent to the remote processor which the @ept @@ -211,24 +251,24 @@ static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, * In case there are no TX buffers available, the function will immediately * return -ENOMEM without waiting until one becomes available. * - * Returns number of bytes it has sent or negative error value on failure. + * @param ept The rpmsg endpoint + * @param data Payload of message + * @param len Length of payload + * + * @return Number of bytes it has sent or negative error value on failure. */ static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data, int len) { - if (ept->dest_addr == RPMSG_ADDR_ANY) - return RPMSG_ERR_ADDR; + if (!ept) + return RPMSG_ERR_PARAM; + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, len, false); } /** - * rpmsg_trysendto() - send a message across to the remote processor, - * specify dst - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload - * @dst: destination address + * @brief Send a message across to the remote processor, specify dst * * This function sends @data of length @len to the remote @dst address. * The message will be sent to the remote processor which the @ept @@ -236,21 +276,24 @@ static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data, * In case there are no TX buffers available, the function will immediately * return -ENOMEM without waiting until one becomes available. * - * Returns number of bytes it has sent or negative error value on failure. + * @param ept The rpmsg endpoint + * @param data Payload of message + * @param len Length of payload + * @param dst Destination address + * + * @return Number of bytes it has sent or negative error value on failure. */ static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, const void *data, int len, uint32_t dst) { + if (!ept) + return RPMSG_ERR_PARAM; + return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, false); } /** - * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses - * @ept: the rpmsg endpoint - * @src: source address - * @dst: destination address - * @data: payload of message - * @len: length of payload + * @brief Send a message using explicit src/dst addresses * * This function sends @data of length @len to the remote @dst address, * and uses @src as the source address. @@ -259,7 +302,13 @@ static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, const void *data, * In case there are no TX buffers available, the function will immediately * return -ENOMEM without waiting until one becomes available. * - * Returns number of bytes it has sent or negative error value on failure. + * @param ept The rpmsg endpoint + * @param src Source address + * @param dst Destination address + * @param data Payload of message + * @param len Length of payload + * + * @return Number of bytes it has sent or negative error value on failure. */ static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, uint32_t src, uint32_t dst, @@ -269,47 +318,201 @@ static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, } /** - * rpmsg_init_ept - initialize rpmsg endpoint - * - * Initialize an RPMsg endpoint with a name, source address, - * remoteproc address, endpoitn callback, and destroy endpoint callback. - * - * @ept: pointer to rpmsg endpoint - * @name: service name associated to the endpoint - * @src: local address of the endpoint - * @dest: target address of the endpoint - * @cb: endpoint callback - * @ns_unbind_cb: end point service unbind callback, called when remote ept is - * destroyed. + * @brief Holds the rx buffer for usage outside the receive callback. + * + * Calling this function prevents the RPMsg receive buffer from being released + * back to the pool of shmem buffers. This API can only be called at rx + * callback context (rpmsg_rx_cb_t). With this API, the application doesn't + * need to copy the message in rx callback. Instead, the rx buffer base address + * is saved in application context and further processed in application + * process. After the message is processed, the application can release the rx + * buffer for future reuse in vring by calling the rpmsg_release_rx_buffer() + * function. + * + * @param ept The rpmsg endpoint + * @param rxbuf RX buffer with message payload + * + * @see rpmsg_release_rx_buffer + */ +void rpmsg_hold_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf); + +/** + * @brief Releases the rx buffer for future reuse in vring. + * + * This API can be called at process context when the message in rx buffer is + * processed. + * + * @param ept The rpmsg endpoint + * @param rxbuf rx buffer with message payload + * + * @see rpmsg_hold_rx_buffer */ -static inline void rpmsg_init_ept(struct rpmsg_endpoint *ept, - const char *name, - uint32_t src, uint32_t dest, - rpmsg_ept_cb cb, - rpmsg_ns_unbind_cb ns_unbind_cb) +void rpmsg_release_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf); + +/** + * @brief Gets the tx buffer for message payload. + * + * This API can only be called at process context to get the tx buffer in vring. + * By this way, the application can directly put its message into the vring tx + * buffer without copy from an application buffer. + * It is the application responsibility to correctly fill the allocated tx + * buffer by data and passing correct parameters to the rpmsg_send_nocopy() or + * rpmsg_sendto_nocopy() function to perform data no-copy-send mechanism. + * + * @param ept Pointer to rpmsg endpoint + * @param len Pointer to store tx buffer size + * @param wait Boolean, wait or not for buffer to become available + * + * @return The tx buffer address on success and NULL on failure + * + * @see rpmsg_send_offchannel_nocopy + * @see rpmsg_sendto_nocopy + * @see rpmsg_send_nocopy + */ +void *rpmsg_get_tx_payload_buffer(struct rpmsg_endpoint *ept, + uint32_t *len, int wait); + +/** + * @brief Releases unused buffer. + * + * This API can be called when the Tx buffer reserved by + * rpmsg_get_tx_payload_buffer needs to be released without having been sent to + * the remote side. + * + * Note that the rpmsg virtio is not able to detect if a buffer has already + * been released. The user must prevent a double release (e.g. by resetting its + * buffer pointer to zero after the release). + * + * @param ept The rpmsg endpoint + * @param txbuf tx buffer with message payload + * + * @return + * - RPMSG_SUCCESS on success + * - RPMSG_ERR_PARAM on invalid parameter + * - RPMSG_ERR_PERM if service not implemented + * + * @see rpmsg_get_tx_payload_buffer + */ +int rpmsg_release_tx_buffer(struct rpmsg_endpoint *ept, void *txbuf); + +/** + * @brief Send a message in tx buffer reserved by + * rpmsg_get_tx_payload_buffer() across to the remote processor. + * + * This function sends buf 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 ept + * endpoint belongs to. + * The application has to take the responsibility for: + * 1. tx buffer reserved (rpmsg_get_tx_payload_buffer() ) + * 2. filling the data to be sent into the pre-allocated tx buffer + * 3. not exceeding the buffer size when filling the data + * 4. data cache coherency + * + * After the rpmsg_send_offchannel_nocopy() function is issued the tx buffer is + * no more owned by the sending task and must not be touched anymore unless the + * rpmsg_send_offchannel_nocopy() function fails and returns an error. In that + * case application should try to re-issue the rpmsg_send_offchannel_nocopy() + * again. + * + * @param ept The rpmsg endpoint + * @param src The rpmsg endpoint local address + * @param dst The rpmsg endpoint remote address + * @param data TX buffer with message filled + * @param len Length of payload + * + * @return Number of bytes it has sent or negative error value on failure. + * + * @see rpmsg_get_tx_payload_buffer + * @see rpmsg_sendto_nocopy + * @see rpmsg_send_nocopy + */ +int rpmsg_send_offchannel_nocopy(struct rpmsg_endpoint *ept, uint32_t src, + uint32_t dst, const void *data, int len); + +/** + * @brief Sends a message in tx buffer allocated by + * rpmsg_get_tx_payload_buffer() across to the remote processor, specify dst. + * + * This function sends buf of length len to the remote dst address. + * The message will be sent to the remote processor which the ept + * endpoint belongs to, using ept's source address. + * The application has to take the responsibility for: + * 1. tx buffer allocation (rpmsg_get_tx_payload_buffer() ) + * 2. filling the data to be sent into the pre-allocated tx buffer + * 3. not exceeding the buffer size when filling the data + * 4. data cache coherency + * + * After the rpmsg_sendto_nocopy() function is issued the tx buffer is no more + * owned by the sending task and must not be touched anymore unless the + * rpmsg_sendto_nocopy() function fails and returns an error. In that case the + * application should try to re-issue the rpmsg_sendto_nocopy() again. + * + * @param ept The rpmsg endpoint + * @param data TX buffer with message filled + * @param len Length of payload + * @param dst Destination address + * + * @return Number of bytes it has sent or negative error value on failure. + * + * @see rpmsg_get_tx_payload_buffer + * @see rpmsg_send_offchannel_nocopy + * @see rpmsg_send_nocopy + */ +static inline int rpmsg_sendto_nocopy(struct rpmsg_endpoint *ept, + const void *data, int len, uint32_t dst) +{ + if (!ept) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_nocopy(ept, ept->addr, dst, data, len); +} + +/** + * @brief Send a message in tx buffer reserved by + * rpmsg_get_tx_payload_buffer() across to the remote processor. + * + * This function sends buf of length len on the ept endpoint. + * The message will be sent to the remote processor which the ept + * endpoint belongs to, using ept's source and destination addresses. + * The application has to take the responsibility for: + * 1. tx buffer reserved (rpmsg_get_tx_payload_buffer() ) + * 2. filling the data to be sent into the pre-allocated tx buffer + * 3. not exceeding the buffer size when filling the data + * 4. data cache coherency + * + * After the rpmsg_send_nocopy() function is issued the tx buffer is no more + * owned by the sending task and must not be touched anymore unless the + * rpmsg_send_nocopy() function fails and returns an error. In that case the + * application should try to re-issue the rpmsg_send_nocopy() again. + * + * @param ept The rpmsg endpoint + * @param data TX buffer with message filled + * @param len Length of payload + * + * @return Number of bytes it has sent or negative error value on failure. + * + * @see rpmsg_get_tx_payload_buffer + * @see rpmsg_send_offchannel_nocopy + * @see rpmsg_sendto_nocopy + */ +static inline int rpmsg_send_nocopy(struct rpmsg_endpoint *ept, + const void *data, int len) { - strncpy(ept->name, name, sizeof(ept->name)-1); - ept->addr = src; - ept->dest_addr = dest; - ept->cb = cb; - ept->ns_unbind_cb = ns_unbind_cb; + if (!ept) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_nocopy(ept, ept->addr, + ept->dest_addr, data, len); } /** - * rpmsg_create_ept - create rpmsg endpoint and register it to rpmsg device + * @brief Create rpmsg endpoint and register it to rpmsg device * * Create a RPMsg endpoint, initialize it with a name, source address, - * remoteproc address, endpoitn callback, and destroy endpoint callback, + * remoteproc address, endpoint callback, and destroy endpoint callback, * and register it to the RPMsg device. * - * @ept: pointer to rpmsg endpoint - * @name: service name associated to the endpoint - * @src: local address of the endpoint - * @dest: target address of the endpoint - * @cb: endpoint callback - * @ns_unbind_cb: end point service unbind callback, called when remote ept is - * destroyed. - * * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as * it binds an rpmsg address with an rx callback handler. * @@ -319,35 +522,43 @@ static inline void rpmsg_init_ept(struct rpmsg_endpoint *ept, * * As an option Some rpmsg clients can specify an endpoint with a specific * source address. + * + * @param ept Pointer to rpmsg endpoint + * @param rdev RPMsg device associated with the endpoint + * @param name Service name associated to the endpoint + * @param src Local address of the endpoint + * @param dest Target address of the endpoint + * @param cb Endpoint callback + * @param ns_unbind_cb Endpoint service unbind callback, called when remote + * ept is destroyed. + * + * @return 0 on success, or negative error value on failure. */ - int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, const char *name, uint32_t src, uint32_t dest, rpmsg_ept_cb cb, rpmsg_ns_unbind_cb ns_unbind_cb); /** - * rpmsg_destroy_ept - destroy rpmsg endpoint and unregister it from rpmsg - * device - * - * @ept: pointer to the rpmsg endpoint + * @brief Destroy rpmsg endpoint and unregister it from rpmsg device * * It unregisters the rpmsg endpoint from the rpmsg device and calls the * destroy endpoint callback if it is provided. + * + * @param ept Pointer to the rpmsg endpoint */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept); /** - * is_rpmsg_ept_ready - check if the rpmsg endpoint ready to send + * @brief Check if the rpmsg endpoint ready to send * - * @ept: pointer to rpmsg endpoint + * @param ept Pointer to rpmsg endpoint * - * Returns 1 if the rpmsg endpoint has both local addr and destination + * @return 1 if the rpmsg endpoint has both local addr and destination * addr set, 0 otherwise */ static inline unsigned int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept) { - return (ept->dest_addr != RPMSG_ADDR_ANY && - ept->addr != RPMSG_ADDR_ANY); + return ept && ept->rdev && ept->dest_addr != RPMSG_ADDR_ANY; } #if defined __cplusplus diff --git a/libraries/openamp_arduino/src/openamp/rpmsg_retarget.h b/libraries/openamp_arduino/src/openamp/rpmsg_retarget.h index 0df3a79..f020f6a 100755 --- a/libraries/openamp_arduino/src/openamp/rpmsg_retarget.h +++ b/libraries/openamp_arduino/src/openamp/rpmsg_retarget.h @@ -1,119 +1,134 @@ -#ifndef RPMSG_RETARGET_H -#define RPMSG_RETARGET_H - -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* File Operations System call definitions */ -#define OPEN_SYSCALL_ID 0x1UL -#define CLOSE_SYSCALL_ID 0x2UL -#define WRITE_SYSCALL_ID 0x3UL -#define READ_SYSCALL_ID 0x4UL -#define ACK_STATUS_ID 0x5UL - -#define TERM_SYSCALL_ID 0x6UL - -#define DEFAULT_PROXY_ENDPOINT 0xFFUL - -struct rpmsg_rpc_data; - -typedef int (*rpmsg_rpc_poll)(void *arg); -typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_data *rpc); - -struct rpmsg_rpc_syscall_header { - int32_t int_field1; - int32_t int_field2; - uint32_t data_len; -}; - -struct rpmsg_rpc_syscall { - uint32_t id; - struct rpmsg_rpc_syscall_header args; -}; - -struct rpmsg_rpc_data { - struct rpmsg_endpoint ept; - int ept_destroyed; - atomic_int nacked; - void *respbuf; - size_t respbuf_len; - rpmsg_rpc_poll poll; - void *poll_arg; - rpmsg_rpc_shutdown_cb shutdown_cb; - metal_mutex_t lock; - struct metal_spinlock buflock; -}; - -/** - * rpmsg_rpc_init - initialize RPMsg remote procedure call - * - * This function is to intialize the remote procedure call - * global data. RPMsg RPC will send request to remote and - * wait for callback. - * - * @rpc: pointer to the global remote procedure call data - * @rdev: pointer to the rpmsg device - * @ept_name: name of the endpoint used by RPC - * @ept_addr: address of the endpoint used by RPC - * @ept_raddr: remote address of the endpoint used by RPC - * @poll_arg: pointer to poll function argument - * @poll: poll function - * @shutdown_cb: shutdown callback function - * - * return 0 for success, and negative value for failure. - */ -int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc, - struct rpmsg_device *rdev, - const char *ept_name, uint32_t ept_addr, - uint32_t ept_raddr, - void *poll_arg, rpmsg_rpc_poll poll, - rpmsg_rpc_shutdown_cb shutdown_cb); - -/** - * rpmsg_rpc_release - release RPMsg remote procedure call - * - * This function is to release remoteproc procedure call - * global data. - * - * @rpc: pointer to the globacl remote procedure call - */ -void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc); - -/** - * rpmsg_rpc_send - Request RPMsg RPC call - * - * This function sends RPC request it will return with the length - * of data and the response buffer. - * - * @rpc: pointer to remoteproc procedure call data struct - * @req: pointer to request buffer - * @len: length of the request data - * @resp: pointer to where store the response buffer - * @resp_len: length of the response buffer - * - * return length of the received response, negative value for failure. - */ -int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc, - void *req, size_t len, - void *resp, size_t resp_len); - -/** - * rpmsg_set_default_rpc - set default RPMsg RPC data - * - * The default RPC data is used to redirect standard C file operations - * to RPMsg channels. - * - * @rpc: pointer to remoteproc procedure call data struct - */ -void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc); - -#if defined __cplusplus -} -#endif - -#endif /* RPMSG_RETARGET_H */ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RPMSG_RETARGET_H +#define RPMSG_RETARGET_H + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* File Operations System call definitions */ +#define OPEN_SYSCALL_ID 0x1UL +#define CLOSE_SYSCALL_ID 0x2UL +#define WRITE_SYSCALL_ID 0x3UL +#define READ_SYSCALL_ID 0x4UL +#define ACK_STATUS_ID 0x5UL + +#define TERM_SYSCALL_ID 0x6UL + +#define DEFAULT_PROXY_ENDPOINT 0xFFUL + +struct rpmsg_rpc_data; + +typedef int (*rpmsg_rpc_poll)(void *arg); +typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_data *rpc); + +struct rpmsg_rpc_syscall_header { + int32_t int_field1; + int32_t int_field2; + uint32_t data_len; +}; + +struct rpmsg_rpc_syscall { + uint32_t id; + struct rpmsg_rpc_syscall_header args; +}; + +struct rpmsg_rpc_data { + struct rpmsg_endpoint ept; + int ept_destroyed; + atomic_flag nacked; + void *respbuf; + size_t respbuf_len; + rpmsg_rpc_poll poll; + void *poll_arg; + rpmsg_rpc_shutdown_cb shutdown_cb; + metal_mutex_t lock; + struct metal_spinlock buflock; +}; + +/** + * @internal + * + * @brief Initialize RPMsg remote procedure call + * + * This function is to initialize the remote procedure call + * global data. RPMsg RPC will send request to remote and + * wait for callback. + * + * @param rpc Pointer to the global remote procedure call data + * @param rdev Pointer to the rpmsg device + * @param ept_name Name of the endpoint used by RPC + * @param ept_addr Address of the endpoint used by RPC + * @param ept_raddr Remote address of the endpoint used by RPC + * @param poll_arg Pointer to poll function argument + * @param poll Poll function + * @param shutdown_cb Shutdown callback function + * + * @return 0 for success, and negative value for failure. + */ +int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc, + struct rpmsg_device *rdev, + const char *ept_name, uint32_t ept_addr, + uint32_t ept_raddr, + void *poll_arg, rpmsg_rpc_poll poll, + rpmsg_rpc_shutdown_cb shutdown_cb); + +/** + * @internal + * + * @brief Release RPMsg remote procedure call + * + * This function is to release remoteproc procedure call + * global data. + * + * @param rpc Pointer to the global remote procedure call + */ +void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc); + +/** + * @internal + * + * @brief Request RPMsg RPC call + * + * This function sends RPC request it will return with the length + * of data and the response buffer. + * + * @param rpc Pointer to remoteproc procedure call data struct + * @param req Pointer to request buffer + * @param len Length of the request data + * @param resp Pointer to where store the response buffer + * @param resp_len Length of the response buffer + * + * @return Length of the received response, negative value for failure. + */ +int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc, + void *req, size_t len, + void *resp, size_t resp_len); + +/** + * @internal + * + * @brief Set default RPMsg RPC data + * + * The default RPC data is used to redirect standard C file operations + * to RPMsg channels. + * + * @param rpc Pointer to remoteproc procedure call data struct + */ +void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc); + +#if defined __cplusplus +} +#endif + +#endif /* RPMSG_RETARGET_H */ diff --git a/libraries/openamp_arduino/src/openamp/rpmsg_rpc_client_server.h b/libraries/openamp_arduino/src/openamp/rpmsg_rpc_client_server.h new file mode 100644 index 0000000..f940784 --- /dev/null +++ b/libraries/openamp_arduino/src/openamp/rpmsg_rpc_client_server.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2021, L&T Technology Services Ltd. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RPMSG_RPC_CLIENT_SERVER_H +#define RPMSG_RPC_CLIENT_SERVER_H + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#define RPMSG_RPC_OK 0 +#define RPMSG_RPC_INVALID_ID (-1L) +#define RPMSG_RPC_SERVICE_NAME "rpmsg-rpc" + +/* RPMSG_BUFFER_SIZE = 512 + * sizeof(struct rpmsg_hdr) = 16 + * RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr) - 1 = 495 + * Aligning to 64 bits -> 488UL + */ +#define MAX_BUF_LEN 488UL +#define MAX_FUNC_ID_LEN sizeof(unsigned long int) + +struct rpmsg_rpc_clt; +struct rpmsg_rpc_svr; + +typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_clt *rpc); +typedef void (*app_cb)(struct rpmsg_rpc_clt *rpc, int statust, void *data, + size_t len); +typedef int (*rpmsg_rpc_syscall_cb)(void *data, struct rpmsg_rpc_svr *rpcs); + +/** + * struct rpmsg_rpc_request - rpc request message + * + * @id: service id + * @params: request params + * + */ +struct rpmsg_rpc_request { + uint32_t id; + unsigned char params[MAX_BUF_LEN]; +}; + +/** @brief RPC request message */ +METAL_PACKED_BEGIN +struct rpmsg_rpc_answer { + /** Service ID */ + uint32_t id; + + /** Status of RPC */ + int32_t status; + + /** Answer params */ + unsigned char params[MAX_BUF_LEN]; +} METAL_PACKED_END; + +/** @brief Table for services */ +struct rpmsg_rpc_services { + /** Service ID */ + uint32_t id; + + /** ID callback */ + rpmsg_rpc_syscall_cb cb_function; +}; + +/** @brief Table for client services */ +struct rpmsg_rpc_client_services { + /** Service ID */ + uint32_t id; + + /** ID callback */ + app_cb cb; +}; + +/** + * @brief Server remote procedure call data + * + * RPMsg RPC will send request to endpoint + */ +struct rpmsg_rpc_svr { + /** RPMsg destination endpoint structure */ + struct rpmsg_endpoint ept; + + /** Service table */ + const struct rpmsg_rpc_services *services; + + /** Number of services */ + unsigned int n_services; +}; + +/** + * @brief Client remote procedure call data + * + * RPMsg RPC will send request to remote and + * wait for callback. + */ +struct rpmsg_rpc_clt { + /** RPMsg endpoint associated with the call */ + struct rpmsg_endpoint ept; + + /** Shutdown callback function */ + rpmsg_rpc_shutdown_cb shutdown_cb; + + /** Service table */ + const struct rpmsg_rpc_client_services *services; + + /** Number of services */ + unsigned int n_services; +}; + +/** + * @internal + * + * @brief Release RPMsg remote procedure call + * + * This function is to release remoteproc procedure call service + * + * @param rpc Pointer to the client remote procedure call data + */ +void rpmsg_rpc_client_release(struct rpmsg_rpc_clt *rpc); + +/** + * @internal + * + * @brief Initialize RPMsg remote procedure call + * + * This function is to initialize the remote procedure call + * client data. RPMsg RPC will send request to remote and + * wait for callback and load services to table + * + * @param rpc Pointer to the client remote procedure call data + * @param rdev Pointer to the rpmsg device + * @param shutdown_cb Shutdown callback function + * @param services Pointer to service table + * @param len Length of table + * + * @return 0 for success, and negative value for failure + */ +int rpmsg_rpc_client_init(struct rpmsg_rpc_clt *rpc, + struct rpmsg_device *rdev, + rpmsg_rpc_shutdown_cb shutdown_cb, + const struct rpmsg_rpc_client_services *services, + int len); + +/** + * @internal + * + * @brief Initialize RPMsg rpc for server + * + * This function create endpoint and loads services into table + * + * @param rpcs Pointer to the server rpc + * @param rdev Pointer to the rpmsg device + * @param services Pointer to service table + * @param len Length of table + * @param rpmsg_service_server_unbind Unbind function callback + * + * @return 0 for success, and negative value for failure + */ +int rpmsg_rpc_server_init(struct rpmsg_rpc_svr *rpcs, struct rpmsg_device *rdev, + const struct rpmsg_rpc_services *services, int len, + rpmsg_ns_unbind_cb rpmsg_service_server_unbind); + +/** + * @internal + * + * @brief Request RPMsg RPC call + * + * @param rpc Pointer to client remoteproc procedure call + * data + * @param rpc_id Function id + * @param request_param Pointer to request buffer + * @param req_param_size Length of the request data + * + * @return Length of the received response, negative value for failure. + */ +int rpmsg_rpc_client_send(struct rpmsg_rpc_clt *rpc, + unsigned int rpc_id, void *request_param, + size_t req_param_size); + +/** + * @internal + * + * @brief Request RPMsg RPC call + * + * This function sends RPC request + * + * @param rpcs Pointer to server rpc data + * @param rpc_id Function id + * @param status Status of rpc + * @param request_param Pointer to request buffer + * @param param_size Length of the request data + * + * @return Length of the received response, negative value for failure. + */ +int rpmsg_rpc_server_send(struct rpmsg_rpc_svr *rpcs, uint32_t rpc_id, + int status, void *request_param, + size_t param_size); + +#if defined __cplusplus +} +#endif + +#endif /* RPMSG_RPC_CLIENT_SERVER_H */ diff --git a/libraries/openamp_arduino/src/openamp/rpmsg_virtio.h b/libraries/openamp_arduino/src/openamp/rpmsg_virtio.h index ea0a255..aea2edf 100755 --- a/libraries/openamp_arduino/src/openamp/rpmsg_virtio.h +++ b/libraries/openamp_arduino/src/openamp/rpmsg_virtio.h @@ -1,190 +1,304 @@ -/* - * rpmsg based on virtio - * - * Copyright (C) 2018 Linaro, Inc. - * - * All rights reserved. - * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _RPMSG_VIRTIO_H_ -#define _RPMSG_VIRTIO_H_ - -#include -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* Configurable parameters */ -#ifndef RPMSG_BUFFER_SIZE -#define RPMSG_BUFFER_SIZE (512) -#endif - -/* The feature bitmap for virtio rpmsg */ -#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ - -struct rpmsg_virtio_shm_pool; -/** - * struct rpmsg_virtio_shm_pool - shared memory pool used for rpmsg buffers - * @get_buffer: function to get buffer from the pool - * @base: base address of the memory pool - * @avail: available memory size - * @size: total pool size - */ -struct rpmsg_virtio_shm_pool { - void *base; - size_t avail; - size_t size; -}; - -/** - * struct rpmsg_virtio_device - representation of a rpmsg device based on virtio - * @rdev: rpmsg device, first property in the struct - * @vdev: pointer to the virtio device - * @rvq: pointer to receive virtqueue - * @svq: pointer to send virtqueue - * @shbuf_io: pointer to the shared buffer I/O region - * @shpool: pointer to the shared buffers pool - * @endpoints: list of endpoints. - */ -struct rpmsg_virtio_device { - struct rpmsg_device rdev; - struct virtio_device *vdev; - struct virtqueue *rvq; - struct virtqueue *svq; - struct metal_io_region *shbuf_io; - struct rpmsg_virtio_shm_pool *shpool; -}; - -#define RPMSG_REMOTE VIRTIO_DEV_SLAVE -#define RPMSG_MASTER VIRTIO_DEV_MASTER -static inline unsigned int - rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev) -{ - return rvdev->vdev->role; -} - -static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev, - uint8_t status) -{ - rvdev->vdev->func->set_status(rvdev->vdev, status); -} - -static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev) -{ - return rvdev->vdev->func->get_status(rvdev->vdev); -} - -static inline uint32_t - rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev) -{ - return rvdev->vdev->func->get_features(rvdev->vdev); -} - -static inline int - rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, - int flags, unsigned int nvqs, - const char *names[], - vq_callback * callbacks[]) -{ - return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names, - callbacks); -} - -/** - * rpmsg_virtio_get_buffer_size - get rpmsg virtio buffer size - * - * @rdev - pointer to the rpmsg device - * - * @return - next available buffer size for text, negative value for failure - */ -int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev); - -/** - * rpmsg_init_vdev - initialize rpmsg virtio device - * Master side: - * Initialize RPMsg virtio queues and shared buffers, the address of shm can be - * ANY. In this case, function will get shared memory from system shared memory - * pools. If the vdev has RPMsg name service feature, this API will create an - * name service endpoint. - * - * Slave side: - * This API will not return until the driver ready is set by the master side. - * - * @param rvdev - pointer to the rpmsg virtio device - * @param vdev - pointer to the virtio device - * @param ns_bind_cb - callback handler for name service announcement without - * local endpoints waiting to bind. - * @param shm_io - pointer to the share memory I/O region. - * @param shpool - pointer to shared memory pool. rpmsg_virtio_init_shm_pool has - * to be called first to fill this structure. - * - * @return - status of function execution - */ -int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, - struct virtio_device *vdev, - rpmsg_ns_bind_cb ns_bind_cb, - struct metal_io_region *shm_io, - struct rpmsg_virtio_shm_pool *shpool); - -/** - * rpmsg_deinit_vdev - deinitialize rpmsg virtio device - * - * @param rvdev - pointer to the rpmsg virtio device - */ -void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev); - -/** - * rpmsg_virtio_init_shm_pool - initialize default shared buffers pool - * - * RPMsg virtio has default shared buffers pool implementation. - * The memory assigned to this pool will be dedicated to the RPMsg - * virtio. This function has to be called before calling rpmsg_init_vdev, - * to initialize the rpmsg_virtio_shm_pool structure. - * - * @param shpool - pointer to the shared buffers pool structure - * @param shbuf - pointer to the beginning of shared buffers - * @param size - shared buffers total size - */ -void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, - void *shbuf, size_t size); - -/** - * rpmsg_virtio_get_rpmsg_device - get RPMsg device from RPMsg virtio device - * - * @param rvdev - pointer to RPMsg virtio device - * @return - RPMsg device pointed by RPMsg virtio device - */ -static inline struct rpmsg_device * -rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev) -{ - return &rvdev->rdev; -} - -/** - * rpmsg_virtio_shm_pool_get_buffer - get buffer in the shared memory pool - * - * RPMsg virtio has default shared buffers pool implementation. - * The memory assigned to this pool will be dedicated to the RPMsg - * virtio. If you prefer to have other shared buffers allocation, - * you can implement your rpmsg_virtio_shm_pool_get_buffer function. - * - * @param shpool - pointer to the shared buffers pool - * @param size - shared buffers total size - * @return - buffer pointer if free buffer is available, NULL otherwise. - */ -metal_weak void * -rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, - size_t size); - -#if defined __cplusplus -} -#endif - -#endif /* _RPMSG_VIRTIO_H_ */ +/* + * rpmsg based on virtio + * + * Copyright (C) 2018 Linaro, Inc. + * + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _RPMSG_VIRTIO_H_ +#define _RPMSG_VIRTIO_H_ + +#include +#include +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* Configurable parameters */ +#ifndef RPMSG_BUFFER_SIZE +#define RPMSG_BUFFER_SIZE (512) +#endif + +/* The feature bitmap for virtio rpmsg */ +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ + +#ifdef VIRTIO_CACHED_BUFFERS +#warning "VIRTIO_CACHED_BUFFERS is deprecated, please use VIRTIO_USE_DCACHE" +#endif +#if defined(VIRTIO_CACHED_BUFFERS) || defined(VIRTIO_USE_DCACHE) +#define BUFFER_FLUSH(x, s) CACHE_FLUSH(x, s) +#define BUFFER_INVALIDATE(x, s) CACHE_INVALIDATE(x, s) +#else +#define BUFFER_FLUSH(x, s) do { } while (0) +#define BUFFER_INVALIDATE(x, s) do { } while (0) +#endif /* VIRTIO_CACHED_BUFFERS || VIRTIO_USE_DCACHE */ + +/** @brief Shared memory pool used for RPMsg buffers */ +struct rpmsg_virtio_shm_pool { + /** Base address of the memory pool */ + void *base; + + /** Available memory size */ + size_t avail; + + /** Total pool size */ + size_t size; +}; + +/** + * @brief Configuration of RPMsg device based on virtio + * + * This structure is used by the RPMsg virtio host to configure the virtiio + * layer. + */ +struct rpmsg_virtio_config { + /** The size of the buffer used to send data from host to remote */ + uint32_t h2r_buf_size; + + /** The size of the buffer used to send data from remote to host */ + uint32_t r2h_buf_size; + + /** The flag for splitting shared memory pool to TX and RX */ + bool split_shpool; +}; + +/** @brief Representation of a RPMsg device based on virtio */ +struct rpmsg_virtio_device { + /** RPMsg device */ + struct rpmsg_device rdev; + + /** Structure containing virtio configuration */ + struct rpmsg_virtio_config config; + + /** Pointer to the virtio device */ + struct virtio_device *vdev; + + /** Pointer to receive virtqueue */ + struct virtqueue *rvq; + + /** Pointer to send virtqueue */ + struct virtqueue *svq; + + /** Pointer to the shared buffer I/O region */ + struct metal_io_region *shbuf_io; + + /** Pointer to the shared buffers pool */ + struct rpmsg_virtio_shm_pool *shpool; + + /** + * RPMsg buffer reclaimer that contains buffers released by the + * \ref rpmsg_virtio_release_tx_buffer function + */ + struct metal_list reclaimer; +}; + +#define RPMSG_REMOTE VIRTIO_DEV_DEVICE +#define RPMSG_HOST VIRTIO_DEV_DRIVER + +#define RPMSG_SLAVE deprecated_rpmsg_slave() +#define RPMSG_MASTER deprecated_rpmsg_master() + +__deprecated static inline int deprecated_rpmsg_master(void) +{ + /* "RPMSG_MASTER is deprecated, please use RPMSG_HOST" */ + return RPMSG_HOST; +} + +__deprecated static inline int deprecated_rpmsg_slave(void) +{ + /* "RPMSG_SLAVE is deprecated, please use RPMSG_REMOTE" */ + return RPMSG_REMOTE; +} + +static inline unsigned int +rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->role; +} + +static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev, + uint8_t status) +{ + rvdev->vdev->func->set_status(rvdev->vdev, status); +} + +static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->func->get_status(rvdev->vdev); +} + +static inline uint32_t +rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev) +{ + return rvdev->vdev->func->get_features(rvdev->vdev); +} + +static inline void +rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev, + uint32_t offset, void *dst, int length) +{ + rvdev->vdev->func->read_config(rvdev->vdev, offset, dst, length); +} + +static inline void +rpmsg_virtio_write_config(struct rpmsg_virtio_device *rvdev, + uint32_t offset, void *dst, int length) +{ + rvdev->vdev->func->write_config(rvdev->vdev, offset, dst, length); +} + +static inline int +rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, + int flags, unsigned int nvqs, + const char *names[], + vq_callback *callbacks) +{ + return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names, + callbacks, NULL); +} + +/** + * @brief Get rpmsg virtio buffer size + * + * @param rdev Pointer to the rpmsg device + * + * @return Next available buffer size for text, negative value for failure + */ +int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev); + +/** + * @brief Initialize rpmsg virtio device + * + * Host side: + * Initialize RPMsg virtio queues and shared buffers, the address of shm can be + * ANY. In this case, function will get shared memory from system shared memory + * pools. If the vdev has the RPMsg name service feature, this API will create + * a name service endpoint. + * + * Remote side: + * This API will not return until the driver ready is set by the host side. + * + * @param rvdev Pointer to the rpmsg virtio device + * @param vdev Pointer to the virtio device + * @param ns_bind_cb Callback handler for name service announcement without + * local endpoints waiting to bind. + * @param shm_io Pointer to the share memory I/O region. + * @param shpool Pointer to shared memory pool. + * rpmsg_virtio_init_shm_pool has to be called first to + * fill this structure. + * + * @return Status of function execution + */ +int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool); + +/** + * @brief Initialize rpmsg virtio device with config + * + * Host side: + * Initialize RPMsg virtio queues and shared buffers, the address of shm can be + * ANY. In this case, function will get shared memory from system shared memory + * pools. If the vdev has the RPMsg name service feature, this API will create + * a name service endpoint. + * Sizes of virtio data buffers used by the initialized RPMsg instance are set + * to values read from the passed configuration structure. + * + * Remote side: + * This API will not return until the driver ready is set by the host side. + * Sizes of virtio data buffers are set by the host side. Values passed in the + * configuration structure have no effect. + * + * @param rvdev Pointer to the rpmsg virtio device + * @param vdev Pointer to the virtio device + * @param ns_bind_cb Callback handler for name service announcement without + * local endpoints waiting to bind. + * @param shm_io Pointer to the share memory I/O region. + * @param shpool Pointer to shared memory pool array. + * If the config->split_shpool is turn on, the array will + * contain two elements, the shpool of txshpool and + * rxshpool, Otherwise, the array has only one element, + * and txshpool rxshpool shares a shpool. + * And rpmsg_virtio_init_shm_pool has to be called first + * to fill each shpool in this array. + * @param config Pointer to configuration structure + * + * @return Status of function execution + */ +int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool, + const struct rpmsg_virtio_config *config); + +/** + * @brief Deinitialize rpmsg virtio device + * + * @param rvdev Pointer to the rpmsg virtio device + */ +void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev); + +/** + * @brief Initialize default shared buffers pool + * + * RPMsg virtio has default shared buffers pool implementation. + * The memory assigned to this pool will be dedicated to the RPMsg + * virtio. This function has to be called before calling rpmsg_init_vdev, + * to initialize the rpmsg_virtio_shm_pool structure. + * + * @param shpool Pointer to the shared buffers pool structure + * @param shbuf Pointer to the beginning of shared buffers + * @param size Shared buffers total size + */ +void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, + void *shbuf, size_t size); + +/** + * @brief Get RPMsg device from RPMsg virtio device + * + * @param rvdev Pointer to RPMsg virtio device + * + * @return RPMsg device pointed by RPMsg virtio device + */ +static inline struct rpmsg_device * +rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev) +{ + if (!rvdev) + return NULL; + + return &rvdev->rdev; +} + +/** + * @brief Get buffer in the shared memory pool + * + * RPMsg virtio has default shared buffers pool implementation. + * The memory assigned to this pool will be dedicated to the RPMsg + * virtio. If you prefer to have other shared buffers allocation, + * you can implement your rpmsg_virtio_shm_pool_get_buffer function. + * + * @param shpool Pointer to the shared buffers pool + * @param size Shared buffers total size + * + * @return Buffer pointer if free buffer is available, NULL otherwise. + */ +metal_weak void * +rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, + size_t size); + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_VIRTIO_H_ */ diff --git a/libraries/openamp_arduino/src/openamp/rsc_table_parser.h b/libraries/openamp_arduino/src/openamp/rsc_table_parser.h index 6802d03..d86da74 100755 --- a/libraries/openamp_arduino/src/openamp/rsc_table_parser.h +++ b/libraries/openamp_arduino/src/openamp/rsc_table_parser.h @@ -1,64 +1,83 @@ -/* - * Copyright (c) 2014, Mentor Graphics Corporation - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef RSC_TABLE_PARSER_H -#define RSC_TABLE_PARSER_H - -#include - -#if defined __cplusplus -extern "C" { -#endif - -#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 remoteproc *rproc, void *rsc); - -/** - * handle_rsc_table - * - * This function parses resource table. - * - * @param rproc - pointer to remote remoteproc - * @param rsc_table - resource table to parse - * @param size - size of rsc table - * @param io - pointer to the resource table I/O region - * It can be NULL if the resource table - * is in the local memory. - * - * @returns - execution status - * - */ -int handle_rsc_table(struct remoteproc *rproc, - struct resource_table *rsc_table, int len, - struct metal_io_region *io); -int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc); -int handle_trace_rsc(struct remoteproc *rproc, void *rsc); -int handle_vdev_rsc(struct remoteproc *rproc, void *rsc); -int handle_vendor_rsc(struct remoteproc *rproc, void *rsc); - -/** - * find_rsc - * - * find out location of a resource type in the resource table. - * - * @rsc_table - pointer to the resource table - * @rsc_type - type of the resource - * @index - index of the resource of the specified type - * - * return the offset to the resource on success, or 0 on failure - */ -size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index); - -#if defined __cplusplus -} -#endif - -#endif /* RSC_TABLE_PARSER_H */ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RSC_TABLE_PARSER_H +#define RSC_TABLE_PARSER_H + +#include + +#if defined __cplusplus +extern "C" { +#endif + +#define RSC_TAB_SUPPORTED_VERSION 1 + +/* Standard control request handling. */ +typedef int (*rsc_handler)(struct remoteproc *rproc, void *rsc); + +/** + * @internal + * + * @brief This function parses resource table. + * + * @param rproc Pointer to remote remoteproc + * @param rsc_table Resource table to parse + * @param len Size of rsc table + * @param io Pointer to the resource table I/O region + * It can be NULL if the resource table + * is in the local memory. + * + * @return Execution status + */ +int handle_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, size_t len, + struct metal_io_region *io); + +/** + * @internal + * + * @brief Carveout resource handler. + * + * @param rproc Pointer to remote remoteproc + * @param rsc Pointer to carveout resource + * + * @return 0 for success, or negative value for failure + */ +int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc); + +/** + * @internal + * + * @brief Trace resource handler. + * + * @param rproc Pointer to remote remoteproc + * @param rsc Pointer to trace resource + * + * @return No service error + */ +int handle_trace_rsc(struct remoteproc *rproc, void *rsc); +int handle_vdev_rsc(struct remoteproc *rproc, void *rsc); +int handle_vendor_rsc(struct remoteproc *rproc, void *rsc); + +/** + * @internal + * + * @brief Find out location of a resource type in the resource table. + * + * @param rsc_table Pointer to the resource table + * @param rsc_type Type of the resource + * @param index Index of the resource of the specified type + * + * @return The offset to the resource on success, or 0 on failure + */ +size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index); + +#if defined __cplusplus +} +#endif + +#endif /* RSC_TABLE_PARSER_H */ diff --git a/libraries/openamp_arduino/src/openamp/version.h b/libraries/openamp_arduino/src/openamp/version.h new file mode 100644 index 0000000..9ee7838 --- /dev/null +++ b/libraries/openamp_arduino/src/openamp/version.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021, STMicroelectronics. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file version.h + * @brief Library version information for OpenAMP. + */ + +#ifndef __OPENAMP_VERSION__H__ +#define __OPENAMP_VERSION__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup versions Library Version Interfaces + * @{ + */ + +/** + * @brief Library major version number. + * + * Return the major version number of the library linked into the application. + * This is required to match the value of LIB_VERSION_MAJOR, which is the major + * version of the library that the application was compiled against. + * + * @return Library major version number. + * + * @see PROJECT_VERSION_MAJOR + */ +extern int openamp_version_major(void); + +/** + * @brief Library minor version number. + * + * Return the minor version number of the library linked into the application. + * This could differ from the value of LIB_VERSION_MINOR, which is the minor + * version of the library that the application was compiled against. + * + * @return Library minor version number. + * + * @see PROJECT_VERSION_MINOR + */ +extern int openamp_version_minor(void); + +/** + * @brief Library patch level. + * + * Return the patch level of the library linked into the application. This + * could differ from the value of LIB_VERSION_PATCH, which is the patch level of + * the library that the application was compiled against. + * + * @return Library patch level. + * + * @see PROJECT_VERSION_PATCH + */ +extern int openamp_version_patch(void); + +/** + * @brief Library version string. + * + * Return the version string of the library linked into the application. This + * could differ from the value of LIB_VERSION, which is the version string of + * the library that the application was compiled against. + * + * @return Library version string. + * + * @see PROJECT_VERSION + */ +extern const char *openamp_version(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENAMP_VERSION__H__ */ diff --git a/libraries/openamp_arduino/src/openamp/virtio.h b/libraries/openamp_arduino/src/openamp/virtio.h index 51a4740..9febd1e 100755 --- a/libraries/openamp_arduino/src/openamp/virtio.h +++ b/libraries/openamp_arduino/src/openamp/virtio.h @@ -1,176 +1,499 @@ -/* - * SPDX-License-Identifier: BSD-3-Clause - * - * $FreeBSD$ - */ - -#ifndef _VIRTIO_H_ -#define _VIRTIO_H_ - -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* TODO: define this as compiler flags */ -#ifndef VIRTIO_MAX_NUM_VRINGS -#define VIRTIO_MAX_NUM_VRINGS 2 -#endif - -/* VirtIO device IDs. */ -#define VIRTIO_ID_NETWORK 0x01UL -#define VIRTIO_ID_BLOCK 0x02UL -#define VIRTIO_ID_CONSOLE 0x03UL -#define VIRTIO_ID_ENTROPY 0x04UL -#define VIRTIO_ID_BALLOON 0x05UL -#define VIRTIO_ID_IOMEMORY 0x06UL -#define VIRTIO_ID_RPMSG 0x07UL /* remote processor messaging */ -#define VIRTIO_ID_SCSI 0x08UL -#define VIRTIO_ID_9P 0x09UL -#define VIRTIO_DEV_ANY_ID (-1)UL - -/* Status byte for guest to report progress. */ -#define VIRTIO_CONFIG_STATUS_ACK 0x01 -#define VIRTIO_CONFIG_STATUS_DRIVER 0x02 -#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04 -#define VIRTIO_CONFIG_STATUS_NEEDS_RESET 0x40 -#define VIRTIO_CONFIG_STATUS_FAILED 0x80 - -/* Virtio device role */ -#define VIRTIO_DEV_MASTER 0UL -#define VIRTIO_DEV_SLAVE 1UL - -struct virtio_device_id { - uint32_t device; - uint32_t vendor; -}; - -/* - * Generate interrupt when the virtqueue ring is - * completely used, even if we've suppressed them. - */ -#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 void (*virtio_dev_reset_cb)(struct virtio_device *vdev); - -struct virtio_dispatch; - -struct virtio_feature_desc { - uint32_t vfd_val; - const char *vfd_str; -}; - -/** - * struct proc_shm - * - * This structure is maintained by hardware interface layer for - * shared memory information. The shared memory provides buffers - * for use by the vring to exchange messages between the cores. - * - */ -struct virtio_buffer_info { - /* Start address of shared memory used for buffers. */ - void *vaddr; - /* Start physical address of shared memory used for buffers. */ - metal_phys_addr_t paddr; - /* sharmed memory I/O region */ - struct metal_io_region *io; - /* Size of shared memory. */ - unsigned long size; -}; - -/** - * struct remoteproc_vring - remoteproc vring structure - * @vq virtio queue - * @va logical address - * @notifyid vring notify id - * @num_descs number of descriptors - * @align vring alignment - * @io metal I/O region of the vring memory, can be NULL - */ -struct virtio_vring_info { - struct virtqueue *vq; - struct vring_alloc_info info; - uint32_t notifyid; - struct metal_io_region *io; -}; - -/* - * Structure definition for virtio devices for use by the - * applications/drivers - */ - -struct virtio_device { - uint32_t index; /**< unique position on the virtio bus */ - struct virtio_device_id id; /**< the device type identification - * (used to match it with a driver - */ - uint64_t features; /**< the features supported by both ends. */ - unsigned int role; /**< if it is virtio backend or front end. */ - virtio_dev_reset_cb reset_cb; /**< user registered device callback */ - const struct virtio_dispatch *func; /**< Virtio dispatch table */ - void *priv; /**< TODO: remove pointer to virtio_device private data */ - unsigned int vrings_num; /**< number of vrings */ - struct virtio_vring_info *vrings_info; -}; - -/* - * Helper functions. - */ -const char *virtio_dev_name(uint16_t devid); -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 { - 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); - void (*notify)(struct virtqueue *vq); -}; - -int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, - unsigned int nvqs, const char *names[], - vq_callback *callbacks[]); - -#if defined __cplusplus -} -#endif - -#endif /* _VIRTIO_H_ */ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * $FreeBSD$ + */ + +#ifndef _VIRTIO_H_ +#define _VIRTIO_H_ + +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* VirtIO device IDs. */ +#define VIRTIO_ID_NETWORK 1UL +#define VIRTIO_ID_BLOCK 2UL +#define VIRTIO_ID_CONSOLE 3UL +#define VIRTIO_ID_ENTROPY 4UL +#define VIRTIO_ID_BALLOON 5UL +#define VIRTIO_ID_IOMEMORY 6UL +#define VIRTIO_ID_RPMSG 7UL /* remote processor messaging */ +#define VIRTIO_ID_SCSI 8UL +#define VIRTIO_ID_9P 9UL +#define VIRTIO_ID_MAC80211_WLAN 10UL +#define VIRTIO_ID_RPROC_SERIAL 11UL +#define VIRTIO_ID_CAIF 12UL +#define VIRTIO_ID_MEMORY_BALLOON 13UL +#define VIRTIO_ID_GPU 16UL +#define VIRTIO_ID_CLOCK 17UL +#define VIRTIO_ID_INPUT 18UL +#define VIRTIO_ID_VSOCK 19UL +#define VIRTIO_ID_CRYPTO 20UL +#define VIRTIO_ID_SIGNAL_DIST 21UL +#define VIRTIO_ID_PSTORE 22UL +#define VIRTIO_ID_IOMMU 23UL +#define VIRTIO_ID_MEM 24UL +#define VIRTIO_ID_SOUND 25UL +#define VIRTIO_ID_FS 26UL +#define VIRTIO_ID_PMEM 27UL +#define VIRTIO_ID_RPMB 28UL +#define VIRTIO_ID_MAC80211_HWSIM 29UL +#define VIRTIO_ID_VIDEO_ENCODER 30UL +#define VIRTIO_ID_VIDEO_DECODER 31UL +#define VIRTIO_ID_SCMI 32UL +#define VIRTIO_ID_NITRO_SEC_MOD 33UL +#define VIRTIO_ID_I2C_ADAPTER 34UL +#define VIRTIO_ID_WATCHDOG 35UL +#define VIRTIO_ID_CAN 36UL +#define VIRTIO_ID_PARAM_SERV 38UL +#define VIRTIO_ID_AUDIO_POLICY 39UL +#define VIRTIO_ID_BT 40UL +#define VIRTIO_ID_GPIO 41UL +#define VIRTIO_ID_RDMA 42UL +#define VIRTIO_DEV_ANY_ID -1UL + +/* 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_FEATURES_OK 0x08 +#define VIRTIO_CONFIG_STATUS_NEEDS_RESET 0x40 +#define VIRTIO_CONFIG_STATUS_FAILED 0x80 + +/* Virtio device role */ +#define VIRTIO_DEV_DRIVER 0UL +#define VIRTIO_DEV_DEVICE 1UL + +#define VIRTIO_DEV_MASTER deprecated_virtio_dev_master() +#define VIRTIO_DEV_SLAVE deprecated_virtio_dev_slave() + +__deprecated static inline int deprecated_virtio_dev_master(void) +{ + /* "VIRTIO_DEV_MASTER is deprecated, please use VIRTIO_DEV_DRIVER" */ + return VIRTIO_DEV_DRIVER; +} + +__deprecated static inline int deprecated_virtio_dev_slave(void) +{ + /* "VIRTIO_DEV_SLAVE is deprecated, please use VIRTIO_DEV_DEVICE" */ + return VIRTIO_DEV_DEVICE; +} + +#ifdef VIRTIO_MASTER_ONLY +#define VIRTIO_DRIVER_ONLY +#warning "VIRTIO_MASTER_ONLY is deprecated, please use VIRTIO_DRIVER_ONLY" +#endif + +#ifdef VIRTIO_SLAVE_ONLY +#define VIRTIO_DEVICE_ONLY +#warning "VIRTIO_SLAVE_ONLY is deprecated, please use VIRTIO_DEVICE_ONLY" +#endif + +/** @brief Virtio device identifier. */ +struct virtio_device_id { + /** Virtio subsystem device ID. */ + uint32_t device; + + /** Virtio subsystem vendor ID. */ + uint32_t vendor; + + /** Virtio subsystem device version. */ + uint32_t version; +}; + +/* + * 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 + +#ifdef VIRTIO_DEBUG +#include + +#define VIRTIO_ASSERT(_exp, _msg) do { \ + int exp = (_exp); \ + if (!(exp)) { \ + metal_log(METAL_LOG_EMERGENCY, \ + "FATAL: %s - " _msg, __func__); \ + metal_assert(exp); \ + } \ + } while (0) +#else +#define VIRTIO_ASSERT(_exp, _msg) metal_assert(_exp) +#endif /* VIRTIO_DEBUG */ + +#define VIRTIO_MMIO_VRING_ALIGNMENT 4096 + +typedef void (*virtio_dev_reset_cb)(struct virtio_device *vdev); + +struct virtio_dispatch; + +/** @brief Device features. */ +struct virtio_feature_desc { + /** Unique feature ID, defined in the virtio specification. */ + uint32_t vfd_val; + + /** Name of the feature (for debug). */ + const char *vfd_str; +}; + +/** @brief Virtio vring data structure */ +struct virtio_vring_info { + /** Virtio queue */ + struct virtqueue *vq; + + /** Vring alloc info */ + struct vring_alloc_info info; + + /** Vring notify id */ + uint32_t notifyid; + + /** Metal I/O region of the vring memory, can be NULL */ + struct metal_io_region *io; +}; + +/** @brief Structure definition for virtio devices for use by the applications/drivers */ +struct virtio_device { + /** Unique position on the virtio bus */ + uint32_t notifyid; + + /** The device type identification used to match it with a driver */ + struct virtio_device_id id; + + /** The features supported by both ends. */ + uint64_t features; + + /** If it is virtio backend or front end. */ + unsigned int role; + + /** User-registered device callback */ + virtio_dev_reset_cb reset_cb; + + /** Virtio dispatch table */ + const struct virtio_dispatch *func; + + /** Private data */ + void *priv; + + /** Number of vrings */ + unsigned int vrings_num; + + /** Pointer to the virtio vring structure */ + struct virtio_vring_info *vrings_info; +}; + +/* + * Helper functions. + */ + +/** + * @brief Get the name of a virtio device. + * + * @param devid Id of the device. + * + * @return pointer to the device name string if found, otherwise null. + */ +const char *virtio_dev_name(uint16_t devid); + +__deprecated void virtio_describe(struct virtio_device *dev, const char *msg, + uint32_t features, + struct virtio_feature_desc *feature_desc); + +/** + * @brief Virtio device dispatcher functions. + * + * Functions for virtio device configuration as defined in Rusty Russell's paper. + * The virtio transport layers are expected to implement these functions in their respective codes. + */ + +struct virtio_dispatch { + /** Create virtio queue instances. */ + int (*create_virtqueues)(struct virtio_device *vdev, + unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback callbacks[], + void *callback_args[]); + + /** Delete virtio queue instances. */ + void (*delete_virtqueues)(struct virtio_device *vdev); + + /** Get the status of the virtio device. */ + uint8_t (*get_status)(struct virtio_device *dev); + + /** Set the status of the virtio device. */ + void (*set_status)(struct virtio_device *dev, uint8_t status); + + /** Get the feature exposed by the virtio device. */ + uint32_t (*get_features)(struct virtio_device *dev); + + /** Set the supported feature (virtio driver only). */ + void (*set_features)(struct virtio_device *dev, uint32_t feature); + + /** + * Set the supported feature negotiate between the \ref features parameter and features + * supported by the device (virtio driver only). + */ + uint32_t (*negotiate_features)(struct virtio_device *dev, + uint32_t features); + + /** + * Read a variable amount from the device specific (ie, network) + * configuration region. + */ + void (*read_config)(struct virtio_device *dev, uint32_t offset, + void *dst, int length); + + /** + * Write a variable amount from the device specific (ie, network) + * configuration region. + */ + void (*write_config)(struct virtio_device *dev, uint32_t offset, + void *src, int length); + + /** Request a reset of the virtio device. */ + void (*reset_device)(struct virtio_device *dev); + + /** Notify the other side that a virtio vring as been updated. */ + void (*notify)(struct virtqueue *vq); +}; + +/** + * @brief Create the virtio device virtqueue. + * + * @param vdev Pointer to virtio device structure. + * @param flags Create flag. + * @param nvqs The virtqueue number. + * @param names Virtqueue names. + * @param callbacks Virtqueue callback functions. + * @param callback_args Virtqueue callback function arguments. + * + * @return 0 on success, otherwise error code. + */ +int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback callbacks[], void *callback_args[]); + +/** + * @brief Delete the virtio device virtqueue. + * + * @param vdev Pointer to virtio device structure. + * + */ +static inline void virtio_delete_virtqueues(struct virtio_device *vdev) +{ + if (!vdev || !vdev->func || !vdev->func->delete_virtqueues) + return; + + vdev->func->delete_virtqueues(vdev); +} + +/** + * @brief Get device ID. + * + * @param dev Pointer to device structure. + * + * @return Device ID value. + */ +static inline uint32_t virtio_get_devid(const struct virtio_device *vdev) +{ + if (!vdev) + return 0; + return vdev->id.device; +} + +/** + * @brief Retrieve device status. + * + * @param dev Pointer to device structure. + * @param status Pointer to the virtio device status. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_get_status(struct virtio_device *vdev, uint8_t *status) +{ + if (!vdev || !status) + return -EINVAL; + + if (!vdev->func || !vdev->func->get_status) + return -ENXIO; + + *status = vdev->func->get_status(vdev); + return 0; +} + +/** + * @brief Set device status. + * + * @param dev Pointer to device structure. + * @param status Value to be set as device status. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_set_status(struct virtio_device *vdev, uint8_t status) +{ + if (!vdev) + return -EINVAL; + + if (!vdev->func || !vdev->func->set_status) + return -ENXIO; + + vdev->func->set_status(vdev, status); + return 0; +} + +/** + * @brief Retrieve configuration data from the device. + * + * @param dev Pointer to device structure. + * @param offset Offset of the data within the configuration area. + * @param dst Address of the buffer that will hold the data. + * @param len Length of the data to be retrieved. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_read_config(struct virtio_device *vdev, + uint32_t offset, void *dst, int len) +{ + if (!vdev || !dst) + return -EINVAL; + + if (!vdev->func || !vdev->func->read_config) + return -ENXIO; + + vdev->func->read_config(vdev, offset, dst, len); + return 0; +} + +/** + * @brief Write configuration data to the device. + * + * @param dev Pointer to device structure. + * @param offset Offset of the data within the configuration area. + * @param src Address of the buffer that holds the data to write. + * @param len Length of the data to be written. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_write_config(struct virtio_device *vdev, + uint32_t offset, void *src, int len) +{ + if (!vdev || !src) + return -EINVAL; + + if (!vdev->func || !vdev->func->write_config) + return -ENXIO; + + vdev->func->write_config(vdev, offset, src, len); + return 0; +} + +/** + * @brief Get the virtio device features. + * + * @param dev Pointer to device structure. + * @param features Pointer to features supported by both the driver and + * the device as a bitfield. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_get_features(struct virtio_device *vdev, + uint32_t *features) +{ + if (!vdev || !features) + return -EINVAL; + + if (!vdev->func || !vdev->func->get_features) + return -ENXIO; + + *features = vdev->func->get_features(vdev); + return 0; +} + +/** + * @brief Set features supported by the VIRTIO driver. + * + * @param dev Pointer to device structure. + * @param features Features supported by the driver as a bitfield. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_set_features(struct virtio_device *vdev, + uint32_t features) +{ + if (!vdev) + return -EINVAL; + + if (!vdev->func || !vdev->func->set_features) + return -ENXIO; + + vdev->func->set_features(vdev, features); + return 0; +} + +/** + * @brief Negotiate features between virtio device and driver. + * + * @param dev Pointer to device structure. + * @param features Supported features. + * @param final_features Pointer to the final features after negotiate. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_negotiate_features(struct virtio_device *vdev, + uint32_t features, + uint32_t *final_features) +{ + if (!vdev || !final_features) + return -EINVAL; + + if (!vdev->func || !vdev->func->negotiate_features) + return -ENXIO; + + *final_features = vdev->func->negotiate_features(vdev, features); + return 0; +} + +/** + * @brief Reset virtio device. + * + * @param vdev Pointer to virtio_device structure. + * + * @return 0 on success, otherwise error code. + */ +static inline int virtio_reset_device(struct virtio_device *vdev) +{ + if (!vdev) + return -EINVAL; + + if (!vdev->func || !vdev->func->reset_device) + return -ENXIO; + + vdev->func->reset_device(vdev); + return 0; +} + +#if defined __cplusplus +} +#endif + +#endif /* _VIRTIO_H_ */ diff --git a/libraries/openamp_arduino/src/openamp/virtio_mmio.h b/libraries/openamp_arduino/src/openamp/virtio_mmio.h new file mode 100644 index 0000000..db678f6 --- /dev/null +++ b/libraries/openamp_arduino/src/openamp/virtio_mmio.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2022 Wind River Systems, Inc. + * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007 + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef OPENAMP_VIRTIO_MMIO_H +#define OPENAMP_VIRTIO_MMIO_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enable support for legacy devices */ +#define VIRTIO_MMIO_LEGACY + +/* Control registers */ + +/* Magic value ("virt" string) - Read Only */ +#define VIRTIO_MMIO_MAGIC_VALUE 0x000 + +#define VIRTIO_MMIO_MAGIC_VALUE_STRING ('v' | ('i' << 8) | ('r' << 16) | ('t' << 24)) + +/* Virtio device version - Read Only */ +#define VIRTIO_MMIO_VERSION 0x004 + +/* Virtio device ID - Read Only */ +#define VIRTIO_MMIO_DEVICE_ID 0x008 + +/* Virtio vendor ID - Read Only */ +#define VIRTIO_MMIO_VENDOR_ID 0x00c + +/* + * Bitmask of the features supported by the device (host) + * (32 bits per set) - Read Only + */ +#define VIRTIO_MMIO_DEVICE_FEATURES 0x010 + +/* Device (host) features set selector - Write Only */ +#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 + +/* + * Bitmask of features activated by the driver (guest) + * (32 bits per set) - Write Only + */ +#define VIRTIO_MMIO_DRIVER_FEATURES 0x020 + +/* Activated features set selector - Write Only */ +#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 + +#ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */ +/* Guest's memory page size in bytes - Write Only */ +#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 +#endif + +/* Queue selector - Write Only */ +#define VIRTIO_MMIO_QUEUE_SEL 0x030 + +/* Maximum size of the currently selected queue - Read Only */ +#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 + +/* Queue size for the currently selected queue - Write Only */ +#define VIRTIO_MMIO_QUEUE_NUM 0x038 + +#ifdef VIRTIO_MMIO_LEGACY +/* Used Ring alignment for the currently selected queue - Write Only */ +#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c +/* Guest's PFN for the currently selected queue - Read Write */ +#define VIRTIO_MMIO_QUEUE_PFN 0x040 +#endif + +/* Ready bit for the currently selected queue - Read Write */ +#define VIRTIO_MMIO_QUEUE_READY 0x044 + +/* Queue notifier - Write Only */ +#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 + +/* Interrupt status - Read Only */ +#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 + +/* Interrupt acknowledge - Write Only */ +#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 + +/* Device status register - Read Write */ +#define VIRTIO_MMIO_STATUS 0x070 + +/* Selected queue's Descriptor Table address, 64 bits in two halves */ +#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 +#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 + +/* Selected queue's Available Ring address, 64 bits in two halves */ +#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 +#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 + +/* Selected queue's Used Ring address, 64 bits in two halves */ +#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 +#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 + +/* Shared memory region id */ +#define VIRTIO_MMIO_SHM_SEL 0x0ac + +/* Shared memory region length, 64 bits in two halves */ +#define VIRTIO_MMIO_SHM_LEN_LOW 0x0b0 +#define VIRTIO_MMIO_SHM_LEN_HIGH 0x0b4 + +/* Shared memory region base address, 64 bits in two halves */ +#define VIRTIO_MMIO_SHM_BASE_LOW 0x0b8 +#define VIRTIO_MMIO_SHM_BASE_HIGH 0x0bc + +/* Configuration atomicity value */ +#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc + +/* + * The config space is defined by each driver as + * the per-driver configuration space - Read Write + */ +#define VIRTIO_MMIO_CONFIG 0x100 + +/* Interrupt flags (re: interrupt status & acknowledge registers) */ +#define VIRTIO_MMIO_INT_VRING (1 << 0) +#define VIRTIO_MMIO_INT_CONFIG (1 << 1) + +/* Data buffer size for preallocated buffers before vring */ +#define VIRTIO_MMIO_MAX_DATA_SIZE 128 + +/** @brief VIRTIO MMIO memory area */ +struct virtio_mmio_dev_mem { + /** Memory region physical address */ + void *base; + + /** Memory region size */ + size_t size; +}; + +/** @brief A VIRTIO MMIO device */ +struct virtio_mmio_device { + /** Base virtio device structure */ + struct virtio_device vdev; + + /** Device configuration space metal_io_region */ + struct metal_io_region *cfg_io; + + /** Pre-shared memory space metal_io_region */ + struct metal_io_region *shm_io; + + /** Shared memory device */ + struct metal_device shm_device; + + /** VIRTIO device configuration space */ + struct virtio_mmio_dev_mem cfg_mem; + + /** VIRTIO device pre-shared memory */ + struct virtio_mmio_dev_mem shm_mem; + + /** VIRTIO_DEV_DRIVER or VIRTIO_DEV_DEVICE */ + unsigned int device_mode; + + /** Interrupt number */ + unsigned int irq; + + /** Custom user data */ + void *user_data; +}; + +/** + * @brief Register a VIRTIO device with the VIRTIO stack. + * + * @param dev Pointer to device structure. + * @param vq_num Number of virtqueues the device uses. + * @param vqs Array of pointers to vthe virtqueues used by the device. + */ +void virtio_mmio_register_device(struct virtio_device *vdev, int vq_num, struct virtqueue **vqs); + +/** + * @brief Setup a virtqueue structure. + * + * @param dev Pointer to device structure. + * @param idx Index of the virtqueue. + * @param vq Pointer to virtqueue structure. + * @param cb Pointer to virtqueue callback. Can be NULL. + * @param cb_arg Argument for the virtqueue callback. + * + * @return pointer to virtqueue structure. + */ +struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev, + unsigned int idx, + struct virtqueue *vq, + void (*cb)(void *), + void *cb_arg, + const char *vq_name); + +/** + * @brief VIRTIO MMIO device initialization. + * + * @param vmdev Pointer to virtio_mmio_device structure. + * @param virt_mem_ptr Guest virtio (shared) memory base address (virtual). + * @param cfg_mem_ptr Virtio device configuration memory base address (virtual). + * @param user_data Pointer to custom user data. + * + * @return int 0 for success. + */ +int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem_ptr, + uintptr_t cfg_mem_ptr, void *user_data); + +/** + * @brief VIRTIO MMIO interrupt service routine. + * + * @param vdev Pointer to virtio_device structure. + */ +void virtio_mmio_isr(struct virtio_device *vdev); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENAMP_VIRTIO_MMIO_H */ diff --git a/libraries/openamp_arduino/src/openamp/virtio_ring.h b/libraries/openamp_arduino/src/openamp/virtio_ring.h index c54f52b..60a9710 100755 --- a/libraries/openamp_arduino/src/openamp/virtio_ring.h +++ b/libraries/openamp_arduino/src/openamp/virtio_ring.h @@ -1,158 +1,218 @@ -/* - * Copyright Rusty Russell IBM Corporation 2007. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * $FreeBSD$ - */ - -#ifndef VIRTIO_RING_H -#define VIRTIO_RING_H - -#if defined __cplusplus -extern "C" { -#endif - -/* 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; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - uint16_t ring[0]; -#pragma GCC diagnostic pop -}; - -/* 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; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - struct vring_used_elem ring[0]; -#pragma GCC diagnostic pop -}; - -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) ((vr)->used->ring[(vr)->num].id & 0xFFFF) - -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 = (struct vring_used *) - (((unsigned long)&vr->avail->ring[num] + sizeof(uint16_t) + - 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); -} - -#if defined __cplusplus -} -#endif - -#endif /* VIRTIO_RING_H */ +/* + * Copyright Rusty Russell IBM Corporation 2007. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * $FreeBSD$ + */ + +#ifndef VIRTIO_RING_H +#define VIRTIO_RING_H + +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* 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 + +/** + * @brief VirtIO ring descriptors. + * + * The descriptor table refers to the buffers the driver is using for the + * device. addr is a physical address, and the buffers can be chained via \ref next. + * Each descriptor describes a buffer which is read-only for the device + * (“device-readable”) or write-only for the device (“device-writable”), but a + * chain of descriptors can contain both device-readable and device-writable + * buffers. + */ +METAL_PACKED_BEGIN +struct vring_desc { + /** Address (guest-physical) */ + uint64_t addr; + + /** Length */ + uint32_t len; + + /** Flags relevant to the descriptors */ + uint16_t flags; + + /** We chain unused descriptors via this, too */ + uint16_t next; +} METAL_PACKED_END; + +/** + * @brief Used to offer buffers to the device. + * + * Each ring entry refers to the head of a descriptor chain. It is only + * written by the driver and read by the device. + */ +METAL_PACKED_BEGIN +struct vring_avail { + /** Flag which determines whether device notifications are required */ + uint16_t flags; + + /** + * Indicates where the driver puts the next descriptor entry in the + * ring (modulo the queue size) + */ + uint16_t idx; + + /** The ring of descriptors */ + uint16_t ring[0]; +} METAL_PACKED_END; + +/* uint32_t is used here for ids for padding reasons. */ +METAL_PACKED_BEGIN +struct vring_used_elem { + union { + uint16_t event; + /* Index of start of used descriptor chain. */ + uint32_t id; + }; + /* Total length of the descriptor chain which was written to. */ + uint32_t len; +} METAL_PACKED_END; + +/** + * @brief The device returns buffers to this structure when done with them + * + * The structure is only written to by the device, and read by the driver. + */ +METAL_PACKED_BEGIN +struct vring_used { + /** Flag which determines whether device notifications are required */ + uint16_t flags; + + /** + * Indicates where the driver puts the next descriptor entry in the + * ring (modulo the queue size) + */ + uint16_t idx; + + /** The ring of descriptors */ + struct vring_used_elem ring[0]; +} METAL_PACKED_END; + +/** + * @brief The virtqueue layout structure + * + * Each virtqueue consists of; descriptor table, available ring, used ring, + * where each part is physically contiguous in guest memory. + * + * When the driver wants to send a buffer to the device, it fills in a slot in + * the descriptor table (or chains several together), and writes the descriptor + * index into the available ring. It then notifies the device. When the device + * has finished a buffer, it writes the descriptor index into the used ring, + * and sends an interrupt. + * + * 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. + */ +struct vring { + /** + * The maximum number of buffer descriptors in the virtqueue. + * The value is always a power of 2. + */ + unsigned int num; + + /** The actual buffer descriptors, 16 bytes each */ + struct vring_desc *desc; + + /** A ring of available descriptor heads with free-running index */ + struct vring_avail *avail; + + /** A ring of used descriptor heads with free-running index */ + struct vring_used *used; +}; + +/* + * 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) ((vr)->used->ring[(vr)->num].event) + +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 = (struct vring_used *) + (((unsigned long)&vr->avail->ring[num] + sizeof(uint16_t) + + 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); +} + +#if defined __cplusplus +} +#endif + +#endif /* VIRTIO_RING_H */ diff --git a/libraries/openamp_arduino/src/openamp/virtqueue.h b/libraries/openamp_arduino/src/openamp/virtqueue.h index 4f84e36..1a9d2e8 100755 --- a/libraries/openamp_arduino/src/openamp/virtqueue.h +++ b/libraries/openamp_arduino/src/openamp/virtqueue.h @@ -1,240 +1,414 @@ -#ifndef VIRTQUEUE_H_ -#define VIRTQUEUE_H_ - -/*- - * Copyright (c) 2011, Bryan Venteicher - * All rights reserved. - * - * SPDX-License-Identifier: BSD-2-Clause - * - * $FreeBSD$ - */ - -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -typedef uint8_t boolean; - -#include -#include -#include - -/*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 VQUEUE_SUCCESS 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) - -struct virtqueue_buf { - void *buf; - int len; -}; - -struct virtqueue { - struct virtio_device *vq_dev; - const char *vq_name; - uint16_t vq_queue_index; - uint16_t vq_nentries; - uint32_t vq_flags; - void (*callback)(struct virtqueue *vq); - void (*notify)(struct virtqueue *vq); - struct vring vq_ring; - uint16_t vq_free_cnt; - uint16_t vq_queued_cnt; - void *shm_io; /* opaque pointer to data needed to allow v2p & p2v */ - - /* - * 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; - -#ifdef VQUEUE_DEBUG - boolean vq_inuse; -#endif - - /* - * 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. - */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" - struct vq_desc_extra { - void *cookie; - uint16_t ndescs; - } vq_descx[0]; -#pragma GCC diagnostic pop -}; - -/* struct to hold vring specific information */ -struct vring_alloc_info { - void *vaddr; - uint32_t align; - uint16_t num_descs; - uint16_t pad; -}; - -typedef void vq_callback(struct virtqueue *); -typedef void vq_notify(struct virtqueue *); - -#ifdef VQUEUE_DEBUG -#include -#include - -#define VQASSERT(_vq, _exp, _msg) \ - do { \ - if (!(_exp)) { \ - metal_log(METAL_LOG_EMERGENCY, \ - "%s: %s - _msg", __func__, (_vq)->vq_name); \ - metal_assert(_exp); \ - } \ - } 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) \ - do { \ - if (((status_var) == 0) && (condition)) { \ - status_var = status_err; \ - } \ - } while (0) - -#define VQUEUE_BUSY(vq) \ - do { \ - if (!(vq)->vq_inuse) \ - (vq)->vq_inuse = true; \ - else \ - VQASSERT(vq, !(vq)->vq_inuse,\ - "VirtQueue already in use") \ - } while (0) - -#define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false) - -#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, - const char *name, struct vring_alloc_info *ring, - void (*callback)(struct virtqueue *vq), - void (*notify)(struct virtqueue *vq), - struct virtqueue *v_queue); - -/* - * virtqueue_set_shmem_io - * - * set virtqueue shared memory I/O region - * - * @vq - virt queue - * @io - pointer to the shared memory I/O region - */ -static inline void virtqueue_set_shmem_io(struct virtqueue *vq, - struct metal_io_region *io) -{ - vq->shm_io = io; -} - -int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, - int readable, int writable, void *cookie); - -void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx); - -void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, - uint32_t *len); - -int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, - uint32_t len); - -void virtqueue_disable_cb(struct virtqueue *vq); - -int virtqueue_enable_cb(struct virtqueue *vq); - -void virtqueue_kick(struct virtqueue *vq); - -/* -static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra) -{ - struct virtqueue *vqs; - uint32_t vq_size = sizeof(struct virtqueue) + - num_desc_extra * sizeof(struct vq_desc_extra); - - vqs = (struct virtqueue *)metal_allocate_memory(vq_size); - - if (vqs) { - memset(vqs, 0x00, vq_size); - } - - return vqs; -} -*/ - -void virtqueue_free(struct virtqueue *vq); - -void virtqueue_dump(struct virtqueue *vq); - -void virtqueue_notification(struct virtqueue *vq); - -uint32_t virtqueue_get_desc_size(struct virtqueue *vq); - -uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx); - -#if defined __cplusplus -} -#endif - -#endif /* VIRTQUEUE_H_ */ +#ifndef VIRTQUEUE_H_ +#define VIRTQUEUE_H_ + +/*- + * Copyright (c) 2011, Bryan Venteicher + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + * + * $FreeBSD$ + */ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/* 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 VQUEUE_SUCCESS 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 + +/* 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) + +/* cache invalidation helpers */ +#define CACHE_FLUSH(x, s) metal_cache_flush(x, s) +#define CACHE_INVALIDATE(x, s) metal_cache_invalidate(x, s) + +#ifdef VIRTIO_CACHED_VRINGS +#warning "VIRTIO_CACHED_VRINGS is deprecated, please use VIRTIO_USE_DCACHE" +#endif +#if defined(VIRTIO_CACHED_VRINGS) || defined(VIRTIO_USE_DCACHE) +#define VRING_FLUSH(x, s) CACHE_FLUSH(x, s) +#define VRING_INVALIDATE(x, s) CACHE_INVALIDATE(x, s) +#else +#define VRING_FLUSH(x, s) do { } while (0) +#define VRING_INVALIDATE(x, s) do { } while (0) +#endif /* VIRTIO_CACHED_VRINGS || VIRTIO_USE_DCACHE */ + +/** @brief Buffer descriptor. */ +struct virtqueue_buf { + /** Address of the buffer. */ + void *buf; + + /** Size of the buffer. */ + int len; +}; + +/** @brief Vring descriptor extra information for buffer list management. */ +struct vq_desc_extra { + /** Pointer to first descriptor. */ + void *cookie; + + /** Number of chained descriptors. */ + uint16_t ndescs; +}; + +/** @brief Local virtio queue to manage a virtio ring for sending or receiving. */ +struct virtqueue { + /** Associated virtio device. */ + struct virtio_device *vq_dev; + + /** Name of the virtio queue. */ + const char *vq_name; + + /** Index of the virtio queue. */ + uint16_t vq_queue_index; + + /** Max number of buffers in the virtio queue. */ + uint16_t vq_nentries; + + /** Function to invoke, when message is available on the virtio queue. */ + void (*callback)(struct virtqueue *vq); + + /** Private data associated to the virtio queue. */ + void *priv; + + /** Function to invoke, to inform the other side about an update in the virtio queue. */ + void (*notify)(struct virtqueue *vq); + + /** Associated virtio ring. */ + struct vring vq_ring; + + /** Number of free descriptor in the virtio ring. */ + uint16_t vq_free_cnt; + + /** Number of queued buffer in the virtio ring. */ + uint16_t vq_queued_cnt; + + /** + * Metal I/O region of the vrings and buffers. + * This structure is used for conversion between virtual and physical addresses. + */ + void *shm_io; + + /** + * 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; + +#ifdef VQUEUE_DEBUG + /** Debug counter for virtqueue reentrance check. */ + bool vq_inuse; +#endif + + /** + * 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 vq_descx[0]; +}; + +/** @brief Virtio ring specific information. */ +struct vring_alloc_info { + /** Vring address. */ + void *vaddr; + + /** Vring alignment. */ + uint32_t align; + + /** Number of descriptors in the vring. */ + uint16_t num_descs; + + /** Padding */ + uint16_t pad; +}; + +typedef void (*vq_callback)(struct virtqueue *); +typedef void (*vq_notify)(struct virtqueue *); + +#ifdef VQUEUE_DEBUG +#include +#include + +#define VQASSERT(_vq, _exp, _msg) \ + do { \ + if (!(_exp)) { \ + metal_log(METAL_LOG_EMERGENCY, \ + "%s: %s - "_msg, __func__, (_vq)->vq_name); \ + metal_assert(_exp); \ + } \ + } 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) \ + do { \ + if (((status_var) == 0) && (condition)) { \ + status_var = status_err; \ + } \ + } while (0) + +#define VQUEUE_BUSY(vq) \ + do { \ + if (!(vq)->vq_inuse) \ + (vq)->vq_inuse = true; \ + else \ + VQASSERT(vq, !(vq)->vq_inuse,\ + "VirtQueue already in use"); \ + } while (0) + +#define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false) + +#else + +#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 + +/** + * @internal + * + * @brief 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 vq Created VirtIO queue. + * + * @return Function status + */ +int virtqueue_create(struct virtio_device *device, unsigned short id, + const char *name, struct vring_alloc_info *ring, + void (*callback)(struct virtqueue *vq), + void (*notify)(struct virtqueue *vq), + struct virtqueue *vq); + +/* + * virtqueue_set_shmem_io + * + * set virtqueue shared memory I/O region + * + * @vq - virt queue + * @io - pointer to the shared memory I/O region + */ +static inline void virtqueue_set_shmem_io(struct virtqueue *vq, + struct metal_io_region *io) +{ + vq->shm_io = io; +} + +/** + * @internal + * + * @brief 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 buf_list Pointer to a list of virtqueue buffers. + * @param readable Number of readable buffers + * @param writable Number of writable buffers + * @param cookie Pointer to hold call back data + * + * @return Function status + */ +int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, + int readable, int writable, void *cookie); + +/** + * @internal + * + * @brief Returns used buffers from VirtIO queue + * + * @param vq Pointer to VirtIO queue control block + * @param len Length of conumed buffer + * @param idx Index of the buffer + * + * @return Pointer to used buffer + */ +void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx); + +/** + * @internal + * + * @brief 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); + +/** + * @internal + * + * @brief 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, + uint32_t len); + +/** + * @internal + * + * @brief Disables callback generation + * + * @param vq Pointer to VirtIO queue control block + */ +void virtqueue_disable_cb(struct virtqueue *vq); + +/** + * @internal + * + * @brief Enables callback generation + * + * @param vq Pointer to VirtIO queue control block + * + * @return Function status + */ +int virtqueue_enable_cb(struct virtqueue *vq); + +/** + * @internal + * + * @brief Notifies other side that there is buffer available for it. + * + * @param vq Pointer to VirtIO queue control block + */ +void virtqueue_kick(struct virtqueue *vq); + +static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra) +{ + struct virtqueue *vqs; + uint32_t vq_size = sizeof(struct virtqueue) + + num_desc_extra * sizeof(struct vq_desc_extra); + + vqs = (struct virtqueue *)metal_allocate_memory(vq_size); + if (vqs) { + memset(vqs, 0x00, vq_size); + } + + return vqs; +} + +/** + * @internal + * + * @brief Frees VirtIO queue resources + * + * @param vq Pointer to VirtIO queue control block + */ +void virtqueue_free(struct virtqueue *vq); + +/** + * @internal + * + * @brief Dumps important virtqueue fields , use for debugging purposes + * + * @param vq Pointer to VirtIO queue control block + */ +void virtqueue_dump(struct virtqueue *vq); + +void virtqueue_notification(struct virtqueue *vq); + +/** + * @internal + * + * @brief Returns vring descriptor size + * + * @param vq Pointer to VirtIO queue control block + * + * @return Descriptor length + */ +uint32_t virtqueue_get_desc_size(struct virtqueue *vq); + +uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx); +void *virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx); + +/** + * @brief Test if virtqueue is empty + * + * @param vq Pointer to VirtIO queue control block + * + * @return 1 if virtqueue is empty, 0 otherwise + */ +static inline int virtqueue_empty(struct virtqueue *vq) +{ + return (vq->vq_nentries == vq->vq_free_cnt); +} + +/** + * @brief Test if virtqueue is full + * + * @param vq Pointer to VirtIO queue control block + * + * @return 1 if virtqueue is full, 0 otherwise + */ +static inline int virtqueue_full(struct virtqueue *vq) +{ + return (vq->vq_free_cnt == 0); +} + +#if defined __cplusplus +} +#endif + +#endif /* VIRTQUEUE_H_ */ diff --git a/libraries/openamp_arduino/src/openamp_conf.h b/libraries/openamp_arduino/src/openamp_conf.h index 96e9d57..c39a41f 100644 --- a/libraries/openamp_arduino/src/openamp_conf.h +++ b/libraries/openamp_arduino/src/openamp_conf.h @@ -1,231 +1,232 @@ -/** - ****************************************************************************** - * @file : openamp_conf.h - * @brief : Configuration file for OpenAMP MW - ****************************************************************************** - * @attention - * - * Copyright (c) 2018 STMicroelectronics International N.V. - * All rights reserved. - * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __OPENAMP_CONF__H__ -#define __OPENAMP_CONF__H__ - -#ifdef __cplusplus - extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#if defined (__LOG_TRACE_IO_) || defined(__LOG_UART_IO_) -#include "log.h" -#endif - - /* ########################## Mailbox Interface Selection ############################## */ - /** - * @brief This is the list of Mailbox interface to be used in the OpenAMP MW - * Please note that not all interfaces are supported by a STM32 device - */ -//#define MAILBOX_IPCC_IF_ENABLED -#define MAILBOX_HSEM_IF_ENABLED - - /* Includes ------------------------------------------------------------------*/ - /** - * @brief Include Maibox interface header file - */ - -#ifdef MAILBOX_IPCC_IF_ENABLED -#include "mbox_ipcc.h" -#endif /* MAILBOX_IPCC_IF_ENABLED */ - -#ifdef MAILBOX_HSEM_IF_ENABLED -#include "mbox_hsem.h" -#endif /* MAILBOX_HSEM_IF_ENABLED */ - - /* ########################## Virtual Diver Module Selection ############################## */ - /** - * @brief This is the list of modules to be used in the OpenAMP Virtual driver module - * Please note that virtual driver are not supported on all stm32 families - */ -//#define VIRTUAL_UART_MODULE_ENABLED -//#define VIRTUAL_I2C_MODULE_ENABLED - - - /* Includes ------------------------------------------------------------------*/ - /** - * @brief Include Virtual Driver module's header file - */ - -#ifdef VIRTUAL_UART_MODULE_ENABLED -#include "virt_uart.h" -#endif /* VIRTUAL_UART_MODULE_ENABLED */ - -#ifdef VIRTUAL_I2C_MODULE_ENABLED -#include "virt_i2c.h" -#endif /* VIRTUAL_I2C_MODULE_ENABLED */ - - - -/* USER CODE BEGIN INCLUDE */ - -/* USER CODE END INCLUDE */ - -/** @addtogroup OPENAMP_MW - * @{ - */ - -/** @defgroup OPENAMP_CONF OPENAMP_CONF - * @brief Configuration file for Openamp mw - * @{ - */ - -/** @defgroup OPENAMP_CONF_Exported_Variables OPENAMP_CONF_Exported_Variables - * @brief Public variables. - * @{ - */ - -/** - * @} - */ - -/** @defgroup OPENAMP_CONF_Exported_Defines OPENAMP_CONF_Exported_Defines - * @brief Defines for configuration of the Openamp mw - * @{ - */ - - -#if defined (__ICCARM__) -/* - * For IAR, the .icf file should contain the following lines: - * define symbol __OPENAMP_region_start__ = BASE_ADDRESS; (0x38000400 for example) - * define symbol __OPENAMP_region_size__ = MEM_SIZE; (0xB000 as example) - * - * export symbol __OPENAMP_region_start__; - * export symbol __OPENAMP_region_size__; - */ -extern const uint32_t __OPENAMP_region_start__; -extern const uint8_t __OPENAMP_region_size__; -#define SHM_START_ADDRESS ((metal_phys_addr_t)&__OPENAMP_region_start__) -#define SHM_SIZE ((size_t)&__OPENAMP_region_size__) - -#elif defined(__CC_ARM) -/* - * For MDK-ARM, the scatter file .sct should contain the following line: - * LR_IROM1 .... { - * ... - * __OpenAMP_SHMEM__ 0x38000400 EMPTY 0x0000B000 {} ; Shared Memory area used by OpenAMP - * } - * - */ -extern unsigned int Image$$__OpenAMP_SHMEM__$$Base; -extern unsigned int Image$$__OpenAMP_SHMEM__$$ZI$$Length; -#define SHM_START_ADDRESS (unsigned int)&Image$$__OpenAMP_SHMEM__$$Base -#define SHM_SIZE ((size_t)&Image$$__OpenAMP_SHMEM__$$ZI$$Length) - -#else -/* - * for GCC add the following content to the .ld file: - * MEMORY - * { - * ... - * OPEN_AMP_SHMEM (xrw) : ORIGIN = 0x38000400, LENGTH = 63K - * } - * __OPENAMP_region_start__ = ORIGIN(OPEN_AMP_SHMEM); - * __OPENAMP_region_end__ = ORIGIN(OPEN_AMP_SHMEM) + LENGTH(OPEN_AMP_SHMEM); - * - * using the LENGTH(OPEN_AMP_SHMEM) to set the SHM_SIZE lead to a crash thus we - * use the start and end address. - */ - -extern int __OPENAMP_region_start__[]; -extern int __OPENAMP_region_end__[]; - -#define SHM_START_ADDRESS ((metal_phys_addr_t)__OPENAMP_region_start__) -#define SHM_SIZE (size_t)((void *)__OPENAMP_region_end__ - (void *) __OPENAMP_region_start__) - -#endif - -#define VRING_RX_ADDRESS SHM_START_ADDRESS -#define VRING_TX_ADDRESS (SHM_START_ADDRESS + 0x400) -#define VRING_BUFF_ADDRESS (SHM_START_ADDRESS + 0x800) -#define VRING_ALIGNMENT 4 -#define VRING_NUM_BUFFS 16 /* number of rpmsg buffers */ - -/* Fixed parameter */ -#define NUM_RESOURCE_ENTRIES 2 -#define VRING_COUNT 2 - -#define VDEV_ID 0xFF -#define VRING0_ID 0 /* VRING0 ID (master to remote) fixed to 0 for linux compatibility*/ -#define VRING1_ID 1 /* VRING1 ID (remote to master) fixed to 1 for linux compatibility */ - -/** - * @} - */ - -/** @defgroup OPENAMP_CONF_Exported_Macros OPENAMP_CONF_Exported_Macros - * @brief Aliases. - * @{ - */ - -/* DEBUG macros */ - -#if defined (__LOG_TRACE_IO_) || defined(__LOG_UART_IO_) - #define OPENAMP_log_dbg log_dbg - #define OPENAMP_log_info log_info - #define OPENAMP_log_warn log_warn - #define OPENAMP_log_err log_err -#else - #define OPENAMP_log_dbg(...) - #define OPENAMP_log_info(...) - #define OPENAMP_log_warn(...) - #define OPENAMP_log_err(...) -#endif - -/** - * @} - */ - -/** @defgroup OPENAMP_CONF_Exported_Types OPENAMP_CONF_Exported_Types - * @brief Types. - * @{ - */ - -/** - * @} - */ - -/** @defgroup OPENAMP_CONF_Exported_FunctionsPrototype OPENAMP_CONF_Exported_FunctionsPrototype - * @brief Declaration of public functions for OpenAMP mw. - * @{ - */ - -/* Exported functions -------------------------------------------------------*/ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __OPENAMP_CONF__H__ */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +/** + ****************************************************************************** + * @file : openamp_conf.h + * @brief : Configuration file for OpenAMP MW + ****************************************************************************** + * @attention + * + * Copyright (c) 2018 STMicroelectronics International N.V. + * All rights reserved. + * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __OPENAMP_CONF__H__ +#define __OPENAMP_CONF__H__ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#if defined (__LOG_TRACE_IO_) || defined(__LOG_UART_IO_) +#include "log.h" +#endif + + /* ########################## Mailbox Interface Selection ############################## */ + /** + * @brief This is the list of Mailbox interface to be used in the OpenAMP MW + * Please note that not all interfaces are supported by a STM32 device + */ +//#define MAILBOX_IPCC_IF_ENABLED +#define MAILBOX_HSEM_IF_ENABLED + + /* Includes ------------------------------------------------------------------*/ + /** + * @brief Include Maibox interface header file + */ + +#ifdef MAILBOX_IPCC_IF_ENABLED +#include "mbox_ipcc.h" +#endif /* MAILBOX_IPCC_IF_ENABLED */ + +#ifdef MAILBOX_HSEM_IF_ENABLED +#include "mbox_hsem.h" +#endif /* MAILBOX_HSEM_IF_ENABLED */ + + /* ########################## Virtual Diver Module Selection ############################## */ + /** + * @brief This is the list of modules to be used in the OpenAMP Virtual driver module + * Please note that virtual driver are not supported on all stm32 families + */ +//#define VIRTUAL_UART_MODULE_ENABLED +//#define VIRTUAL_I2C_MODULE_ENABLED + + + /* Includes ------------------------------------------------------------------*/ + /** + * @brief Include Virtual Driver module's header file + */ + +#ifdef VIRTUAL_UART_MODULE_ENABLED +#include "virt_uart.h" +#endif /* VIRTUAL_UART_MODULE_ENABLED */ + +#ifdef VIRTUAL_I2C_MODULE_ENABLED +#include "virt_i2c.h" +#endif /* VIRTUAL_I2C_MODULE_ENABLED */ + + + +/* USER CODE BEGIN INCLUDE */ + +/* USER CODE END INCLUDE */ + +/** @addtogroup OPENAMP_MW + * @{ + */ + +/** @defgroup OPENAMP_CONF OPENAMP_CONF + * @brief Configuration file for Openamp mw + * @{ + */ + +/** @defgroup OPENAMP_CONF_Exported_Variables OPENAMP_CONF_Exported_Variables + * @brief Public variables. + * @{ + */ + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_Defines OPENAMP_CONF_Exported_Defines + * @brief Defines for configuration of the Openamp mw + * @{ + */ + + +#if defined (__ICCARM__) +/* + * For IAR, the .icf file should contain the following lines: + * define symbol __OPENAMP_region_start__ = BASE_ADDRESS; (0x38000400 for example) + * define symbol __OPENAMP_region_size__ = MEM_SIZE; (0xB000 as example) + * + * export symbol __OPENAMP_region_start__; + * export symbol __OPENAMP_region_size__; + */ +extern const uint32_t __OPENAMP_region_start__; +extern const uint8_t __OPENAMP_region_size__; +#define SHM_START_ADDRESS ((metal_phys_addr_t)&__OPENAMP_region_start__) +#define SHM_SIZE ((size_t)&__OPENAMP_region_size__) + +#elif defined(__CC_ARM) +/* + * For MDK-ARM, the scatter file .sct should contain the following line: + * LR_IROM1 .... { + * ... + * __OpenAMP_SHMEM__ 0x38000400 EMPTY 0x0000B000 {} ; Shared Memory area used by OpenAMP + * } + * + */ +extern unsigned int Image$$__OpenAMP_SHMEM__$$Base; +extern unsigned int Image$$__OpenAMP_SHMEM__$$ZI$$Length; +#define SHM_START_ADDRESS (unsigned int)&Image$$__OpenAMP_SHMEM__$$Base +#define SHM_SIZE ((size_t)&Image$$__OpenAMP_SHMEM__$$ZI$$Length) + +#else +/* + * for GCC add the following content to the .ld file: + * MEMORY + * { + * ... + * OPEN_AMP_SHMEM (xrw) : ORIGIN = 0x38000400, LENGTH = 63K + * } + * __OPENAMP_region_start__ = ORIGIN(OPEN_AMP_SHMEM); + * __OPENAMP_region_end__ = ORIGIN(OPEN_AMP_SHMEM) + LENGTH(OPEN_AMP_SHMEM); + * + * using the LENGTH(OPEN_AMP_SHMEM) to set the SHM_SIZE lead to a crash thus we + * use the start and end address. + */ + +extern int __OPENAMP_region_start__[]; +extern int __OPENAMP_region_end__[]; + +#define SHM_START_ADDRESS ((metal_phys_addr_t)__OPENAMP_region_start__) +#define SHM_SIZE (size_t)((void *)__OPENAMP_region_end__ - (void *) __OPENAMP_region_start__) + +#endif + +#define VRING_RX_ADDRESS SHM_START_ADDRESS +#define VRING_TX_ADDRESS (SHM_START_ADDRESS + 0x1000) +#define VRING_BUFF_ADDRESS (SHM_START_ADDRESS + 0x2000) +#define VRING_BUFF_SIZE (SHM_SIZE - 0x2000) +#define VRING_ALIGNMENT 32 +#define VRING_NUM_BUFFS 16 /* number of rpmsg buffers */ + +/* Fixed parameter */ +#define NUM_RESOURCE_ENTRIES 2 +#define VRING_COUNT 2 + +#define VDEV_ID 0xFF +#define VRING0_ID 0 /* VRING0 ID (master to remote) fixed to 0 for linux compatibility*/ +#define VRING1_ID 1 /* VRING1 ID (remote to master) fixed to 1 for linux compatibility */ + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_Macros OPENAMP_CONF_Exported_Macros + * @brief Aliases. + * @{ + */ + +/* DEBUG macros */ + +#if defined (__LOG_TRACE_IO_) || defined(__LOG_UART_IO_) + #define OPENAMP_log_dbg log_dbg + #define OPENAMP_log_info log_info + #define OPENAMP_log_warn log_warn + #define OPENAMP_log_err log_err +#else + #define OPENAMP_log_dbg(...) + #define OPENAMP_log_info(...) + #define OPENAMP_log_warn(...) + #define OPENAMP_log_err(...) +#endif + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_Types OPENAMP_CONF_Exported_Types + * @brief Types. + * @{ + */ + +/** + * @} + */ + +/** @defgroup OPENAMP_CONF_Exported_FunctionsPrototype OPENAMP_CONF_Exported_FunctionsPrototype + * @brief Declaration of public functions for OpenAMP mw. + * @{ + */ + +/* Exported functions -------------------------------------------------------*/ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENAMP_CONF__H__ */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/openamp_arduino/src/remoteproc.c b/libraries/openamp_arduino/src/remoteproc.c new file mode 100644 index 0000000..ad16a2d --- /dev/null +++ b/libraries/openamp_arduino/src/remoteproc.c @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * All rights reserved. + * Copyright (c) 2015 Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * static functions + *****************************************************************************/ +static const struct loader_ops * +remoteproc_check_fw_format(const void *img_data, size_t img_len) +{ + if (img_len <= 0) + return NULL; + else if (elf_identify(img_data, img_len) == 0) + return &elf_ops; + else + return NULL; +} + +/* try the internal list added by remoteproc_add_mem first and then get_mem callback */ +static struct remoteproc_mem * +remoteproc_get_mem(struct remoteproc *rproc, const char *name, + metal_phys_addr_t pa, metal_phys_addr_t da, + void *va, size_t size, struct remoteproc_mem *buf) +{ + struct metal_list *node; + struct remoteproc_mem *mem; + + /* + * Check name length to avoid overflow. This test has to be kept for + * MISRA compliance + */ + if (name && strlen(name) > RPROC_MAX_NAME_LEN) + return NULL; + + metal_list_for_each(&rproc->mems, node) { + mem = metal_container_of(node, struct remoteproc_mem, node); + if (name) { + if (!strncmp(name, mem->name, RPROC_MAX_NAME_LEN)) + return mem; + } else if (pa != METAL_BAD_PHYS) { + metal_phys_addr_t pa_start, pa_end; + + pa_start = mem->pa; + pa_end = pa_start + mem->size; + if (pa >= pa_start && (pa + size) <= pa_end && pa < pa_end) + return mem; + } else if (da != METAL_BAD_PHYS) { + metal_phys_addr_t da_start, da_end; + + da_start = mem->da; + da_end = da_start + mem->size; + if (da >= da_start && (da + size) <= da_end && da < da_end) + return mem; + } else if (va) { + if (metal_io_virt_to_offset(mem->io, va) != + METAL_BAD_OFFSET) + return mem; + + } else { + return NULL; + } + } + + if (!rproc->ops->get_mem) + return NULL; + + return rproc->ops->get_mem(rproc, name, pa, da, va, size, buf); +} + +static metal_phys_addr_t +remoteproc_datopa(struct remoteproc_mem *mem, metal_phys_addr_t da) +{ + metal_phys_addr_t pa; + + pa = mem->pa + da - mem->da; + return pa; +} + +static metal_phys_addr_t +remoteproc_patoda(struct remoteproc_mem *mem, metal_phys_addr_t pa) +{ + metal_phys_addr_t da; + + da = mem->da + pa - mem->pa; + return da; +} + +static void *remoteproc_get_rsc_table(struct remoteproc *rproc, + void *store, + const struct image_store_ops *store_ops, + size_t offset, + size_t len) +{ + int ret; + void *rsc_table = NULL; + const void *img_data; + + /* Copy the resource table to local memory, + * the caller should be responsible to release the memory + */ + rsc_table = metal_allocate_memory(len); + if (!rsc_table) { + return RPROC_ERR_PTR(-RPROC_ENOMEM); + } + ret = store_ops->load(store, offset, len, &img_data, RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < 0 || ret < (int)len || !img_data) { + metal_log(METAL_LOG_ERROR, + "get rsc failed: 0x%llx, 0x%llx\r\n", offset, len); + ret = -RPROC_EINVAL; + goto error; + } + memcpy(rsc_table, img_data, len); + + ret = handle_rsc_table(rproc, rsc_table, len, NULL); + if (ret < 0) { + goto error; + } + return rsc_table; + +error: + metal_free_memory(rsc_table); + return RPROC_ERR_PTR(ret); +} + +static int remoteproc_parse_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size) +{ + struct metal_io_region *io; + + if (!rsc_table) + return -RPROC_EINVAL; + + io = remoteproc_get_io_with_va(rproc, rsc_table); + return handle_rsc_table(rproc, rsc_table, rsc_size, io); +} + +int remoteproc_set_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, + size_t rsc_size) +{ + int ret; + struct metal_io_region *io; + + if (!rproc || !rsc_table || rsc_size == 0) + return -RPROC_EINVAL; + + io = remoteproc_get_io_with_va(rproc, rsc_table); + if (!io) + return -RPROC_EINVAL; + ret = remoteproc_parse_rsc_table(rproc, rsc_table, rsc_size); + if (!ret) { + rproc->rsc_table = rsc_table; + rproc->rsc_len = rsc_size; + rproc->rsc_io = io; + } + return ret; +} + +struct remoteproc *remoteproc_init(struct remoteproc *rproc, + const struct remoteproc_ops *ops, void *priv) +{ + if (!rproc || !ops) + return NULL; + + memset(rproc, 0, sizeof(*rproc)); + rproc->state = RPROC_OFFLINE; + metal_mutex_init(&rproc->lock); + metal_list_init(&rproc->mems); + metal_list_init(&rproc->vdevs); + rproc = ops->init(rproc, ops, priv); + return rproc; +} + +int remoteproc_remove(struct remoteproc *rproc) +{ + int ret = 0; + + if (!rproc) + return -RPROC_EINVAL; + + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_OFFLINE) { + if (rproc->ops->remove) + rproc->ops->remove(rproc); + } else { + ret = -RPROC_EAGAIN; + } + metal_mutex_release(&rproc->lock); + return ret; +} + +int remoteproc_config(struct remoteproc *rproc, void *data) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_OFFLINE) { + /* configure operation is allowed if the state is + * offline or ready. This function can be called + * multiple times before start the remote. + */ + if (rproc->ops->config) + ret = rproc->ops->config(rproc, data); + else + ret = 0; + rproc->state = RPROC_READY; + } else { + ret = -RPROC_EINVAL; + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_start(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state == RPROC_READY) { + ret = rproc->ops->start(rproc); + rproc->state = RPROC_RUNNING; + } else { + ret = -RPROC_EINVAL; + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_stop(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + metal_mutex_acquire(&rproc->lock); + if (rproc->state != RPROC_STOPPED && + rproc->state != RPROC_OFFLINE) { + if (rproc->ops->stop) + ret = rproc->ops->stop(rproc); + rproc->state = RPROC_STOPPED; + } else { + ret = 0; + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +int remoteproc_shutdown(struct remoteproc *rproc) +{ + int ret = -RPROC_ENODEV; + + if (rproc) { + ret = 0; + metal_mutex_acquire(&rproc->lock); + if (rproc->state != RPROC_OFFLINE) { + if (rproc->state != RPROC_STOPPED) { + if (rproc->ops->stop) + ret = rproc->ops->stop(rproc); + } + if (!ret) { + if (rproc->ops->shutdown) + ret = rproc->ops->shutdown(rproc); + if (!ret) { + rproc->state = RPROC_OFFLINE; + } + } + } + metal_mutex_release(&rproc->lock); + } + return ret; +} + +struct metal_io_region * +remoteproc_get_io_with_name(struct remoteproc *rproc, + const char *name) +{ + struct remoteproc_mem *mem; + struct remoteproc_mem buf; + + if (!rproc) + return NULL; + + mem = remoteproc_get_mem(rproc, name, + METAL_BAD_PHYS, METAL_BAD_PHYS, NULL, 0, &buf); + if (mem) + return mem->io; + + return NULL; +} + +struct metal_io_region * +remoteproc_get_io_with_pa(struct remoteproc *rproc, + metal_phys_addr_t pa) +{ + struct remoteproc_mem *mem; + struct remoteproc_mem buf; + + if (!rproc) + return NULL; + + mem = remoteproc_get_mem(rproc, NULL, pa, METAL_BAD_PHYS, NULL, 0, &buf); + if (mem) + return mem->io; + + return NULL; +} + +struct metal_io_region * +remoteproc_get_io_with_da(struct remoteproc *rproc, + metal_phys_addr_t da, + unsigned long *offset) +{ + struct remoteproc_mem *mem; + struct remoteproc_mem buf; + + if (!rproc || !offset) + return NULL; + + mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, da, NULL, 0, &buf); + if (mem) { + struct metal_io_region *io; + metal_phys_addr_t pa; + + io = mem->io; + pa = remoteproc_datopa(mem, da); + *offset = metal_io_phys_to_offset(io, pa); + return io; + } + + return NULL; +} + +struct metal_io_region * +remoteproc_get_io_with_va(struct remoteproc *rproc, void *va) +{ + struct remoteproc_mem *mem; + struct remoteproc_mem buf; + + if (!rproc) + return NULL; + + mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, METAL_BAD_PHYS, + va, 0, &buf); + if (mem) + return mem->io; + + return NULL; +} + +void *remoteproc_mmap(struct remoteproc *rproc, + metal_phys_addr_t *pa, metal_phys_addr_t *da, + size_t size, unsigned int attribute, + struct metal_io_region **io) +{ + void *va = NULL; + metal_phys_addr_t lpa, lda; + struct remoteproc_mem *mem; + struct remoteproc_mem buf; + + if (!rproc || size == 0 || (!pa && !da)) + return NULL; + if (pa) + lpa = *pa; + else + lpa = METAL_BAD_PHYS; + if (da) + lda = *da; + else + lda = METAL_BAD_PHYS; + mem = remoteproc_get_mem(rproc, NULL, lpa, lda, NULL, size, &buf); + if (mem) { + if (lpa != METAL_BAD_PHYS) + lda = remoteproc_patoda(mem, lpa); + else if (lda != METAL_BAD_PHYS) + lpa = remoteproc_datopa(mem, lda); + if (io) + *io = mem->io; + va = metal_io_phys_to_virt(mem->io, lpa); + } else if (rproc->ops->mmap) { + va = rproc->ops->mmap(rproc, &lpa, &lda, size, attribute, io); + } + + if (pa) + *pa = lpa; + if (da) + *da = lda; + return va; +} + +int remoteproc_load(struct remoteproc *rproc, const char *path, + void *store, const struct image_store_ops *store_ops, + void **img_info) +{ + int ret; + const struct loader_ops *loader; + const void *img_data; + void *limg_info = NULL; + size_t offset, noffset; + size_t len, nlen; + int last_load_state; + metal_phys_addr_t da, rsc_da; + size_t rsc_size = 0; + void *rsc_table = NULL; + struct metal_io_region *io = NULL; + + if (!rproc) + return -RPROC_ENODEV; + + metal_mutex_acquire(&rproc->lock); + metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__); + /* If remoteproc is not in ready state, cannot load executable */ + if (rproc->state != RPROC_READY && rproc->state != RPROC_CONFIGURED) { + metal_log(METAL_LOG_ERROR, + "load failure: invalid rproc state %d.\r\n", + rproc->state); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + if (!store_ops) { + metal_log(METAL_LOG_ERROR, + "load failure: loader ops is not set.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + /* Open executable to get ready to parse */ + metal_log(METAL_LOG_DEBUG, "%s: open executable image\r\n", __func__); + ret = store_ops->open(store, path, &img_data); + if (ret <= 0) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to open firmware %d.\r\n", + ret); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + len = ret; + metal_assert(img_data); + + /* Check executable format to select a parser */ + loader = rproc->loader; + if (!loader) { + metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__); + loader = remoteproc_check_fw_format(img_data, len); + if (!loader) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to get store ops.\r\n"); + ret = -RPROC_EINVAL; + goto error1; + } + rproc->loader = loader; + } + + /* Load executable headers */ + metal_log(METAL_LOG_DEBUG, "%s: loading headers\r\n", __func__); + offset = 0; + last_load_state = RPROC_LOADER_NOT_READY; + while (1) { + ret = loader->load_header(img_data, offset, len, + &limg_info, last_load_state, + &noffset, &nlen); + last_load_state = ret; + metal_log(METAL_LOG_DEBUG, + "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, noffset, nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load header failed 0x%lx,%d.\r\n", + offset, len); + + goto error2; + } else if ((ret & RPROC_LOADER_READY_TO_LOAD) != 0) { + if (nlen == 0) + break; + else if ((noffset > (offset + len)) && + (store_ops->features & SUPPORT_SEEK) == 0) { + /* Required data is not continued, however + * seek is not supported, stop to load + * headers such as ELF section headers which + * is usually located to the end of image. + * Continue to load binary data to target + * memory. + */ + break; + } + } + /* Continue to load headers image data */ + img_data = NULL; + ret = store_ops->load(store, noffset, nlen, + &img_data, + RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < (int)nlen) { + metal_log(METAL_LOG_ERROR, + "load image data failed 0x%x,%d\r\n", + noffset, nlen); + goto error2; + } + offset = noffset; + len = nlen; + } + ret = loader->locate_rsc_table(limg_info, &rsc_da, &offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + /* parse resource table */ + rsc_table = remoteproc_get_rsc_table(rproc, store, store_ops, + offset, rsc_size); + } + + /* load executable data */ + metal_log(METAL_LOG_DEBUG, "%s: load executable data\r\n", __func__); + offset = 0; + len = 0; + while (1) { + unsigned char padding; + size_t nmemsize; + metal_phys_addr_t pa; + + da = RPROC_LOAD_ANYADDR; + nlen = 0; + nmemsize = 0; + noffset = 0; + ret = loader->load_data(rproc, img_data, offset, len, + &limg_info, last_load_state, &da, + &noffset, &nlen, &padding, &nmemsize); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load data failed,0x%lx,%d\r\n", + noffset, nlen); + goto error3; + } + metal_log(METAL_LOG_DEBUG, + "load data: da 0x%lx, offset 0x%lx, len = 0x%lx, memsize = 0x%lx, state 0x%x\r\n", + da, noffset, nlen, nmemsize, ret); + last_load_state = ret; + if (da != RPROC_LOAD_ANYADDR) { + /* Data is supposed to be loaded to target memory */ + img_data = NULL; + /* get the I/O region from remoteproc */ + pa = METAL_BAD_PHYS; + (void)remoteproc_mmap(rproc, &pa, &da, nmemsize, 0, + &io); + if (pa == METAL_BAD_PHYS || !io) { + metal_log(METAL_LOG_ERROR, + "load failed, no mapping for 0x%llx.\r\n", + da); + ret = -RPROC_EINVAL; + goto error3; + } + if (nlen > 0) { + ret = store_ops->load(store, noffset, nlen, + &img_data, pa, io, 1); + if (ret != (int)nlen) { + metal_log(METAL_LOG_ERROR, + "load data failed 0x%lx, 0x%lx, 0x%x\r\n", + pa, noffset, nlen); + ret = -RPROC_EINVAL; + goto error3; + } + } + if (nmemsize > nlen) { + size_t tmpoffset; + + tmpoffset = metal_io_phys_to_offset(io, + pa + nlen); + metal_io_block_set(io, tmpoffset, + padding, (nmemsize - nlen)); + } + } else if (nlen != 0) { + ret = store_ops->load(store, noffset, nlen, + &img_data, + RPROC_LOAD_ANYADDR, + NULL, 1); + if (ret < (int)nlen) { + if ((last_load_state & + RPROC_LOADER_POST_DATA_LOAD) != 0) { + metal_log(METAL_LOG_WARNING, + "not all the headers are loaded\r\n"); + break; + } + metal_log(METAL_LOG_ERROR, + "post-load image data failed 0x%x,%d\r\n", + noffset, nlen); + goto error3; + } + offset = noffset; + len = nlen; + } else { + /* (last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0 */ + break; + } + } + + if (rsc_size == 0) { + ret = loader->locate_rsc_table(limg_info, &rsc_da, + &offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + /* parse resource table */ + rsc_table = remoteproc_get_rsc_table(rproc, store, + store_ops, + offset, + rsc_size); + } + } + + /* Update resource table */ + if (rsc_table) { + void *rsc_table_cp = rsc_table; + + metal_log(METAL_LOG_DEBUG, + "%s, update resource table\r\n", __func__); + rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da, + rsc_size, 0, &io); + if (rsc_table) { + size_t rsc_io_offset; + + /* Update resource table */ + rsc_io_offset = metal_io_virt_to_offset(io, rsc_table); + ret = metal_io_block_write(io, rsc_io_offset, + rsc_table_cp, rsc_size); + if (ret != (int)rsc_size) { + metal_log(METAL_LOG_WARNING, + "load: failed to update rsc\r\n"); + } + rproc->rsc_table = rsc_table; + rproc->rsc_len = rsc_size; + rproc->rsc_io = io; + } else { + metal_log(METAL_LOG_WARNING, + "load: not able to update rsc table.\r\n"); + } + metal_free_memory(rsc_table_cp); + /* So that the rsc_table will not get released */ + rsc_table = NULL; + } + + metal_log(METAL_LOG_DEBUG, "%s: successfully load firmware\r\n", + __func__); + /* get entry point from the firmware */ + rproc->bootaddr = loader->get_entry(limg_info); + rproc->state = RPROC_READY; + + metal_mutex_release(&rproc->lock); + if (img_info) + *img_info = limg_info; + else + loader->release(limg_info); + store_ops->close(store); + return 0; + +error3: + if (rsc_table) + metal_free_memory(rsc_table); +error2: + loader->release(limg_info); +error1: + store_ops->close(store); + metal_mutex_release(&rproc->lock); + return ret; +} + +int remoteproc_load_noblock(struct remoteproc *rproc, + const void *img_data, size_t offset, size_t len, + void **img_info, + metal_phys_addr_t *pa, struct metal_io_region **io, + size_t *noffset, size_t *nlen, + size_t *nmlen, unsigned char *padding) +{ + int ret; + const struct loader_ops *loader; + void *limg_info = NULL; + int last_load_state; + metal_phys_addr_t da, rsc_da; + size_t rsc_size; + void *rsc_table = NULL, *lrsc_table = NULL; + + if (!rproc) + return -RPROC_ENODEV; + + metal_assert(pa); + metal_assert(io); + metal_assert(noffset); + metal_assert(nlen); + metal_assert(nmlen); + metal_assert(padding); + + metal_mutex_acquire(&rproc->lock); + metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__); + /* If remoteproc is not in ready state, cannot load executable */ + if (rproc->state != RPROC_READY) { + metal_log(METAL_LOG_ERROR, + "load failure: invalid rproc state %d.\r\n", + rproc->state); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + + /* Check executable format to select a parser */ + loader = rproc->loader; + if (!loader) { + metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__); + if (!img_data || offset != 0 || len == 0) { + metal_log(METAL_LOG_ERROR, + "load failure, invalid inputs, not able to identify image.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + loader = remoteproc_check_fw_format(img_data, len); + if (!loader) { + metal_log(METAL_LOG_ERROR, + "load failure: failed to identify image.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + rproc->loader = loader; + } + if (!img_info || !*img_info) { + last_load_state = 0; + } else { + limg_info = *img_info; + last_load_state = loader->get_load_state(limg_info); + if (last_load_state < 0) { + metal_log(METAL_LOG_ERROR, + "load failure, not able get load state.\r\n"); + metal_mutex_release(&rproc->lock); + return -RPROC_EINVAL; + } + } + da = RPROC_LOAD_ANYADDR; + *nlen = 0; + if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0 && + (last_load_state & RPROC_LOADER_LOAD_COMPLETE) == 0) { + /* Get the mandatory executable headers */ + ret = loader->load_header(img_data, offset, len, + &limg_info, last_load_state, + noffset, nlen); + metal_log(METAL_LOG_DEBUG, + "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, *noffset, *nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load header failed 0x%lx,%d.\r\n", + offset, len); + goto error1; + } + last_load_state = ret; + if (*nlen != 0 && + (last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0) + goto out; + } + if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) != 0 || + (last_load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) { + /* Enough information to know which target memory for + * which data. + */ + ret = loader->load_data(rproc, img_data, offset, len, + &limg_info, last_load_state, &da, + noffset, nlen, padding, nmlen); + metal_log(METAL_LOG_DEBUG, + "%s, load data 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n", + __func__, offset, len, *noffset, *nlen); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load data failed,0x%lx,%d\r\n", + offset, len); + goto error1; + } + last_load_state = ret; + if (da != RPROC_LOAD_ANYADDR) { + /* get the I/O region from remoteproc */ + *pa = METAL_BAD_PHYS; + (void)remoteproc_mmap(rproc, pa, &da, *nmlen, 0, io); + if (*pa == METAL_BAD_PHYS || !io) { + metal_log(METAL_LOG_ERROR, + "load failed, no mapping for 0x%llx.\r\n", + da); + ret = -RPROC_EINVAL; + goto error1; + } + } + if (*nlen != 0) + goto out; + } + if ((last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0) { + /* Get resource table */ + size_t rsc_offset; + size_t rsc_io_offset; + + ret = loader->locate_rsc_table(limg_info, &rsc_da, + &rsc_offset, &rsc_size); + if (ret == 0 && rsc_size > 0) { + lrsc_table = metal_allocate_memory(rsc_size); + if (!lrsc_table) { + ret = -RPROC_ENOMEM; + goto error1; + } + rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da, + rsc_size, 0, io); + if (!*io) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to mmap rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + rsc_io_offset = metal_io_virt_to_offset(*io, rsc_table); + ret = metal_io_block_read(*io, rsc_io_offset, + lrsc_table, rsc_size); + if (ret != (int)rsc_size) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to get rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + /* parse resource table */ + ret = remoteproc_parse_rsc_table(rproc, lrsc_table, + rsc_size); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "load failed: failed to parse rsc\r\n"); + metal_free_memory(lrsc_table); + goto error1; + } + /* Update resource table */ + ret = metal_io_block_write(*io, rsc_io_offset, + lrsc_table, rsc_size); + if (ret != (int)rsc_size) { + metal_log(METAL_LOG_WARNING, + "load executable, failed to update rsc\r\n"); + } + rproc->rsc_table = rsc_table; + rproc->rsc_len = rsc_size; + rproc->rsc_io = *io; + metal_free_memory(lrsc_table); + } + + /* get entry point from the firmware */ + rproc->bootaddr = loader->get_entry(limg_info); + } +out: + if (img_info) + *img_info = limg_info; + else + loader->release(limg_info); + metal_mutex_release(&rproc->lock); + return 0; + +error1: + loader->release(limg_info); + metal_mutex_release(&rproc->lock); + return ret; +} + +unsigned int remoteproc_allocate_id(struct remoteproc *rproc, + unsigned int start, + unsigned int end) +{ + unsigned int notifyid = RSC_NOTIFY_ID_ANY; + + if (start == RSC_NOTIFY_ID_ANY) + start = 0; + if (end == RSC_NOTIFY_ID_ANY) + end = METAL_BITS_PER_ULONG; + if ((start < (8U * sizeof(rproc->bitmap))) && + (end <= (8U * sizeof(rproc->bitmap)))) { + notifyid = metal_bitmap_next_clear_bit(&rproc->bitmap, + start, end); + if (notifyid != end) + metal_bitmap_set_bit(&rproc->bitmap, notifyid); + else + notifyid = RSC_NOTIFY_ID_ANY; + } + return notifyid; +} + +static int remoteproc_virtio_notify(void *priv, uint32_t id) +{ + struct remoteproc *rproc = priv; + + if (rproc->ops->notify) + return rproc->ops->notify(rproc, id); + + return 0; +} + +struct virtio_device * +remoteproc_create_virtio(struct remoteproc *rproc, + int vdev_id, unsigned int role, + void (*rst_cb)(struct virtio_device *vdev)) +{ + char *rsc_table; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *vdev_rsc_io; + struct virtio_device *vdev; + struct remoteproc_virtio *rpvdev; + size_t vdev_rsc_offset; + unsigned int notifyid; + unsigned int num_vrings, i; + struct metal_list *node; + +#ifdef VIRTIO_DRIVER_ONLY + role = (role != VIRTIO_DEV_DRIVER) ? 0xFFFFFFFFUL : role; +#endif + +#ifdef VIRTIO_DEVICE_ONLY + role = (role != VIRTIO_DEV_DEVICE) ? 0xFFFFFFFFUL : role; +#endif + + if (!rproc || (role != VIRTIO_DEV_DEVICE && role != VIRTIO_DEV_DRIVER)) + return NULL; + + metal_assert(rproc); + metal_mutex_acquire(&rproc->lock); + rsc_table = rproc->rsc_table; + vdev_rsc_io = rproc->rsc_io; + vdev_rsc_offset = find_rsc(rsc_table, RSC_VDEV, vdev_id); + if (!vdev_rsc_offset) { + metal_mutex_release(&rproc->lock); + return NULL; + } + vdev_rsc = (struct fw_rsc_vdev *)(rsc_table + vdev_rsc_offset); + notifyid = vdev_rsc->notifyid; + /* Check if the virtio device is already created */ + metal_list_for_each(&rproc->vdevs, node) { + rpvdev = metal_container_of(node, struct remoteproc_virtio, + node); + if (rpvdev->vdev.notifyid == notifyid) { + metal_mutex_release(&rproc->lock); + return &rpvdev->vdev; + } + } + vdev = rproc_virtio_create_vdev(role, notifyid, + vdev_rsc, vdev_rsc_io, rproc, + remoteproc_virtio_notify, + rst_cb); + if (!vdev) { + metal_mutex_release(&rproc->lock); + return NULL; + } + + rproc_virtio_wait_remote_ready(vdev); + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_list_add_tail(&rproc->vdevs, &rpvdev->node); + num_vrings = vdev_rsc->num_of_vrings; + + /* set the notification id for vrings */ + for (i = 0; i < num_vrings; i++) { + struct fw_rsc_vdev_vring *vring_rsc; + metal_phys_addr_t da; + unsigned int num_descs, align; + struct metal_io_region *io; + void *va; + size_t size; + int ret; + + vring_rsc = &vdev_rsc->vring[i]; + notifyid = vring_rsc->notifyid; + da = vring_rsc->da; + num_descs = vring_rsc->num; + align = vring_rsc->align; + size = vring_size(num_descs, align); + va = remoteproc_mmap(rproc, NULL, &da, size, 0, &io); + if (!va) + goto err1; + ret = rproc_virtio_init_vring(vdev, i, notifyid, + va, io, num_descs, align); + if (ret) + goto err1; + } + metal_mutex_release(&rproc->lock); + return vdev; + +err1: + remoteproc_remove_virtio(rproc, vdev); + metal_mutex_release(&rproc->lock); + return NULL; +} + +void remoteproc_remove_virtio(struct remoteproc *rproc, + struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + + (void)rproc; + metal_assert(vdev); + + if (vdev) { + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + metal_list_del(&rpvdev->node); + rproc_virtio_remove_vdev(&rpvdev->vdev); + } +} + +int remoteproc_get_notification(struct remoteproc *rproc, uint32_t notifyid) +{ + struct remoteproc_virtio *rpvdev; + struct metal_list *node; + int ret; + + if (!rproc) + return 0; + + metal_list_for_each(&rproc->vdevs, node) { + rpvdev = metal_container_of(node, struct remoteproc_virtio, + node); + ret = rproc_virtio_notified(&rpvdev->vdev, notifyid); + if (ret) + return ret; + } + + return 0; +} diff --git a/libraries/openamp_arduino/src/remoteproc_virtio.c b/libraries/openamp_arduino/src/remoteproc_virtio.c index 82b99c4..7ef1064 100644 --- a/libraries/openamp_arduino/src/remoteproc_virtio.c +++ b/libraries/openamp_arduino/src/remoteproc_virtio.c @@ -6,54 +6,16 @@ * 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. + * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include +#include #include #include -static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra) -{ - struct virtqueue *vqs; - uint32_t vq_size = sizeof(struct virtqueue) + - num_desc_extra * sizeof(struct vq_desc_extra); - - vqs = (struct virtqueue *)metal_allocate_memory(vq_size); - - if (vqs) { - memset(vqs, 0x00, vq_size); - } - - return vqs; -} - static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) { struct remoteproc_virtio *rpvdev; @@ -63,7 +25,7 @@ static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) vdev = vq->vq_dev; rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); - metal_assert(vq_id <= vdev->vrings_num); + metal_assert(vq_id < vdev->vrings_num); vring_info = &vdev->vrings_info[vq_id]; rpvdev->notify(rpvdev->priv, vring_info->notifyid); } @@ -78,12 +40,13 @@ static unsigned char rproc_virtio_get_status(struct virtio_device *vdev) rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); vdev_rsc = rpvdev->vdev_rsc; io = rpvdev->vdev_rsc_io; + RSC_TABLE_INVALIDATE(vdev_rsc, sizeof(struct fw_rsc_vdev)); status = metal_io_read8(io, metal_io_virt_to_offset(io, &vdev_rsc->status)); return status; } -#ifndef VIRTIO_SLAVE_ONLY +#ifndef VIRTIO_DEVICE_ONLY static void rproc_virtio_set_status(struct virtio_device *vdev, unsigned char status) { @@ -97,11 +60,12 @@ static void rproc_virtio_set_status(struct virtio_device *vdev, metal_io_write8(io, metal_io_virt_to_offset(io, &vdev_rsc->status), status); - rpvdev->notify(rpvdev->priv, vdev->index); + RSC_TABLE_FLUSH(vdev_rsc, sizeof(struct fw_rsc_vdev)); + rpvdev->notify(rpvdev->priv, vdev->notifyid); } #endif -static uint32_t rproc_virtio_get_features(struct virtio_device *vdev) +static uint32_t rproc_virtio_get_dfeatures(struct virtio_device *vdev) { struct remoteproc_virtio *rpvdev; struct fw_rsc_vdev *vdev_rsc; @@ -111,14 +75,33 @@ static uint32_t rproc_virtio_get_features(struct virtio_device *vdev) rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); vdev_rsc = rpvdev->vdev_rsc; io = rpvdev->vdev_rsc_io; - /* TODO: shall we get features based on the role ? */ + RSC_TABLE_INVALIDATE(vdev_rsc, sizeof(struct fw_rsc_vdev)); features = metal_io_read32(io, metal_io_virt_to_offset(io, &vdev_rsc->dfeatures)); return features; } -#ifndef VIRTIO_SLAVE_ONLY +static uint32_t rproc_virtio_get_features(struct virtio_device *vdev) +{ + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + uint32_t gfeatures; + uint32_t dfeatures; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + io = rpvdev->vdev_rsc_io; + RSC_TABLE_INVALIDATE(vdev_rsc, sizeof(struct fw_rsc_vdev)); + gfeatures = metal_io_read32(io, + metal_io_virt_to_offset(io, &vdev_rsc->gfeatures)); + dfeatures = rproc_virtio_get_dfeatures(vdev); + + return dfeatures & gfeatures; +} + +#ifndef VIRTIO_DEVICE_ONLY static void rproc_virtio_set_features(struct virtio_device *vdev, uint32_t features) { @@ -129,64 +112,90 @@ static void rproc_virtio_set_features(struct virtio_device *vdev, rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); vdev_rsc = rpvdev->vdev_rsc; io = rpvdev->vdev_rsc_io; - /* TODO: shall we set features based on the role ? */ metal_io_write32(io, - metal_io_virt_to_offset(io, &vdev_rsc->dfeatures), + metal_io_virt_to_offset(io, &vdev_rsc->gfeatures), features); - rpvdev->notify(rpvdev->priv, vdev->index); + RSC_TABLE_FLUSH(vdev_rsc, sizeof(struct fw_rsc_vdev)); + rpvdev->notify(rpvdev->priv, vdev->notifyid); } -#endif static uint32_t rproc_virtio_negotiate_features(struct virtio_device *vdev, uint32_t features) { - (void)vdev; - (void)features; + uint32_t dfeatures = rproc_virtio_get_dfeatures(vdev); + + rproc_virtio_set_features(vdev, dfeatures & features); return 0; } +#endif static void rproc_virtio_read_config(struct virtio_device *vdev, uint32_t offset, void *dst, int length) { - (void)vdev; - (void)offset; - (void)dst; - (void)length; + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + char *config; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + config = (char *)(&vdev_rsc->vring[vdev->vrings_num]); + io = rpvdev->vdev_rsc_io; + + if (offset + length <= vdev_rsc->config_len) { + RSC_TABLE_INVALIDATE(config + offset, length); + metal_io_block_read(io, + metal_io_virt_to_offset(io, config + offset), + dst, length); + } } -#ifndef VIRTIO_SLAVE_ONLY +#ifndef VIRTIO_DEVICE_ONLY static void rproc_virtio_write_config(struct virtio_device *vdev, uint32_t offset, void *src, int length) { - (void)vdev; - (void)offset; - (void)src; - (void)length; + struct remoteproc_virtio *rpvdev; + struct fw_rsc_vdev *vdev_rsc; + struct metal_io_region *io; + char *config; + + rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev); + vdev_rsc = rpvdev->vdev_rsc; + config = (char *)(&vdev_rsc->vring[vdev->vrings_num]); + io = rpvdev->vdev_rsc_io; + + if (offset + length <= vdev_rsc->config_len) { + metal_io_block_write(io, + metal_io_virt_to_offset(io, config + offset), + src, length); + RSC_TABLE_FLUSH(config + offset, length); + rpvdev->notify(rpvdev->priv, vdev->notifyid); + } } static void rproc_virtio_reset_device(struct virtio_device *vdev) { - if (vdev->role == VIRTIO_DEV_MASTER) + if (vdev->role == VIRTIO_DEV_DRIVER) rproc_virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_NEEDS_RESET); } #endif -const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { - .get_status = rproc_virtio_get_status, +static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { + .get_status = rproc_virtio_get_status, .get_features = rproc_virtio_get_features, .read_config = rproc_virtio_read_config, .notify = rproc_virtio_virtqueue_notify, - .negotiate_features = rproc_virtio_negotiate_features, -#ifndef VIRTIO_SLAVE_ONLY +#ifndef VIRTIO_DEVICE_ONLY /* * We suppose here that the vdev is in a shared memory so that can - * be access only by one core: the master. In this case salve core has + * be access only by one core: the host. In this case salve core has * only read access right. */ .set_status = rproc_virtio_set_status, .set_features = rproc_virtio_set_features, + .negotiate_features = rproc_virtio_negotiate_features, .write_config = rproc_virtio_write_config, .reset_device = rproc_virtio_reset_device, #endif @@ -207,9 +216,8 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, unsigned int i; rpvdev = metal_allocate_memory(sizeof(*rpvdev)); - if (!rpvdev) { + if (!rpvdev) return NULL; - } vrings_info = metal_allocate_memory(sizeof(*vrings_info) * num_vrings); if (!vrings_info) goto err0; @@ -219,21 +227,23 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, for (i = 0; i < num_vrings; i++) { struct virtqueue *vq; +#ifndef VIRTIO_DEVICE_ONLY struct fw_rsc_vdev_vring *vring_rsc; +#endif unsigned int num_extra_desc = 0; +#ifndef VIRTIO_DEVICE_ONLY vring_rsc = &vdev_rsc->vring[i]; - if (role == VIRTIO_DEV_MASTER) { + if (role == VIRTIO_DEV_DRIVER) { num_extra_desc = vring_rsc->num; } +#endif vq = virtqueue_allocate(num_extra_desc); if (!vq) goto err1; vrings_info[i].vq = vq; } - /* FIXME commended as seems not nedded, already stored in vdev */ - //rpvdev->notifyid = notifyid; rpvdev->notify = notify; rpvdev->priv = priv; vdev->vrings_info = vrings_info; @@ -243,12 +253,19 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, rpvdev->vdev_rsc = vdev_rsc; rpvdev->vdev_rsc_io = rsc_io; - vdev->index = notifyid; + vdev->notifyid = notifyid; vdev->role = role; vdev->reset_cb = rst_cb; vdev->vrings_num = num_vrings; vdev->func = &remoteproc_virtio_dispatch_funcs; - /* TODO: Shall we set features here ? */ + +#ifndef VIRTIO_DEVICE_ONLY + if (role == VIRTIO_DEV_DRIVER) { + uint32_t dfeatures = rproc_virtio_get_dfeatures(vdev); + /* Assume the virtio driver support all remote features */ + rproc_virtio_negotiate_features(vdev, dfeatures); + } +#endif return &rpvdev->vdev; @@ -278,7 +295,8 @@ void rproc_virtio_remove_vdev(struct virtio_device *vdev) if (vq) metal_free_memory(vq); } - metal_free_memory(vdev->vrings_info); + if (vdev->vrings_info) + metal_free_memory(vdev->vrings_info); metal_free_memory(rpvdev); } @@ -291,7 +309,7 @@ int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index, unsigned int num_vrings; num_vrings = vdev->vrings_num; - if (index >= num_vrings) + if ((index >= num_vrings) || (num_descs > RPROC_MAX_VRING_DESC)) return -RPROC_EINVAL; vring_info = &vdev->vrings_info[index]; vring_info->io = io; @@ -310,9 +328,9 @@ int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid) struct virtqueue *vq; if (!vdev) - return -EINVAL; + return -RPROC_EINVAL; /* We do nothing for vdev notification in this implementation */ - if (vdev->index == notifyid) + if (vdev->notifyid == notifyid) return 0; num_vrings = vdev->vrings_num; for (i = 0; i < num_vrings; i++) { @@ -330,17 +348,19 @@ void rproc_virtio_wait_remote_ready(struct virtio_device *vdev) { uint8_t status; +#ifndef VIRTIO_DEVICE_ONLY /* - * No status available for slave. As Master has not to wait - * slave action, we can return. Behavior should be updated - * in future if a slave status is added. + * No status available for remote. As virtio driver has not to wait + * remote action, we can return. Behavior should be updated + * in future if a remote status is added. */ - if (vdev->role == VIRTIO_DEV_MASTER) + if (vdev->role == VIRTIO_DEV_DRIVER) return; - +#endif while (1) { status = rproc_virtio_get_status(vdev); if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) return; + metal_cpu_yield(); } } diff --git a/libraries/openamp_arduino/src/rpmsg.c b/libraries/openamp_arduino/src/rpmsg.c index 9268889..5a9237f 100644 --- a/libraries/openamp_arduino/src/rpmsg.c +++ b/libraries/openamp_arduino/src/rpmsg.c @@ -9,19 +9,20 @@ #include #include -#include #include "rpmsg_internal.h" /** - * rpmsg_get_address + * @internal + * + * @brief rpmsg_get_address * * This function provides unique 32 bit address. * - * @param bitmap - bit map for addresses - * @param size - size of bitmap + * @param bitmap Bit map for addresses + * @param size Size of bitmap * - * return - a unique address + * @return A unique address */ static uint32_t rpmsg_get_address(unsigned long *bitmap, int size) { @@ -30,7 +31,7 @@ static uint32_t rpmsg_get_address(unsigned long *bitmap, int size) nextbit = metal_bitmap_next_clear_bit(bitmap, 0, size); if (nextbit < (uint32_t)size) { - addr = nextbit; + addr = RPMSG_RESERVED_ADDRESSES + nextbit; metal_bitmap_set_bit(bitmap, nextbit); } @@ -38,54 +39,57 @@ static uint32_t rpmsg_get_address(unsigned long *bitmap, int size) } /** - * rpmsg_release_address + * @internal * - * Frees the given address. + * @brief Frees the given address. * - * @param bitmap - bit map for addresses - * @param size - size of bitmap - * @param addr - address to free + * @param bitmap Bit map for addresses + * @param size Size of bitmap + * @param addr Address to free */ static void rpmsg_release_address(unsigned long *bitmap, int size, int addr) { - if (addr < size) + addr -= RPMSG_RESERVED_ADDRESSES; + if (addr >= 0 && addr < size) metal_bitmap_clear_bit(bitmap, addr); } /** - * rpmsg_is_address_set + * @internal * - * Checks whether address is used or free. + * @brief Checks whether address is used or free. * - * @param bitmap - bit map for addresses - * @param size - size of bitmap - * @param addr - address to free + * @param bitmap Bit map for addresses + * @param size Size of bitmap + * @param addr Address to free * - * return - TRUE/FALSE + * @return TRUE/FALSE */ static int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr) { - if (addr < size) + addr -= RPMSG_RESERVED_ADDRESSES; + if (addr >= 0 && addr < size) return metal_bitmap_is_bit_set(bitmap, addr); else return RPMSG_ERR_PARAM; } /** - * rpmsg_set_address + * @internal * - * Marks the address as consumed. + * @brief Marks the address as consumed. * - * @param bitmap - bit map for addresses - * @param size - size of bitmap - * @param addr - address to free + * @param bitmap Bit map for addresses + * @param size Size of bitmap + * @param addr Address to free * - * return - none + * @return 0 on success, otherwise error code */ static int rpmsg_set_address(unsigned long *bitmap, int size, int addr) { - if (addr < size) { + addr -= RPMSG_RESERVED_ADDRESSES; + if (addr >= 0 && addr < size) { metal_bitmap_set_bit(bitmap, addr); return RPMSG_SUCCESS; } else { @@ -93,34 +97,20 @@ static int rpmsg_set_address(unsigned long *bitmap, int size, int addr) } } -/** - * This function sends rpmsg "message" to remote device. - * - * @param ept - pointer to end point - * @param src - source address of channel - * @param dst - destination address of channel - * @param data - data to transmit - * @param size - size of data - * @param wait - boolean, wait or not for buffer to become - * available - * - * @return - size of data sent or negative value for failure. - * - */ int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, - uint32_t dst, const void *data, int size, + uint32_t dst, const void *data, int len, int wait) { struct rpmsg_device *rdev; - if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY) + if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY || len < 0) return RPMSG_ERR_PARAM; rdev = ept->rdev; if (rdev->ops.send_offchannel_raw) return rdev->ops.send_offchannel_raw(rdev, src, dst, data, - size, wait); + len, wait); return RPMSG_ERR_PARAM; } @@ -142,6 +132,80 @@ int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags) return RPMSG_SUCCESS; } +void rpmsg_hold_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev || !rxbuf) + return; + + rdev = ept->rdev; + + if (rdev->ops.hold_rx_buffer) + rdev->ops.hold_rx_buffer(rdev, rxbuf); +} + +void rpmsg_release_rx_buffer(struct rpmsg_endpoint *ept, void *rxbuf) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev || !rxbuf) + return; + + rdev = ept->rdev; + + if (rdev->ops.release_rx_buffer) + rdev->ops.release_rx_buffer(rdev, rxbuf); +} + +int rpmsg_release_tx_buffer(struct rpmsg_endpoint *ept, void *buf) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev || !buf) + return RPMSG_ERR_PARAM; + + rdev = ept->rdev; + + if (rdev->ops.release_tx_buffer) + return rdev->ops.release_tx_buffer(rdev, buf); + + return RPMSG_ERR_PERM; +} + +void *rpmsg_get_tx_payload_buffer(struct rpmsg_endpoint *ept, + uint32_t *len, int wait) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev || !len) + return NULL; + + rdev = ept->rdev; + + if (rdev->ops.get_tx_payload_buffer) + return rdev->ops.get_tx_payload_buffer(rdev, len, wait); + + return NULL; +} + +int rpmsg_send_offchannel_nocopy(struct rpmsg_endpoint *ept, uint32_t src, + uint32_t dst, const void *data, int len) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY || len < 0) + return RPMSG_ERR_PARAM; + + rdev = ept->rdev; + + if (rdev->ops.send_offchannel_nocopy) + return rdev->ops.send_offchannel_nocopy(rdev, src, dst, + data, len); + + return RPMSG_ERR_PARAM; +} + struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev, const char *name, uint32_t addr, uint32_t dest_addr) @@ -156,19 +220,16 @@ struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev, /* try to get by local address only */ if (addr != RPMSG_ADDR_ANY && ept->addr == addr) return ept; - /* try to find match on local end remote address */ - if (addr == ept->addr && dest_addr == ept->dest_addr) - return ept; /* else use name service and destination address */ if (name) name_match = !strncmp(ept->name, name, sizeof(ept->name)); if (!name || !name_match) continue; - /* destination address is known, equal to ept remote address*/ + /* destination address is known, equal to ept remote address */ if (dest_addr != RPMSG_ADDR_ANY && ept->dest_addr == dest_addr) return ept; - /* ept is registered but not associated to remote ept*/ + /* ept is registered but not associated to remote ept */ if (addr == RPMSG_ADDR_ANY && ept->dest_addr == RPMSG_ADDR_ANY) return ept; } @@ -177,40 +238,51 @@ struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev, static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept) { - struct rpmsg_device *rdev; - - if (!ept) - return; - - rdev = ept->rdev; + struct rpmsg_device *rdev = ept->rdev; + metal_mutex_acquire(&rdev->lock); if (ept->addr != RPMSG_ADDR_ANY) rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, ept->addr); metal_list_del(&ept->node); + ept->rdev = NULL; + metal_mutex_release(&rdev->lock); } -int rpmsg_register_endpoint(struct rpmsg_device *rdev, - struct rpmsg_endpoint *ept) +void rpmsg_register_endpoint(struct rpmsg_device *rdev, + struct rpmsg_endpoint *ept, + const char *name, + uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, + rpmsg_ns_unbind_cb ns_unbind_cb) { + strncpy(ept->name, name ? name : "", sizeof(ept->name)); + ept->addr = src; + ept->dest_addr = dest; + ept->cb = cb; + ept->ns_unbind_cb = ns_unbind_cb; ept->rdev = rdev; - metal_list_add_tail(&rdev->endpoints, &ept->node); - return RPMSG_SUCCESS; } int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, const char *name, uint32_t src, uint32_t dest, rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb) { - int status; + int status = RPMSG_SUCCESS; uint32_t addr = src; - if (!ept) + if (!ept || !rdev || !cb) return RPMSG_ERR_PARAM; metal_mutex_acquire(&rdev->lock); - if (src != RPMSG_ADDR_ANY) { + if (src == RPMSG_ADDR_ANY) { + addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE); + if (addr == RPMSG_ADDR_ANY) { + status = RPMSG_ERR_ADDR; + goto ret_status; + } + } else if (src >= RPMSG_RESERVED_ADDRESSES) { status = rpmsg_is_address_set(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, src); if (!status) { @@ -218,54 +290,46 @@ int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, src); } else if (status > 0) { - status = RPMSG_SUCCESS; + status = RPMSG_ERR_ADDR; goto ret_status; } else { goto ret_status; } } else { - addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE); + /* Skip check the address duplication in 0-1023: + * 1.Trust the author of predefined service + * 2.Simplify the tracking implementation + */ } - rpmsg_init_ept(ept, name, addr, dest, cb, unbind_cb); - - status = rpmsg_register_endpoint(rdev, ept); - if (status < 0) - rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr); + rpmsg_register_endpoint(rdev, ept, name, addr, dest, cb, unbind_cb); + metal_mutex_release(&rdev->lock); - if (!status && ept->dest_addr == RPMSG_ADDR_ANY) { - /* Send NS announcement to remote processor */ - metal_mutex_release(&rdev->lock); + /* Send NS announcement to remote processor */ + if (ept->name[0] && rdev->support_ns && + ept->dest_addr == RPMSG_ADDR_ANY) status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE); - metal_mutex_acquire(&rdev->lock); - if (status) - rpmsg_unregister_endpoint(ept); - } + + if (status) + rpmsg_unregister_endpoint(ept); + return status; ret_status: metal_mutex_release(&rdev->lock); return status; } -/** - * rpmsg_destroy_ept - * - * This function deletes rpmsg endpoint and performs cleanup. - * - * @param ept - pointer to endpoint to destroy - * - */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { struct rpmsg_device *rdev; - if (!ept) + if (!ept || !ept->rdev) return; rdev = ept->rdev; - if (ept->addr != RPMSG_NS_EPT_ADDR) + + if (ept->name[0] && rdev->support_ns && + ept->addr >= RPMSG_RESERVED_ADDRESSES) (void)rpmsg_send_ns_message(ept, RPMSG_NS_DESTROY); - metal_mutex_acquire(&rdev->lock); rpmsg_unregister_endpoint(ept); - metal_mutex_release(&rdev->lock); } diff --git a/libraries/openamp_arduino/src/rpmsg_internal.h b/libraries/openamp_arduino/src/rpmsg_internal.h index e1b8208..6721ecf 100644 --- a/libraries/openamp_arduino/src/rpmsg_internal.h +++ b/libraries/openamp_arduino/src/rpmsg_internal.h @@ -15,24 +15,25 @@ extern "C" { #endif #ifdef RPMSG_DEBUG +#include + #define RPMSG_ASSERT(_exp, _msg) do { \ if (!(_exp)) { \ - openamp_print("FATAL: %s - _msg", __func__); \ - while (1) { \ - ; \ - } \ + metal_log(METAL_LOG_EMERGENCY, \ + "FATAL: %s - "_msg, __func__); \ + metal_assert(_exp); \ } \ } while (0) #else -#define RPMSG_ASSERT(_exp, _msg) do { \ - if (!(_exp)) \ - while (1) { \ - ; \ - } \ - } while (0) +#define RPMSG_ASSERT(_exp, _msg) metal_assert(_exp) #endif +#define RPMSG_BUF_HELD (1U << 31) /* Flag to suggest to hold the buffer */ + +#define RPMSG_LOCATE_HDR(p) \ + ((struct rpmsg_hdr *)((unsigned char *)(p) - sizeof(struct rpmsg_hdr))) #define RPMSG_LOCATE_DATA(p) ((unsigned char *)(p) + sizeof(struct rpmsg_hdr)) + /** * enum rpmsg_ns_flags - dynamic name service announcement flags * @@ -47,50 +48,60 @@ enum rpmsg_ns_flags { }; /** - * 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 + * @brief Common header for all RPMsg messages * - * Every message sent(/received) on the rpmsg bus begins with this header. + * Every message sent(/received) on the RPMsg bus begins with this header. */ -OPENAMP_PACKED_BEGIN +METAL_PACKED_BEGIN struct rpmsg_hdr { + /** Source address */ uint32_t src; + + /** Destination address */ uint32_t dst; + + /** Reserved for future use */ uint32_t reserved; + + /** Length of payload (in bytes) */ uint16_t len; + + /** Message flags */ uint16_t flags; -} OPENAMP_PACKED_END; +} METAL_PACKED_END; /** - * struct rpmsg_ns_msg - dynamic name service announcement message - * @name: name of remote service that is published - * @addr: address of remote service that is published - * @flags: indicates whether service is created or destroyed + * @brief Dynamic name service announcement message * * 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 + * RPMsg channel (i.e device) is created/destroyed. In turn, the ->probe() + * or ->remove() handler of the appropriate RPMsg driver will be invoked * (if/as-soon-as one is registered). */ -OPENAMP_PACKED_BEGIN +METAL_PACKED_BEGIN struct rpmsg_ns_msg { + /** Name of the remote service that is being published */ char name[RPMSG_NAME_SIZE]; + + /** Endpoint address of the remote service that is being published */ uint32_t addr; + + /** Indicates whether service is created or destroyed */ uint32_t flags; -} OPENAMP_PACKED_END; +} METAL_PACKED_END; int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags); struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rvdev, const char *name, uint32_t addr, uint32_t dest_addr); -int rpmsg_register_endpoint(struct rpmsg_device *rdev, - struct rpmsg_endpoint *ept); +void rpmsg_register_endpoint(struct rpmsg_device *rdev, + struct rpmsg_endpoint *ept, + const char *name, + uint32_t src, uint32_t dest, + rpmsg_ept_cb cb, + rpmsg_ns_unbind_cb ns_unbind_cb); static inline struct rpmsg_endpoint * rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr) diff --git a/libraries/openamp_arduino/src/rpmsg_virtio.c b/libraries/openamp_arduino/src/rpmsg_virtio.c index 207edc3..ea4cc0d 100644 --- a/libraries/openamp_arduino/src/rpmsg_virtio.c +++ b/libraries/openamp_arduino/src/rpmsg_virtio.c @@ -3,12 +3,12 @@ * All rights reserved. * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. * Copyright (c) 2018 Linaro, Inc. All rights reserved. + * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: BSD-3-Clause */ #include -#include #include #include #include @@ -16,62 +16,86 @@ #include "rpmsg_internal.h" -#define RPMSG_NUM_VRINGS (2) +#define RPMSG_NUM_VRINGS 2 -/* Total tick count for 15secs - 1msec tick. */ -#define RPMSG_TICK_COUNT 15000 +/* Total tick count for 15secs - 1usec tick. */ +#define RPMSG_TICK_COUNT 15000000 -/* Time to wait - In multiple of 10 msecs. */ -#define RPMSG_TICKS_PER_INTERVAL 10 +/* Time to wait - In multiple of 1 msecs. */ +#define RPMSG_TICKS_PER_INTERVAL 1000 -#define WORD_SIZE sizeof(unsigned long) -#define WORD_ALIGN(a) ((((a) & (WORD_SIZE - 1)) != 0) ? \ - (((a) & (~(WORD_SIZE - 1))) + WORD_SIZE) : (a)) +/** + * struct vbuff_reclaimer_t - vring buffer recycler + * + * This structure is used by the rpmsg virtio to store unused virtio buffer, as the + * virtqueue structure has been already updated and memory allocated. + * + * @node: node in reclaimer list. + * @idx: virtio descriptor index containing the buffer information. + */ +struct vbuff_reclaimer_t { + struct metal_list node; + uint16_t idx; +}; + +/* Default configuration */ +#ifndef VIRTIO_DEVICE_ONLY +#define RPMSG_VIRTIO_DEFAULT_CONFIG \ + (&(const struct rpmsg_virtio_config) { \ + .h2r_buf_size = RPMSG_BUFFER_SIZE, \ + .r2h_buf_size = RPMSG_BUFFER_SIZE, \ + .split_shpool = false, \ + }) +#else +#define RPMSG_VIRTIO_DEFAULT_CONFIG NULL +#endif -#ifndef VIRTIO_SLAVE_ONLY +#ifndef VIRTIO_DEVICE_ONLY metal_weak void * rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, size_t size) { void *buffer; - if (shpool->avail < size) + if (!shpool || size == 0 || shpool->avail < size) return NULL; - buffer = (void *)((char *)shpool->base + shpool->size - shpool->avail); + buffer = (char *)shpool->base + shpool->size - shpool->avail; shpool->avail -= size; return buffer; } -#endif /*!VIRTIO_SLAVE_ONLY*/ +#endif /*!VIRTIO_DEVICE_ONLY*/ void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, void *shb, size_t size) { - if (!shpool) + if (!shpool || !shb || size == 0) return; shpool->base = shb; - shpool->size = WORD_ALIGN(size); - shpool->avail = WORD_ALIGN(size); + shpool->size = size; + shpool->avail = size; } /** - * rpmsg_virtio_return_buffer + * @internal * - * Places the used buffer back on the virtqueue. - * - * @param rvdev - pointer to remote core - * @param buffer - buffer pointer - * @param len - buffer length - * @param idx - buffer index + * @brief Places the used buffer back on the virtqueue. * + * @param rvdev Pointer to remote core + * @param buffer Buffer pointer + * @param len Buffer length + * @param idx Buffer index */ static void rpmsg_virtio_return_buffer(struct rpmsg_virtio_device *rvdev, - void *buffer, unsigned long len, - unsigned short idx) + void *buffer, uint32_t len, + uint16_t idx) { unsigned int role = rpmsg_virtio_get_role(rvdev); -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) { + + BUFFER_INVALIDATE(buffer, len); + +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) { struct virtqueue_buf vqbuf; (void)idx; @@ -80,140 +104,151 @@ static void rpmsg_virtio_return_buffer(struct rpmsg_virtio_device *rvdev, vqbuf.len = len; virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, buffer); } -#endif /*VIRTIO_SLAVE_ONLY*/ +#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_MASTER_ONLY +#ifndef VIRTIO_DRIVER_ONLY if (role == RPMSG_REMOTE) { (void)buffer; virtqueue_add_consumed_buffer(rvdev->rvq, idx, len); } -#endif /*VIRTIO_MASTER_ONLY*/ +#endif /*VIRTIO_DRIVER_ONLY*/ } /** - * rpmsg_virtio_enqueue_buffer + * @internal * - * Places buffer on the virtqueue for consumption by the other side. + * @brief Places buffer on the virtqueue for consumption by the other side. * - * @param rvdev - pointer to rpmsg virtio - * @param buffer - buffer pointer - * @param len - buffer length - * @param idx - buffer index + * @param rvdev Pointer to rpmsg virtio + * @param buffer Buffer pointer + * @param len Buffer length + * @param idx Buffer index * - * @return - status of function execution + * @return Status of function execution */ static int rpmsg_virtio_enqueue_buffer(struct rpmsg_virtio_device *rvdev, - void *buffer, unsigned long len, - unsigned short idx) + void *buffer, uint32_t len, + uint16_t idx) { unsigned int role = rpmsg_virtio_get_role(rvdev); -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) { + + BUFFER_FLUSH(buffer, len); + +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) { struct virtqueue_buf vqbuf; (void)idx; /* Initialize buffer node */ vqbuf.buf = buffer; vqbuf.len = len; - return virtqueue_add_buffer(rvdev->svq, &vqbuf, 0, 1, buffer); + return virtqueue_add_buffer(rvdev->svq, &vqbuf, 1, 0, buffer); } -#endif /*!VIRTIO_SLAVE_ONLY*/ +#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_MASTER_ONLY +#ifndef VIRTIO_DRIVER_ONLY if (role == RPMSG_REMOTE) { (void)buffer; return virtqueue_add_consumed_buffer(rvdev->svq, idx, len); } -#endif /*!VIRTIO_MASTER_ONLY*/ +#endif /*!VIRTIO_DRIVER_ONLY*/ return 0; } /** - * rpmsg_virtio_get_tx_buffer + * @internal * - * Provides buffer to transmit messages. + * @brief Provides buffer to transmit messages. * - * @param rvdev - pointer to rpmsg device - * @param len - length of returned buffer - * @param idx - buffer index + * @param rvdev Pointer to rpmsg device + * @param len Length of returned buffer + * @param idx Buffer index * - * return - pointer to buffer. + * @return Pointer to buffer. */ static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev, - unsigned long *len, - unsigned short *idx) + uint32_t *len, uint16_t *idx) { unsigned int role = rpmsg_virtio_get_role(rvdev); + struct metal_list *node; + struct vbuff_reclaimer_t *r_desc; void *data = NULL; -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) { - data = virtqueue_get_buffer(rvdev->svq, (uint32_t *)len, idx); - if (data == NULL) { + /* Try first to recycle a buffer that has been freed without been used */ + node = metal_list_first(&rvdev->reclaimer); + if (node) { + r_desc = metal_container_of(node, struct vbuff_reclaimer_t, node); + metal_list_del(node); + data = r_desc; + +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) + *len = rvdev->config.h2r_buf_size; +#endif /*!VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (role == RPMSG_REMOTE) { + *idx = r_desc->idx; + *len = virtqueue_get_buffer_length(rvdev->svq, *idx); + } +#endif /*!VIRTIO_DRIVER_ONLY*/ +#ifndef VIRTIO_DEVICE_ONLY + } else if (role == RPMSG_HOST) { + data = virtqueue_get_buffer(rvdev->svq, len, idx); + if (!data && rvdev->svq->vq_free_cnt) { data = rpmsg_virtio_shm_pool_get_buffer(rvdev->shpool, - RPMSG_BUFFER_SIZE); - *len = RPMSG_BUFFER_SIZE; + rvdev->config.h2r_buf_size); + *len = rvdev->config.h2r_buf_size; + *idx = 0; } +#endif /*!VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + } else if (role == RPMSG_REMOTE) { + data = virtqueue_get_available_buffer(rvdev->svq, idx, len); +#endif /*!VIRTIO_DRIVER_ONLY*/ } -#endif /*!VIRTIO_SLAVE_ONLY*/ - -#ifndef VIRTIO_MASTER_ONLY - if (role == RPMSG_REMOTE) { - data = virtqueue_get_available_buffer(rvdev->svq, idx, - (uint32_t *)len); - } -#endif /*!VIRTIO_MASTER_ONLY*/ return data; } /** - * rpmsg_virtio_get_rx_buffer + * @internal * - * Retrieves the received buffer from the virtqueue. + * @brief Retrieves the received buffer from the virtqueue. * - * @param rvdev - pointer to rpmsg device - * @param len - size of received buffer - * @param idx - index of buffer - * - * @return - pointer to received buffer + * @param rvdev Pointer to rpmsg device + * @param len Size of received buffer + * @param idx Index of buffer * + * @return Pointer to received buffer */ static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev, - unsigned long *len, - unsigned short *idx) + uint32_t *len, uint16_t *idx) { unsigned int role = rpmsg_virtio_get_role(rvdev); void *data = NULL; -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) { - data = virtqueue_get_buffer(rvdev->rvq, (uint32_t *)len, idx); +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) { + data = virtqueue_get_buffer(rvdev->rvq, len, idx); } -#endif /*!VIRTIO_SLAVE_ONLY*/ +#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_MASTER_ONLY +#ifndef VIRTIO_DRIVER_ONLY if (role == RPMSG_REMOTE) { data = - virtqueue_get_available_buffer(rvdev->rvq, idx, - (uint32_t *)len); + virtqueue_get_available_buffer(rvdev->rvq, idx, len); } -#endif /*!VIRTIO_MASTER_ONLY*/ +#endif /*!VIRTIO_DRIVER_ONLY*/ - if (data) { - /* FIX ME: library should not worry about if it needs - * to flush/invalidate cache, it is shared memory. - * The shared memory should be mapped properly before - * using it. - */ - metal_cache_invalidate(data, (unsigned int)(*len)); - } + /* Invalidate the buffer before returning it */ + if (data) + BUFFER_INVALIDATE(data, *len); return data; } -#ifndef VIRTIO_MASTER_ONLY -/** +#ifndef VIRTIO_DRIVER_ONLY +/* * check if the remote is ready to start RPMsg communication */ static int rpmsg_virtio_wait_remote_ready(struct rpmsg_virtio_device *rvdev) @@ -232,87 +267,102 @@ static int rpmsg_virtio_wait_remote_ready(struct rpmsg_virtio_device *rvdev) /* TODO: clarify metal_cpu_yield usage*/ metal_cpu_yield(); } - - return false; } -#endif /*!VIRTIO_MASTER_ONLY*/ +#endif /*!VIRTIO_DRIVER_ONLY*/ /** - * _rpmsg_virtio_get_buffer_size - * - * Returns buffer size available for sending messages. + * @internal * - * @param channel - pointer to rpmsg channel + * @brief Returns buffer size available for sending messages. * - * @return - buffer size + * @param rvdev Pointer to rpmsg device * + * @return Buffer size */ static int _rpmsg_virtio_get_buffer_size(struct rpmsg_virtio_device *rvdev) { unsigned int role = rpmsg_virtio_get_role(rvdev); int length = 0; -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) { +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) { /* - * If device role is Remote then buffers are provided by us - * (RPMSG Master), so just provide the macro. + * If device role is host then buffers are provided by us, + * so just provide the macro. */ - length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr); + length = rvdev->config.h2r_buf_size - sizeof(struct rpmsg_hdr); } -#endif /*!VIRTIO_SLAVE_ONLY*/ +#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_MASTER_ONLY +#ifndef VIRTIO_DRIVER_ONLY if (role == RPMSG_REMOTE) { /* - * If other core is Master then buffers are provided by it, + * If other core is host then buffers are provided by it, * so get the buffer size from the virtqueue. */ length = (int)virtqueue_get_desc_size(rvdev->svq) - sizeof(struct rpmsg_hdr); } -#endif /*!VIRTIO_MASTER_ONLY*/ +#endif /*!VIRTIO_DRIVER_ONLY*/ + + if (length <= 0) { + length = RPMSG_ERR_NO_BUFF; + } return length; } -/** - * This function sends rpmsg "message" to remote device. - * - * @param rdev - pointer to rpmsg device - * @param src - source address of channel - * @param dst - destination address of channel - * @param data - data to transmit - * @param size - size of data - * @param wait - boolean, wait or not for buffer to become - * available - * - * @return - size of data sent or negative value for failure. - * - */ -static int rpmsg_virtio_send_offchannel_raw(struct rpmsg_device *rdev, - uint32_t src, uint32_t dst, - const void *data, - int size, int wait) +static void rpmsg_virtio_hold_rx_buffer(struct rpmsg_device *rdev, void *rxbuf) +{ + struct rpmsg_hdr *rp_hdr; + + (void)rdev; + + rp_hdr = RPMSG_LOCATE_HDR(rxbuf); + + /* Set held status to keep buffer */ + rp_hdr->reserved |= RPMSG_BUF_HELD; +} + +static void rpmsg_virtio_release_rx_buffer(struct rpmsg_device *rdev, + void *rxbuf) { struct rpmsg_virtio_device *rvdev; - struct rpmsg_hdr rp_hdr; - void *buffer = NULL; - unsigned short idx; - int tick_count = 0; - unsigned long buff_len; + struct rpmsg_hdr *rp_hdr; + uint16_t idx; + uint32_t len; + + rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); + rp_hdr = RPMSG_LOCATE_HDR(rxbuf); + /* The reserved field contains buffer index */ + idx = (uint16_t)(rp_hdr->reserved & ~RPMSG_BUF_HELD); + + metal_mutex_acquire(&rdev->lock); + /* Return buffer on virtqueue. */ + len = virtqueue_get_buffer_length(rvdev->rvq, idx); + rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); + /* Tell peer we return some rx buffers */ + virtqueue_kick(rvdev->rvq); + metal_mutex_release(&rdev->lock); +} + +static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, + uint32_t *len, int wait) +{ + struct rpmsg_virtio_device *rvdev; + struct rpmsg_hdr *rp_hdr; + uint16_t idx; + int tick_count; int status; - struct metal_io_region *io; /* Get the associated remote device for channel. */ rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); - status = rpmsg_virtio_get_status(rvdev); /* Validate device state */ - if (!(status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) { - return RPMSG_ERR_DEV_STATE; - } + status = rpmsg_virtio_get_status(rvdev); + if (!(status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) + return NULL; if (wait) tick_count = RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL; @@ -320,63 +370,157 @@ static int rpmsg_virtio_send_offchannel_raw(struct rpmsg_device *rdev, tick_count = 0; while (1) { - int avail_size; - /* Lock the device to enable exclusive access to virtqueues */ metal_mutex_acquire(&rdev->lock); - avail_size = _rpmsg_virtio_get_buffer_size(rvdev); - if (size <= avail_size) - buffer = rpmsg_virtio_get_tx_buffer(rvdev, &buff_len, - &idx); + rp_hdr = rpmsg_virtio_get_tx_buffer(rvdev, len, &idx); metal_mutex_release(&rdev->lock); - if (buffer || !tick_count) + if (rp_hdr || !tick_count) break; - if (avail_size != 0) - return RPMSG_ERR_BUFF_SIZE; metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); tick_count--; } - if (!buffer) - return RPMSG_ERR_NO_BUFF; + + if (!rp_hdr) + return NULL; + + /* Store the index into the reserved field to be used when sending */ + rp_hdr->reserved = idx; + + /* Actual data buffer size is vring buffer size minus header length */ + *len -= sizeof(struct rpmsg_hdr); + return RPMSG_LOCATE_DATA(rp_hdr); +} + +static int rpmsg_virtio_send_offchannel_nocopy(struct rpmsg_device *rdev, + uint32_t src, uint32_t dst, + const void *data, int len) +{ + struct rpmsg_virtio_device *rvdev; + struct metal_io_region *io; + struct rpmsg_hdr rp_hdr; + struct rpmsg_hdr *hdr; + uint32_t buff_len; + uint16_t idx; + int status; + + /* Get the associated remote device for channel. */ + rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); + + hdr = RPMSG_LOCATE_HDR(data); + /* The reserved field contains buffer index */ + idx = hdr->reserved; /* Initialize RPMSG header. */ rp_hdr.dst = dst; rp_hdr.src = src; - rp_hdr.len = size; + rp_hdr.len = len; rp_hdr.reserved = 0; + rp_hdr.flags = 0; /* Copy data to rpmsg buffer. */ io = rvdev->shbuf_io; - status = metal_io_block_write(io, metal_io_virt_to_offset(io, buffer), + status = metal_io_block_write(io, metal_io_virt_to_offset(io, hdr), &rp_hdr, sizeof(rp_hdr)); - RPMSG_ASSERT(status == sizeof(rp_hdr), "failed to write header\n"); + RPMSG_ASSERT(status == sizeof(rp_hdr), "failed to write header\r\n"); - status = metal_io_block_write(io, - metal_io_virt_to_offset(io, - RPMSG_LOCATE_DATA(buffer)), - data, size); - RPMSG_ASSERT(status == size, "failed to write buffer\n"); metal_mutex_acquire(&rdev->lock); +#ifndef VIRTIO_DEVICE_ONLY + if (rpmsg_virtio_get_role(rvdev) == RPMSG_HOST) + buff_len = rvdev->config.h2r_buf_size; + else +#endif /*!VIRTIO_DEVICE_ONLY*/ + buff_len = virtqueue_get_buffer_length(rvdev->svq, idx); + /* Enqueue buffer on virtqueue. */ - status = rpmsg_virtio_enqueue_buffer(rvdev, buffer, buff_len, idx); - RPMSG_ASSERT(status == VQUEUE_SUCCESS, "failed to enqueue buffer\n"); + status = rpmsg_virtio_enqueue_buffer(rvdev, hdr, buff_len, idx); + RPMSG_ASSERT(status == VQUEUE_SUCCESS, "failed to enqueue buffer\r\n"); /* Let the other side know that there is a job to process. */ virtqueue_kick(rvdev->svq); metal_mutex_release(&rdev->lock); - return size; + return len; +} + +static int rpmsg_virtio_release_tx_buffer(struct rpmsg_device *rdev, void *txbuf) +{ + struct rpmsg_virtio_device *rvdev; + struct rpmsg_hdr *rp_hdr = RPMSG_LOCATE_HDR(txbuf); + void *vbuff = rp_hdr; /* only used to avoid warning on the cast of a packed structure */ + struct vbuff_reclaimer_t *r_desc = (struct vbuff_reclaimer_t *)vbuff; + uint16_t idx; + + /* + * Reuse the RPMsg buffer to temporary store the vbuff_reclaimer_t structure. + * Stores the index locally before overwriting the RPMsg header. + */ + idx = rp_hdr->reserved; + + rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); + + metal_mutex_acquire(&rdev->lock); + + r_desc->idx = idx; + metal_list_add_tail(&rvdev->reclaimer, &r_desc->node); + + metal_mutex_release(&rdev->lock); + + return RPMSG_SUCCESS; } /** - * rpmsg_virtio_tx_callback + * @internal * - * Tx callback function. + * @brief This function sends rpmsg "message" to remote device. + * + * @param rdev Pointer to rpmsg device + * @param src Source address of channel + * @param dst Destination address of channel + * @param data Data to transmit + * @param len Size of data + * @param wait Boolean, wait or not for buffer to become + * available + * + * @return Size of data sent or negative value for failure. + */ +static int rpmsg_virtio_send_offchannel_raw(struct rpmsg_device *rdev, + uint32_t src, uint32_t dst, + const void *data, + int len, int wait) +{ + struct rpmsg_virtio_device *rvdev; + struct metal_io_region *io; + uint32_t buff_len; + void *buffer; + int status; + + /* Get the associated remote device for channel. */ + rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); + + /* Get the payload buffer. */ + buffer = rpmsg_virtio_get_tx_payload_buffer(rdev, &buff_len, wait); + if (!buffer) + return RPMSG_ERR_NO_BUFF; + + /* Copy data to rpmsg buffer. */ + if (len > (int)buff_len) + len = buff_len; + io = rvdev->shbuf_io; + status = metal_io_block_write(io, metal_io_virt_to_offset(io, buffer), + data, len); + RPMSG_ASSERT(status == len, "failed to write buffer\r\n"); + + return rpmsg_virtio_send_offchannel_nocopy(rdev, src, dst, buffer, len); +} + +/** + * @internal * - * @param vq - pointer to virtqueue on which Tx is has been - * completed. + * @brief Tx callback function. * + * @param vq Pointer to virtqueue on which Tx is has been + * completed. */ static void rpmsg_virtio_tx_callback(struct virtqueue *vq) { @@ -384,12 +528,11 @@ static void rpmsg_virtio_tx_callback(struct virtqueue *vq) } /** - * rpmsg_virtio_rx_callback - * - * Rx callback function. + * @internal * - * @param vq - pointer to virtqueue on which messages is received + * @brief Rx callback function. * + * @param vq Pointer to virtqueue on which messages is received */ static void rpmsg_virtio_rx_callback(struct virtqueue *vq) { @@ -398,73 +541,71 @@ static void rpmsg_virtio_rx_callback(struct virtqueue *vq) struct rpmsg_device *rdev = &rvdev->rdev; struct rpmsg_endpoint *ept; struct rpmsg_hdr *rp_hdr; - unsigned long len; - unsigned short idx; + uint32_t len; + uint16_t idx; int status; metal_mutex_acquire(&rdev->lock); /* Process the received data from remote node */ - rp_hdr = (struct rpmsg_hdr *)rpmsg_virtio_get_rx_buffer(rvdev, - &len, &idx); + rp_hdr = rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); metal_mutex_release(&rdev->lock); while (rp_hdr) { + rp_hdr->reserved = idx; + /* Get the channel node from the remote device channels list. */ metal_mutex_acquire(&rdev->lock); ept = rpmsg_get_ept_from_addr(rdev, rp_hdr->dst); metal_mutex_release(&rdev->lock); - if (!ept) - /* Fatal error no endpoint for the given dst addr. */ - return; + if (ept) { + if (ept->dest_addr == RPMSG_ADDR_ANY) { + /* + * First message received from the remote side, + * update channel destination address + */ + ept->dest_addr = rp_hdr->src; + } + status = ept->cb(ept, RPMSG_LOCATE_DATA(rp_hdr), + rp_hdr->len, rp_hdr->src, ept->priv); - if (ept->dest_addr == RPMSG_ADDR_ANY) { - /* - * First message received from the remote side, - * update channel destination address - */ - ept->dest_addr = rp_hdr->src; + RPMSG_ASSERT(status >= 0, + "unexpected callback status\r\n"); } - status = ept->cb(ept, (void *)RPMSG_LOCATE_DATA(rp_hdr), - rp_hdr->len, ept->addr, ept->priv); - RPMSG_ASSERT(status == RPMSG_SUCCESS, - "unexpected callback status\n"); metal_mutex_acquire(&rdev->lock); - /* Return used buffers. */ - rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); + /* Check whether callback wants to hold buffer */ + if (!(rp_hdr->reserved & RPMSG_BUF_HELD)) { + /* No, return used buffers. */ + rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); + } - rp_hdr = (struct rpmsg_hdr *) - rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); + rp_hdr = rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); + if (!rp_hdr) { + /* tell peer we return some rx buffer */ + virtqueue_kick(rvdev->rvq); + } metal_mutex_release(&rdev->lock); } } /** - * rpmsg_virtio_ns_callback + * @internal * - * This callback handles name service announcement from the remote device - * and creates/deletes rpmsg channels. + * @brief 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 + * @param ept Pointer to server channel control block. + * @param data Pointer to received messages + * @param len Length of received data + * @param priv Any private data + * @param src Source address * - * @return - rpmag endpoint callback handled + * @return Rpmsg endpoint callback handled */ - -#if defined (__GNUC__) && ! defined (__CC_ARM) -#pragma GCC push_options -#pragma GCC optimize ("O0") -#elif defined (__CC_ARM) -#pragma push -#pragma O0 -#endif static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) { @@ -479,7 +620,7 @@ static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, (void)priv; (void)src; - ns_msg = (struct rpmsg_ns_msg *)data; + ns_msg = data; if (len != sizeof(*ns_msg)) /* Returns as the message is corrupted */ return RPMSG_SUCCESS; @@ -497,7 +638,9 @@ static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, _ept->dest_addr = RPMSG_ADDR_ANY; metal_mutex_release(&rdev->lock); if (_ept && _ept->ns_unbind_cb) - _ept->ns_unbind_cb(ept); + _ept->ns_unbind_cb(_ept); + if (rdev->ns_unbind_cb) + rdev->ns_unbind_cb(rdev, name, dest); } else { if (!_ept) { /* @@ -517,11 +660,6 @@ static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, return RPMSG_SUCCESS; } -#if defined (__GNUC__) && ! defined (__CC_ARM) -#pragma GCC pop_options -#elif defined (__CC_ARM) -#pragma pop -#endif int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev) { @@ -542,15 +680,27 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, rpmsg_ns_bind_cb ns_bind_cb, struct metal_io_region *shm_io, struct rpmsg_virtio_shm_pool *shpool) +{ + return rpmsg_init_vdev_with_config(rvdev, vdev, ns_bind_cb, shm_io, + shpool, RPMSG_VIRTIO_DEFAULT_CONFIG); +} + +int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, + struct virtio_device *vdev, + rpmsg_ns_bind_cb ns_bind_cb, + struct metal_io_region *shm_io, + struct rpmsg_virtio_shm_pool *shpool, + const struct rpmsg_virtio_config *config) { struct rpmsg_device *rdev; const char *vq_names[RPMSG_NUM_VRINGS]; - typedef void (*vqcallback)(struct virtqueue *vq); - vqcallback callback[RPMSG_NUM_VRINGS]; - unsigned long dev_features; + vq_callback callback[RPMSG_NUM_VRINGS]; int status; unsigned int i, role; + if (!rvdev || !vdev || !shm_io) + return RPMSG_ERR_PARAM; + rdev = &rvdev->rdev; memset(rdev, 0, sizeof(*rdev)); metal_mutex_init(&rdev->lock); @@ -558,19 +708,50 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, rdev->ns_bind_cb = ns_bind_cb; vdev->priv = rvdev; rdev->ops.send_offchannel_raw = rpmsg_virtio_send_offchannel_raw; + rdev->ops.hold_rx_buffer = rpmsg_virtio_hold_rx_buffer; + rdev->ops.release_rx_buffer = rpmsg_virtio_release_rx_buffer; + rdev->ops.get_tx_payload_buffer = rpmsg_virtio_get_tx_payload_buffer; + rdev->ops.send_offchannel_nocopy = rpmsg_virtio_send_offchannel_nocopy; + rdev->ops.release_tx_buffer = rpmsg_virtio_release_tx_buffer; role = rpmsg_virtio_get_role(rvdev); -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) { +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) { + /* + * The virtio configuration contains only options applicable to + * a virtio driver, implying rpmsg host role. + */ + if (config == NULL) { + return RPMSG_ERR_PARAM; + } + rvdev->config = *config; + } +#else /*!VIRTIO_DEVICE_ONLY*/ + /* Ignore passed config in the virtio-device-only configuration. */ + (void)config; +#endif /*!VIRTIO_DEVICE_ONLY*/ + + +#ifndef VIRTIO_DRIVER_ONLY + if (role == RPMSG_REMOTE) { + /* wait synchro with the host */ + rpmsg_virtio_wait_remote_ready(rvdev); + } +#endif /*!VIRTIO_DRIVER_ONLY*/ + vdev->features = rpmsg_virtio_get_features(rvdev); + rdev->support_ns = !!(vdev->features & (1 << VIRTIO_RPMSG_F_NS)); + +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) { /* * Since device is RPMSG Remote so we need to manage the * shared buffers. Create shared memory pool to handle buffers. */ + rvdev->shpool = config->split_shpool ? shpool + 1 : shpool; if (!shpool) return RPMSG_ERR_PARAM; - if (!shpool->size) + if (!shpool->size || !rvdev->shpool->size) return RPMSG_ERR_NO_BUFF; - rvdev->shpool = shpool; vq_names[0] = "rx_vq"; vq_names[1] = "tx_vq"; @@ -579,9 +760,9 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, rvdev->rvq = vdev->vrings_info[0].vq; rvdev->svq = vdev->vrings_info[1].vq; } -#endif /*!VIRTIO_SLAVE_ONLY*/ +#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_MASTER_ONLY +#ifndef VIRTIO_DRIVER_ONLY (void)shpool; if (role == RPMSG_REMOTE) { vq_names[0] = "tx_vq"; @@ -591,15 +772,9 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, rvdev->rvq = vdev->vrings_info[1].vq; rvdev->svq = vdev->vrings_info[0].vq; } -#endif /*!VIRTIO_MASTER_ONLY*/ +#endif /*!VIRTIO_DRIVER_ONLY*/ rvdev->shbuf_io = shm_io; - -#ifndef VIRTIO_MASTER_ONLY - if (role == RPMSG_REMOTE) { - /* wait synchro with the master */ - rpmsg_virtio_wait_remote_ready(rvdev); - } -#endif /*!VIRTIO_MASTER_ONLY*/ + metal_list_init(&rvdev->reclaimer); /* Create virtqueues for remote device */ status = rpmsg_virtio_create_virtqueues(rvdev, 0, RPMSG_NUM_VRINGS, @@ -607,6 +782,12 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, if (status != RPMSG_SUCCESS) return status; + /* + * Suppress "tx-complete" interrupts + * since send method use busy loop when buffer pool exhaust + */ + virtqueue_disable_cb(rvdev->svq); + /* TODO: can have a virtio function to set the shared memory I/O */ for (i = 0; i < RPMSG_NUM_VRINGS; i++) { struct virtqueue *vq; @@ -615,17 +796,17 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, vq->shm_io = shm_io; } -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) { +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) { struct virtqueue_buf vqbuf; unsigned int idx; void *buffer; - vqbuf.len = RPMSG_BUFFER_SIZE; + vqbuf.len = rvdev->config.r2h_buf_size; for (idx = 0; idx < rvdev->rvq->vq_nentries; idx++) { /* Initialize TX virtqueue buffers for remote device */ buffer = rpmsg_virtio_shm_pool_get_buffer(shpool, - RPMSG_BUFFER_SIZE); + rvdev->config.r2h_buf_size); if (!buffer) { return RPMSG_ERR_NO_BUFF; @@ -636,7 +817,7 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, metal_io_block_set(shm_io, metal_io_virt_to_offset(shm_io, buffer), - 0x00, RPMSG_BUFFER_SIZE); + 0x00, rvdev->config.r2h_buf_size); status = virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, buffer); @@ -646,28 +827,25 @@ int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev, } } } -#endif /*!VIRTIO_SLAVE_ONLY*/ +#endif /*!VIRTIO_DEVICE_ONLY*/ /* Initialize channels and endpoints list */ metal_list_init(&rdev->endpoints); - dev_features = rpmsg_virtio_get_features(rvdev); - /* * Create name service announcement endpoint if device supports name * service announcement feature. */ - if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) { - rpmsg_init_ept(&rdev->ns_ept, "NS", - RPMSG_NS_EPT_ADDR, RPMSG_NS_EPT_ADDR, - rpmsg_virtio_ns_callback, NULL); - (void)rpmsg_register_endpoint(rdev, &rdev->ns_ept); + if (rdev->support_ns) { + rpmsg_register_endpoint(rdev, &rdev->ns_ept, "NS", + RPMSG_NS_EPT_ADDR, RPMSG_NS_EPT_ADDR, + rpmsg_virtio_ns_callback, NULL); } -#ifndef VIRTIO_SLAVE_ONLY - if (role == RPMSG_MASTER) +#ifndef VIRTIO_DEVICE_ONLY + if (role == RPMSG_HOST) rpmsg_virtio_set_status(rvdev, VIRTIO_CONFIG_STATUS_DRIVER_OK); -#endif /*!VIRTIO_SLAVE_ONLY*/ +#endif /*!VIRTIO_DEVICE_ONLY*/ return status; } @@ -678,15 +856,17 @@ void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev) struct rpmsg_device *rdev; struct rpmsg_endpoint *ept; - rdev = &rvdev->rdev; - while (!metal_list_is_empty(&rdev->endpoints)) { - node = rdev->endpoints.next; - ept = metal_container_of(node, struct rpmsg_endpoint, node); - rpmsg_destroy_ept(ept); - } + if (rvdev) { + rdev = &rvdev->rdev; + while (!metal_list_is_empty(&rdev->endpoints)) { + node = rdev->endpoints.next; + ept = metal_container_of(node, struct rpmsg_endpoint, node); + rpmsg_destroy_ept(ept); + } - rvdev->rvq = 0; - rvdev->svq = 0; + rvdev->rvq = 0; + rvdev->svq = 0; - metal_mutex_deinit(&rdev->lock); + metal_mutex_deinit(&rdev->lock); + } } diff --git a/libraries/openamp_arduino/src/rsc_table.c b/libraries/openamp_arduino/src/rsc_table.c index 1c2f646..3fde247 100644 --- a/libraries/openamp_arduino/src/rsc_table.c +++ b/libraries/openamp_arduino/src/rsc_table.c @@ -122,7 +122,7 @@ void resource_table_init(int RPMsgRole, void **table_ptr, int *length) * Currently the GCC linker doesn't initialize the resource_table global variable at startup * it is done here by the CM7 application. */ - memset((void *)&resource_table, '\0', sizeof(struct shared_resource_table)); + memset(&resource_table, '\0', sizeof(struct shared_resource_table)); resource_table.num = 1; resource_table.version = 1; resource_table.offset[0] = offsetof(struct shared_resource_table, vdev); @@ -153,5 +153,5 @@ void resource_table_init(int RPMsgRole, void **table_ptr, int *length) (void)RPMsgRole; *length = sizeof(resource_table); - *table_ptr = (void *)&resource_table; + *table_ptr = &resource_table; } diff --git a/libraries/openamp_arduino/src/rsc_table.h b/libraries/openamp_arduino/src/rsc_table.h index 035b2d3..a84933b 100644 --- a/libraries/openamp_arduino/src/rsc_table.h +++ b/libraries/openamp_arduino/src/rsc_table.h @@ -1,60 +1,60 @@ -/* - * 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. - */ - -/* This file populates resource table for BM remote - * for use by the Linux Master */ - -#ifndef RSC_TABLE_H_ -#define RSC_TABLE_H_ - -#include "openamp/open_amp.h" -#include "openamp_conf.h" - -/* Place resource table in special ELF section */ - -/* Resource table for the given remote */ -struct shared_resource_table { - unsigned int version; - unsigned int num; - unsigned int reserved[2]; - unsigned int offset[NUM_RESOURCE_ENTRIES]; - /* text carveout entry */ - - /* rpmsg vdev entry */ - struct fw_rsc_vdev vdev; - struct fw_rsc_vdev_vring vring0; - struct fw_rsc_vdev_vring vring1; - struct fw_rsc_trace cm_trace; -}; - -void resource_table_init(int RPMsgRole, void **table_ptr, int *length); - -#endif /* RSC_TABLE_H_ */ - +/* + * 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. + */ + +/* This file populates resource table for BM remote + * for use by the Linux Master */ + +#ifndef RSC_TABLE_H_ +#define RSC_TABLE_H_ + +#include "openamp/open_amp.h" +#include "openamp_conf.h" + +/* Place resource table in special ELF section */ + +/* Resource table for the given remote */ +struct shared_resource_table { + unsigned int version; + unsigned int num; + unsigned int reserved[2]; + unsigned int offset[NUM_RESOURCE_ENTRIES]; + /* text carveout entry */ + + /* rpmsg vdev entry */ + struct fw_rsc_vdev vdev; + struct fw_rsc_vdev_vring vring0; + struct fw_rsc_vdev_vring vring1; + struct fw_rsc_trace cm_trace; +}; + +void resource_table_init(int RPMsgRole, void **table_ptr, int *length); + +#endif /* RSC_TABLE_H_ */ + diff --git a/libraries/openamp_arduino/src/rsc_table_parser.c b/libraries/openamp_arduino/src/rsc_table_parser.c new file mode 100644 index 0000000..c099f84 --- /dev/null +++ b/libraries/openamp_arduino/src/rsc_table_parser.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2018, Xilinx Inc. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc); + +/* Resources handler */ +static const rsc_handler rsc_handler_table[] = { + handle_carve_out_rsc, /**< carved out resource */ + handle_dummy_rsc, /**< IOMMU dev mem resource */ + handle_trace_rsc, /**< trace buffer resource */ + handle_vdev_rsc, /**< virtio resource */ +}; + +int handle_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, size_t size, + struct metal_io_region *io) +{ + struct fw_rsc_hdr *hdr; + uint32_t rsc_type; + unsigned int idx, offset; + int 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 */ + offset = sizeof(struct resource_table) + + rsc_table->num * sizeof(rsc_table->offset[0]); + + if (offset > 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; + } + + /* Loop through the offset array and parse each resource entry */ + for (idx = 0; idx < rsc_table->num; idx++) { + hdr = (void *)((char *)rsc_table + rsc_table->offset[idx]); + if (io && metal_io_virt_to_offset(io, hdr) == METAL_BAD_OFFSET) + return -RPROC_ERR_RSC_TAB_TRUNC; + rsc_type = hdr->type; + if (rsc_type < RSC_LAST) + status = rsc_handler_table[rsc_type](rproc, hdr); + else if (rsc_type >= RSC_VENDOR_START && + rsc_type <= RSC_VENDOR_END) + status = handle_vendor_rsc(rproc, hdr); + if (status == -RPROC_ERR_RSC_TAB_NS) { + status = 0; + continue; + } else if (status) { + break; + } + } + + return status; +} + +int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc) +{ + struct fw_rsc_carveout *carve_rsc = rsc; + metal_phys_addr_t da; + metal_phys_addr_t pa; + size_t size; + unsigned int attribute; + + /* Validate resource fields */ + if (!carve_rsc) { + return -RPROC_ERR_RSC_TAB_NP; + } + + if (carve_rsc->reserved) { + return -RPROC_ERR_RSC_TAB_RSVD; + } + pa = carve_rsc->pa; + da = carve_rsc->da; + size = carve_rsc->len; + attribute = carve_rsc->flags; + if (remoteproc_mmap(rproc, &pa, &da, size, attribute, NULL)) + return 0; + else + return -RPROC_EINVAL; +} + +int handle_vendor_rsc(struct remoteproc *rproc, void *rsc) +{ + if (rproc && rproc->ops->handle_rsc) { + struct fw_rsc_vendor *vend_rsc = rsc; + size_t len = vend_rsc->len; + + return rproc->ops->handle_rsc(rproc, rsc, len); + } + return -RPROC_ERR_RSC_TAB_NS; +} + +int handle_vdev_rsc(struct remoteproc *rproc, void *rsc) +{ + struct fw_rsc_vdev *vdev_rsc = rsc; + int i, num_vrings; + unsigned int notifyid; + struct fw_rsc_vdev_vring *vring_rsc; + + /* only assign notification IDs but do not initialize vdev */ + notifyid = vdev_rsc->notifyid; + notifyid = remoteproc_allocate_id(rproc, + notifyid, + notifyid == RSC_NOTIFY_ID_ANY ? + RSC_NOTIFY_ID_ANY : notifyid + 1); + if (notifyid != RSC_NOTIFY_ID_ANY) + vdev_rsc->notifyid = notifyid; + else + return -RPROC_ERR_RSC_TAB_NP; + + num_vrings = vdev_rsc->num_of_vrings; + for (i = 0; i < num_vrings; i++) { + vring_rsc = &vdev_rsc->vring[i]; + notifyid = vring_rsc->notifyid; + notifyid = remoteproc_allocate_id(rproc, + notifyid, + notifyid == RSC_NOTIFY_ID_ANY ? + RSC_NOTIFY_ID_ANY : notifyid + 1); + if (notifyid != RSC_NOTIFY_ID_ANY) + vring_rsc->notifyid = notifyid; + else + goto err; + } + + return 0; + +err: + for (i--; i >= 0; i--) { + vring_rsc = &vdev_rsc->vring[i]; + metal_bitmap_clear_bit(&rproc->bitmap, vring_rsc->notifyid); + } + metal_bitmap_clear_bit(&rproc->bitmap, vdev_rsc->notifyid); + + return -RPROC_ERR_RSC_TAB_NP; +} + +int handle_trace_rsc(struct remoteproc *rproc, void *rsc) +{ + struct fw_rsc_trace *vdev_rsc = rsc; + (void)rproc; + + if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0) + return 0; + /* FIXME: The host should allocated a memory used by remote */ + + return -RPROC_ERR_RSC_TAB_NS; +} + +/** + * @internal + * + * @brief Dummy resource handler. + * + * @param rproc Pointer to remote remoteproc + * @param rsc Pointer to trace resource + * + * @return No service error + */ +static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc) +{ + (void)rproc; + (void)rsc; + + return -RPROC_ERR_RSC_TAB_NS; +} + +size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index) +{ + struct resource_table *r_table = rsc_table; + struct fw_rsc_hdr *hdr; + unsigned int i, rsc_index; + unsigned int lrsc_type; + + metal_assert(r_table); + if (!r_table) + return 0; + + /* Loop through the offset array and parse each resource entry */ + rsc_index = 0; + for (i = 0; i < r_table->num; i++) { + hdr = (void *)((char *)r_table + r_table->offset[i]); + lrsc_type = hdr->type; + if (lrsc_type == rsc_type) { + if (rsc_index++ == index) + return r_table->offset[i]; + } + } + return 0; +} diff --git a/libraries/openamp_arduino/src/shmem.c b/libraries/openamp_arduino/src/shmem.c index 5ead8e7..0ded4ec 100644 --- a/libraries/openamp_arduino/src/shmem.c +++ b/libraries/openamp_arduino/src/shmem.c @@ -9,8 +9,8 @@ * @brief Generic libmetal shared memory handling. */ -#include #include +#include #include #include #include @@ -38,10 +38,10 @@ int metal_shmem_open_generic(const char *name, size_t size, shmem = metal_container_of(node, struct metal_generic_shmem, node); if (strcmp(shmem->name, name) != 0) continue; - if (size > metal_io_region_size(&shmem->io)) - continue; - *result = &shmem->io; - return 0; + if (size <= metal_io_region_size(&shmem->io)) { + *result = &shmem->io; + return 0; + } } return -ENOENT; diff --git a/libraries/openamp_arduino/src/softirq.c b/libraries/openamp_arduino/src/softirq.c new file mode 100644 index 0000000..4ba745f --- /dev/null +++ b/libraries/openamp_arduino/src/softirq.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define METAL_SOFTIRQ_NUM 64 + +#define METAL_SOFTIRQ_ARRAY_DECLARE(num) \ + static const int metal_softirq_num = num; \ + static struct metal_irq metal_softirqs[num]; \ + static atomic_char metal_softirq_pending[num]; \ + static atomic_char metal_softirq_enabled[num]; + +static int metal_softirq_avail; +METAL_SOFTIRQ_ARRAY_DECLARE(METAL_SOFTIRQ_NUM) + +static void metal_softirq_set_enable(struct metal_irq_controller *cntr, + int irq, unsigned int enable) +{ + if (irq < cntr->irq_base || + irq >= (cntr->irq_base + cntr->irq_num)) { + return; + } + + irq -= cntr->irq_base; + if (enable == METAL_IRQ_ENABLE) { + atomic_store(&metal_softirq_enabled[irq], 1); + } else { + atomic_store(&metal_softirq_enabled[irq], 0); + } +} + +static METAL_IRQ_CONTROLLER_DECLARE(metal_softirq_cntr, + METAL_IRQ_ANY, METAL_SOFTIRQ_NUM, + NULL, + metal_softirq_set_enable, NULL, + metal_softirqs); + +void metal_softirq_set(int irq) +{ + struct metal_irq_controller *cntr; + + cntr = &metal_softirq_cntr; + + if (irq < cntr->irq_base || + irq >= (cntr->irq_base + cntr->irq_num)) { + return; + } + + irq -= cntr->irq_base; + atomic_store(&metal_softirq_pending[irq], 1); +} + +int metal_softirq_init(void) +{ + return metal_irq_register_controller(&metal_softirq_cntr); +} + +int metal_softirq_allocate(int num) +{ + int irq_base; + + if ((metal_softirq_avail + num) >= metal_softirq_num) { + metal_log(METAL_LOG_ERROR, "No %d available soft irqs.\r\n", + num); + return -EINVAL; + } + irq_base = metal_softirq_avail; + irq_base += metal_softirq_cntr.irq_base; + metal_softirq_avail += num; + return irq_base; +} + +void metal_softirq_dispatch(void) +{ + int i; + + for (i = 0; i < metal_softirq_num; i++) { + struct metal_irq *irq; + char is_pending = 1; + + if (atomic_load(&metal_softirq_enabled[i]) != 0 && + atomic_compare_exchange_strong(&metal_softirq_pending[i], + &is_pending, 0)) { + irq = &metal_softirqs[i]; + (void)metal_irq_handle(irq, + i + metal_softirq_cntr.irq_base); + } + } +} diff --git a/libraries/openamp_arduino/src/version.c b/libraries/openamp_arduino/src/version.c new file mode 100644 index 0000000..bc23ee4 --- /dev/null +++ b/libraries/openamp_arduino/src/version.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +int metal_ver_major(void) +{ + return METAL_VER_MAJOR; +} + +int metal_ver_minor(void) +{ + return METAL_VER_MINOR; +} + +int metal_ver_patch(void) +{ + return METAL_VER_PATCH; +} + +const char *metal_ver(void) +{ + return METAL_VER; +} diff --git a/libraries/openamp_arduino/src/virtio.c b/libraries/openamp_arduino/src/virtio.c index 5cf8722..794212a 100644 --- a/libraries/openamp_arduino/src/virtio.c +++ b/libraries/openamp_arduino/src/virtio.c @@ -9,7 +9,10 @@ static const char *virtio_feature_name(unsigned long feature, const struct virtio_feature_desc *); -//TODO : This structure may change depending on the types of devices we support. +/* + * TODO : + * This structure may change depending on the types of devices we support. + */ static const struct virtio_ident { unsigned short devid; const char *name; @@ -23,6 +26,17 @@ static const struct virtio_ident { VIRTIO_ID_IOMEMORY, "IOMemory"}, { VIRTIO_ID_SCSI, "SCSI"}, { VIRTIO_ID_9P, "9P Transport"}, { + VIRTIO_ID_MAC80211_WLAN, "MAC80211 WLAN"}, { + VIRTIO_ID_RPROC_SERIAL, "Remoteproc Serial"}, { + VIRTIO_ID_GPU, "GPU"}, { + VIRTIO_ID_INPUT, "Input"}, { + VIRTIO_ID_VSOCK, "Vsock Transport"}, { + VIRTIO_ID_SOUND, "Sound"}, { + VIRTIO_ID_FS, "File System"}, { + VIRTIO_ID_MAC80211_HWSIM, "MAC80211 HWSIM"}, { + VIRTIO_ID_I2C_ADAPTER, "I2C Adapter"}, { + VIRTIO_ID_BT, "Bluetooth"}, { + VIRTIO_ID_GPIO, "GPIO" }, { 0, NULL} }; @@ -40,12 +54,12 @@ const char *virtio_dev_name(unsigned short devid) { const struct virtio_ident *ident; - for (ident = virtio_ident_table; ident->name != NULL; ident++) { + for (ident = virtio_ident_table; ident->name; ident++) { if (ident->devid == devid) - return (ident->name); + return ident->name; } - return (NULL); + return NULL; } static const char *virtio_feature_name(unsigned long val, @@ -62,27 +76,27 @@ static const char *virtio_feature_name(unsigned long val, for (j = 0; descs[i][j].vfd_val != 0; j++) { if (val == descs[i][j].vfd_val) - return (descs[i][j].vfd_str); + return descs[i][j].vfd_str; } } - return (NULL); + return NULL; } -void virtio_describe(struct virtio_device *dev, const char *msg, - uint32_t features, struct virtio_feature_desc *desc) +__deprecated void virtio_describe(struct virtio_device *dev, const char *msg, + uint32_t features, struct virtio_feature_desc *desc) { (void)dev; (void)msg; (void)features; - // TODO: Not used currently - keeping it for future use + /* TODO: Not used currently - keeping it for future use*/ virtio_feature_name(0, desc); } int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, unsigned int nvqs, const char *names[], - vq_callback *callbacks[]) + vq_callback callbacks[], void *callback_args[]) { struct virtio_vring_info *vring_info; struct vring_alloc_info *vring_alloc; @@ -90,16 +104,24 @@ int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, int ret; (void)flags; + if (!vdev) + return -EINVAL; + + if (vdev->func && vdev->func->create_virtqueues) { + return vdev->func->create_virtqueues(vdev, flags, nvqs, + names, callbacks, callback_args); + } + num_vrings = vdev->vrings_num; if (nvqs > num_vrings) - return -ERROR_VQUEUE_INVLD_PARAM; + return ERROR_VQUEUE_INVLD_PARAM; /* Initialize virtqueue for each vring */ for (i = 0; i < nvqs; i++) { vring_info = &vdev->vrings_info[i]; vring_alloc = &vring_info->info; -#ifndef VIRTIO_SLAVE_ONLY - if (vdev->role == VIRTIO_DEV_MASTER) { +#ifndef VIRTIO_DEVICE_ONLY + if (vdev->role == VIRTIO_DEV_DRIVER) { size_t offset; struct metal_io_region *io = vring_info->io; diff --git a/libraries/openamp_arduino/src/virtio_mmio_drv.c b/libraries/openamp_arduino/src/virtio_mmio_drv.c new file mode 100644 index 0000000..5f42180 --- /dev/null +++ b/libraries/openamp_arduino/src/virtio_mmio_drv.c @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2022 Wind River Systems, Inc. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +void virtio_mmio_isr(struct virtio_device *vdev); + +typedef void (*virtio_mmio_vq_callback)(void *); + +static int virtio_mmio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback callbacks[], void *callback_args[]); + +static inline void virtio_mmio_write32(struct virtio_device *vdev, int offset, uint32_t value) +{ + struct virtio_mmio_device *vmdev = metal_container_of(vdev, + struct virtio_mmio_device, vdev); + + metal_io_write32(vmdev->cfg_io, offset, value); +} + +static inline uint32_t virtio_mmio_read32(struct virtio_device *vdev, int offset) +{ + struct virtio_mmio_device *vmdev = metal_container_of(vdev, + struct virtio_mmio_device, vdev); + + return metal_io_read32(vmdev->cfg_io, offset); +} + +static inline uint8_t virtio_mmio_read8(struct virtio_device *vdev, int offset) +{ + struct virtio_mmio_device *vmdev = metal_container_of(vdev, + struct virtio_mmio_device, vdev); + + return metal_io_read8(vmdev->cfg_io, offset); +} + +static inline void virtio_mmio_set_status(struct virtio_device *vdev, uint8_t status) +{ + virtio_mmio_write32(vdev, VIRTIO_MMIO_STATUS, status); +} + +static uint8_t virtio_mmio_get_status(struct virtio_device *vdev) +{ + return virtio_mmio_read32(vdev, VIRTIO_MMIO_STATUS); +} + +static void virtio_mmio_write_config(struct virtio_device *vdev, + uint32_t offset, void *dst, int length) +{ + (void)(vdev); + (void)(offset); + (void)(dst); + (void)length; + + metal_log(METAL_LOG_WARNING, "%s not supported\n", __func__); +} + +static void virtio_mmio_read_config(struct virtio_device *vdev, + uint32_t offset, void *dst, int length) +{ + int i; + uint8_t *d = dst; + (void)(offset); + + for (i = 0; i < length; i++) + d[i] = virtio_mmio_read8(vdev, VIRTIO_MMIO_CONFIG + i); +} + +static uint32_t _virtio_mmio_get_features(struct virtio_device *vdev, int idx) +{ + uint32_t hfeatures; + + /* Writing selection register VIRTIO_MMIO_DEVICE_FEATURES_SEL. In pure AMP + * mode this needs to be followed by a synchronization w/ the device + * before reading VIRTIO_MMIO_DEVICE_FEATURES + */ + virtio_mmio_write32(vdev, VIRTIO_MMIO_DEVICE_FEATURES_SEL, idx); + hfeatures = virtio_mmio_read32(vdev, VIRTIO_MMIO_DEVICE_FEATURES); + return hfeatures & vdev->features; +} + +static uint32_t virtio_mmio_get_features(struct virtio_device *vdev) +{ + return _virtio_mmio_get_features(vdev, 0); +} + +/* This is more like negotiate_features */ +static void _virtio_mmio_set_features(struct virtio_device *vdev, + uint32_t features, int idx) +{ + uint32_t hfeatures; + + /* Writing selection register VIRTIO_MMIO_DEVICE_FEATURES_SEL. In pure AMP + * mode this needs to be followed by a synchronization w/ the device + * before reading VIRTIO_MMIO_DEVICE_FEATURES + */ + virtio_mmio_write32(vdev, VIRTIO_MMIO_DEVICE_FEATURES_SEL, idx); + hfeatures = virtio_mmio_read32(vdev, VIRTIO_MMIO_DEVICE_FEATURES); + features &= hfeatures; + virtio_mmio_write32(vdev, VIRTIO_MMIO_DRIVER_FEATURES, features); + vdev->features = features; +} + +static void virtio_mmio_set_features(struct virtio_device *vdev, uint32_t features) +{ + _virtio_mmio_set_features(vdev, features, 0); +} + +static void virtio_mmio_reset_device(struct virtio_device *vdev) +{ + virtio_mmio_set_status(vdev, 0); +} + +static void virtio_mmio_notify(struct virtqueue *vq) +{ + /* VIRTIO_F_NOTIFICATION_DATA is not supported for now */ + virtio_mmio_write32(vq->vq_dev, VIRTIO_MMIO_QUEUE_NOTIFY, vq->vq_queue_index); +} + +const struct virtio_dispatch virtio_mmio_dispatch = { + .create_virtqueues = virtio_mmio_create_virtqueues, + .get_status = virtio_mmio_get_status, + .set_status = virtio_mmio_set_status, + .get_features = virtio_mmio_get_features, + .set_features = virtio_mmio_set_features, + .read_config = virtio_mmio_read_config, + .write_config = virtio_mmio_write_config, + .reset_device = virtio_mmio_reset_device, + .notify = virtio_mmio_notify, +}; + +static int virtio_mmio_get_metal_io(struct virtio_device *vdev, uintptr_t virt_mem_ptr, + uintptr_t cfg_mem_ptr) +{ + struct metal_device *device; + int32_t err; + struct virtio_mmio_device *vmdev = metal_container_of(vdev, + struct virtio_mmio_device, vdev); + + /* Setup shared memory device */ + vmdev->shm_device.regions[0].physmap = (metal_phys_addr_t *)&vmdev->shm_mem.base; + vmdev->shm_device.regions[0].virt = (void *)virt_mem_ptr; + vmdev->shm_device.regions[0].size = vmdev->shm_mem.size; + + VIRTIO_ASSERT((METAL_MAX_DEVICE_REGIONS > 1), + "METAL_MAX_DEVICE_REGIONS must be greater that 1"); + + vmdev->shm_device.regions[1].physmap = (metal_phys_addr_t *)&vmdev->cfg_mem.base; + vmdev->shm_device.regions[1].virt = (void *)cfg_mem_ptr; + vmdev->shm_device.regions[1].size = vmdev->cfg_mem.size; + + err = metal_register_generic_device(&vmdev->shm_device); + if (err) { + metal_log(METAL_LOG_ERROR, "Couldn't register shared memory device: %d\n", err); + return err; + } + + err = metal_device_open("generic", vmdev->shm_device.name, &device); + if (err) { + metal_log(METAL_LOG_ERROR, "metal_device_open failed: %d", err); + return err; + } + + vmdev->shm_io = metal_device_io_region(device, 0); + if (!vmdev->shm_io) { + metal_log(METAL_LOG_ERROR, "metal_device_io_region failed to get region 0"); + return err; + } + + vmdev->cfg_io = metal_device_io_region(device, 1); + if (!vmdev->cfg_io) { + metal_log(METAL_LOG_ERROR, "metal_device_io_region failed to get region 1"); + return err; + } + + return 0; +} + +uint32_t virtio_mmio_get_max_elem(struct virtio_device *vdev, int idx) +{ + /* Select the queue we're interested in by writing selection register + * VIRTIO_MMIO_QUEUE_SEL. In pure AMP mode this needs to be followed by a + * synchronization w/ the device before reading VIRTIO_MMIO_QUEUE_NUM_MAX + */ + virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_SEL, idx); + return virtio_mmio_read32(vdev, VIRTIO_MMIO_QUEUE_NUM_MAX); +} + +int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem_ptr, + uintptr_t cfg_mem_ptr, void *user_data) +{ + struct virtio_device *vdev = &vmdev->vdev; + uint32_t magic, version, devid, vendor; + + vdev->role = vmdev->device_mode; + vdev->priv = vmdev; + vdev->func = &virtio_mmio_dispatch; + vmdev->user_data = user_data; + + /* Set metal io mem ops */ + virtio_mmio_get_metal_io(vdev, virt_mem_ptr, cfg_mem_ptr); + + magic = virtio_mmio_read32(vdev, VIRTIO_MMIO_MAGIC_VALUE); + if (magic != VIRTIO_MMIO_MAGIC_VALUE_STRING) { + metal_log(METAL_LOG_ERROR, "Bad magic value %08x\n", magic); + return -1; + } + + version = virtio_mmio_read32(vdev, VIRTIO_MMIO_VERSION); + devid = virtio_mmio_read32(vdev, VIRTIO_MMIO_DEVICE_ID); + if (devid == 0) { + /* Placeholder */ + return -1; + } + + if (version != 1) { + metal_log(METAL_LOG_ERROR, "Bad version %08x\n", version); + return -1; + } + + vendor = virtio_mmio_read32(vdev, VIRTIO_MMIO_VENDOR_ID); + metal_log(METAL_LOG_DEBUG, "VIRTIO %08x:%08x\n", vendor, devid); + + vdev->id.version = version; + vdev->id.device = devid; + vdev->id.vendor = vendor; + + virtio_mmio_set_status(vdev, VIRTIO_CONFIG_STATUS_ACK); + virtio_mmio_write32(vdev, VIRTIO_MMIO_GUEST_PAGE_SIZE, 4096); + + return 0; +} + +/* Register preallocated virtqueues */ +void virtio_mmio_register_device(struct virtio_device *vdev, int vq_num, struct virtqueue **vqs) +{ + int i; + + vdev->vrings_info = metal_allocate_memory(sizeof(struct virtio_vring_info) * vq_num); + /* TODO: handle error case */ + for (i = 0; i < vq_num; i++) { + vdev->vrings_info[i].vq = vqs[i]; + } + vdev->vrings_num = vq_num; +} + +struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev, + unsigned int idx, + struct virtqueue *vq, + void (*cb)(void *), + void *cb_arg, + const char *vq_name) +{ + uint32_t maxq; + struct virtio_vring_info _vring_info = {0}; + struct virtio_vring_info *vring_info = &_vring_info; + struct vring_alloc_info *vring_alloc_info; + struct virtio_mmio_device *vmdev = metal_container_of(vdev, + struct virtio_mmio_device, vdev); + + if (vdev->role != (unsigned int)VIRTIO_DEV_DRIVER) { + metal_log(METAL_LOG_ERROR, "Only VIRTIO_DEV_DRIVER is currently supported\n"); + return NULL; + } + + if (!vq) { + metal_log(METAL_LOG_ERROR, + "Only preallocated virtqueues are currently supported\n"); + return NULL; + } + + if (vdev->id.version != 0x1) { + metal_log(METAL_LOG_ERROR, + "Only VIRTIO MMIO version 1 is currently supported\n"); + return NULL; + } + + vring_info->io = vmdev->shm_io; + vring_info->info.num_descs = virtio_mmio_get_max_elem(vdev, idx); + vring_info->info.align = VIRTIO_MMIO_VRING_ALIGNMENT; + + /* Check if vrings are already configured */ + if (vq->vq_nentries != 0 && vq->vq_nentries == vq->vq_free_cnt && + vq->vq_ring.desc) { + vring_info->info.vaddr = vq->vq_ring.desc; + vring_info->vq = vq; + } + vring_info->info.num_descs = vq->vq_nentries; + + vq->vq_dev = vdev; + + vring_alloc_info = &vring_info->info; + + unsigned int role_bk = vdev->role; + /* Assign OA VIRTIO_DEV_DRIVER role to allow virtio guests to setup the vrings */ + vdev->role = (unsigned int)VIRTIO_DEV_DRIVER; + if (virtqueue_create(vdev, idx, vq_name, vring_alloc_info, (void (*)(struct virtqueue *))cb, + vdev->func->notify, vring_info->vq)) { + metal_log(METAL_LOG_ERROR, "virtqueue_create failed\n"); + return NULL; + } + vdev->role = role_bk; + vq->priv = cb_arg; + virtqueue_set_shmem_io(vq, vmdev->shm_io); + + /* Writing selection register VIRTIO_MMIO_QUEUE_SEL. In pure AMP + * mode this needs to be followed by a synchronization w/ the device + * before reading VIRTIO_MMIO_QUEUE_NUM_MAX + */ + virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_SEL, idx); + maxq = virtio_mmio_read32(vdev, VIRTIO_MMIO_QUEUE_NUM_MAX); + VIRTIO_ASSERT((maxq != 0), + "VIRTIO_MMIO_QUEUE_NUM_MAX cannot be 0"); + VIRTIO_ASSERT((maxq >= vq->vq_nentries), + "VIRTIO_MMIO_QUEUE_NUM_MAX must be greater than vqueue->vq_nentries"); + virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_NUM, vq->vq_nentries); + virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_ALIGN, 4096); + virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_PFN, + ((uintptr_t)metal_io_virt_to_phys(vq->shm_io, + (char *)vq->vq_ring.desc)) / 4096); + + vdev->vrings_info[vdev->vrings_num].vq = vq; + vdev->vrings_num++; + virtqueue_enable_cb(vq); + + return vq; +} + +void virtio_mmio_isr(struct virtio_device *vdev) +{ + struct virtio_vring_info *vrings_info = vdev->vrings_info; + + uint32_t isr = virtio_mmio_read32(vdev, VIRTIO_MMIO_INTERRUPT_STATUS); + struct virtqueue *vq; + unsigned int i; + + if (isr & VIRTIO_MMIO_INT_VRING) { + for (i = 0; i < vdev->vrings_num; i++) { + vq = vrings_info[i].vq; + if (vq->callback) + vq->callback(vq->priv); + } + } + + if (isr & ~(VIRTIO_MMIO_INT_VRING)) + metal_log(METAL_LOG_WARNING, "Unhandled interrupt type: 0x%x\n", isr); + + virtio_mmio_write32(vdev, VIRTIO_MMIO_INTERRUPT_ACK, isr); +} + +static int virtio_mmio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, + unsigned int nvqs, const char *names[], + vq_callback callbacks[], void *callback_args[]) +{ + struct virtqueue *vq; + struct virtqueue *vring_vq; + void (*cb)(void *); + void *cb_arg; + unsigned int i; + + (void)flags; + + if (!vdev || !names || !vdev->vrings_info) + return -EINVAL; + + for (i = 0; i < nvqs; i++) { + vring_vq = NULL; + cb = NULL; + cb_arg = NULL; + if (vdev->vrings_info[i].vq) + vring_vq = vdev->vrings_info[i].vq; + if (callbacks) + cb = (virtio_mmio_vq_callback)callbacks[i]; + if (callback_args) + cb_arg = callback_args[i]; + vq = virtio_mmio_setup_virtqueue(vdev, i, vring_vq, cb, cb_arg, names[i]); + if (!vq) + return -ENODEV; + } + + return 0; +} diff --git a/libraries/openamp_arduino/src/virtqueue.c b/libraries/openamp_arduino/src/virtqueue.c index e90a694..2544ee3 100644 --- a/libraries/openamp_arduino/src/virtqueue.c +++ b/libraries/openamp_arduino/src/virtqueue.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -18,9 +19,14 @@ static uint16_t vq_ring_add_buffer(struct virtqueue *, struct vring_desc *, uint16_t, struct virtqueue_buf *, int, int); static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t); static void vq_ring_free_chain(struct virtqueue *, uint16_t); -static int vq_ring_must_notify_host(struct virtqueue *vq); -static void vq_ring_notify_host(struct virtqueue *vq); +static int vq_ring_must_notify(struct virtqueue *vq); +static void vq_ring_notify(struct virtqueue *vq); +#ifndef VIRTIO_DEVICE_ONLY static int virtqueue_nused(struct virtqueue *vq); +#endif +#ifndef VIRTIO_DRIVER_ONLY +static int virtqueue_navail(struct virtqueue *vq); +#endif /* Default implementation of P2V based on libmetal */ static inline void *virtqueue_phys_to_virt(struct virtqueue *vq, @@ -40,21 +46,6 @@ static inline metal_phys_addr_t virtqueue_virt_to_phys(struct virtqueue *vq, return metal_io_virt_to_phys(io, buf); } -/** - * 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 vq - Created VirtIO queue. - * - * @return - Function status - */ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, const char *name, struct vring_alloc_info *ring, void (*callback)(struct virtqueue *vq), @@ -71,7 +62,7 @@ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, if (status == VQUEUE_SUCCESS) { vq->vq_dev = virt_dev; - vq->vq_name = name; + vq->vq_name = name; vq->vq_queue_index = id; vq->vq_nentries = ring->num_descs; vq->vq_free_cnt = vq->vq_nentries; @@ -79,30 +70,17 @@ int virtqueue_create(struct virtio_device *virt_dev, unsigned short id, vq->notify = notify; /* Initialize vring control block in virtqueue. */ - vq_ring_init(vq, (void *)ring->vaddr, ring->align); - - /* Disable callbacks - will be enabled by the application - * once initialization is completed. - */ - virtqueue_disable_cb(vq); + vq_ring_init(vq, ring->vaddr, ring->align); } - return (status); + /* + * CACHE: nothing to be done here. Only desc.next is setup at this + * stage but that is only written by driver, so no need to flush it. + */ + + 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 buf_list - Pointer to a list of virtqueue buffers. - * @param readable - Number of readable buffers - * @param writable - Number of writable buffers - * @param cookie - Pointer to hold call back data - * - * @return - Function status - */ int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, int readable, int writable, void *cookie) { @@ -116,7 +94,7 @@ int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, VQ_PARAM_CHK(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); + VQ_PARAM_CHK(vq->vq_free_cnt < needed, status, ERROR_VRING_FULL); VQUEUE_BUSY(vq); @@ -158,23 +136,17 @@ int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, 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 - * @param idx - index of the buffer - * - * @return - Pointer to used buffer - */ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx) { struct vring_used_elem *uep; void *cookie; uint16_t used_idx, desc_idx; + /* Used.idx is updated by the virtio device, so we need to invalidate */ + VRING_INVALIDATE(&vq->vq_ring.used->idx, sizeof(vq->vq_ring.used->idx)); + if (!vq || vq->vq_used_cons_idx == vq->vq_ring.used->idx) - return (NULL); + return NULL; VQUEUE_BUSY(vq); @@ -183,6 +155,10 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx) atomic_thread_fence(memory_order_seq_cst); + /* Used.ring is written by remote, invalidate it */ + VRING_INVALIDATE(&vq->vq_ring.used->ring[used_idx], + sizeof(vq->vq_ring.used->ring[used_idx])); + desc_idx = (uint16_t)uep->id; if (len) *len = uep->len; @@ -201,15 +177,18 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx) uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx) { + VRING_INVALIDATE(&vq->vq_ring.desc[idx].len, + sizeof(vq->vq_ring.desc[idx].len)); return vq->vq_ring.desc[idx].len; } -/** - * virtqueue_free - Frees VirtIO queue resources - * - * @param vq - Pointer to VirtIO queue control block - * - */ +void *virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx) +{ + VRING_INVALIDATE(&vq->vq_ring.desc[idx].addr, + sizeof(vq->vq_ring.desc[idx].addr)); + return virtqueue_phys_to_virt(vq, vq->vq_ring.desc[idx].addr); +} + void virtqueue_free(struct virtqueue *vq) { if (vq) { @@ -223,16 +202,6 @@ void virtqueue_free(struct virtqueue *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) { @@ -240,6 +209,9 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, void *buffer; atomic_thread_fence(memory_order_seq_cst); + + /* Avail.idx is updated by driver, invalidate it */ + VRING_INVALIDATE(&vq->vq_ring.avail->idx, sizeof(vq->vq_ring.avail->idx)); if (vq->vq_available_idx == vq->vq_ring.avail->idx) { return NULL; } @@ -247,8 +219,15 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, VQUEUE_BUSY(vq); head_idx = vq->vq_available_idx++ & (vq->vq_nentries - 1); + + /* Avail.ring is updated by driver, invalidate it */ + VRING_INVALIDATE(&vq->vq_ring.avail->ring[head_idx], + sizeof(vq->vq_ring.avail->ring[head_idx])); *avail_idx = vq->vq_ring.avail->ring[head_idx]; + /* Invalidate the desc entry written by driver before accessing it */ + VRING_INVALIDATE(&vq->vq_ring.desc[*avail_idx], + sizeof(vq->vq_ring.desc[*avail_idx])); buffer = virtqueue_phys_to_virt(vq, vq->vq_ring.desc[*avail_idx].addr); *len = vq->vq_ring.desc[*avail_idx].len; @@ -257,78 +236,89 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, 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, uint32_t len) { struct vring_used_elem *used_desc = NULL; uint16_t used_idx; - if (head_idx > vq->vq_nentries) { + if (head_idx >= vq->vq_nentries) { return ERROR_VRING_NO_BUFF; } VQUEUE_BUSY(vq); + /* CACHE: used is never written by driver, so it's safe to directly access it */ 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; + /* We still need to flush it because this is read by driver */ + VRING_FLUSH(&vq->vq_ring.used->ring[used_idx], + sizeof(vq->vq_ring.used->ring[used_idx])); + atomic_thread_fence(memory_order_seq_cst); vq->vq_ring.used->idx++; + /* Used.idx is read by driver, so we need to flush it */ + VRING_FLUSH(&vq->vq_ring.used->idx, sizeof(vq->vq_ring.used->idx)); + + /* Keep pending count until virtqueue_notify(). */ + vq->vq_queued_cnt++; + 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; + if (vq->vq_dev->features & VIRTIO_RING_F_EVENT_IDX) { +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + vring_used_event(&vq->vq_ring) = + vq->vq_used_cons_idx - vq->vq_nentries - 1; + VRING_FLUSH(&vring_used_event(&vq->vq_ring), + sizeof(vring_used_event(&vq->vq_ring))); + } +#endif /*VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + vring_avail_event(&vq->vq_ring) = + vq->vq_available_idx - vq->vq_nentries - 1; + VRING_FLUSH(&vring_avail_event(&vq->vq_ring), + sizeof(vring_avail_event(&vq->vq_ring))); + } +#endif /*VIRTIO_DRIVER_ONLY*/ } else { - vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; + VRING_FLUSH(&vq->vq_ring.avail->flags, + sizeof(vq->vq_ring.avail->flags)); + } +#endif /*VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + vq->vq_ring.used->flags |= VRING_USED_F_NO_NOTIFY; + VRING_FLUSH(&vq->vq_ring.used->flags, + sizeof(vq->vq_ring.used->flags)); + } +#endif /*VIRTIO_DRIVER_ONLY*/ } 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); @@ -336,48 +326,42 @@ void virtqueue_kick(struct virtqueue *vq) /* Ensure updated avail->idx is visible to host. */ atomic_thread_fence(memory_order_seq_cst); - if (vq_ring_must_notify_host(vq)) - vq_ring_notify_host(vq); + if (vq_ring_must_notify(vq)) + vq_ring_notify(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) return; + VRING_INVALIDATE(&vq->vq_ring.avail, sizeof(vq->vq_ring.avail)); + VRING_INVALIDATE(&vq->vq_ring.used, sizeof(vq->vq_ring.used)); + metal_log(METAL_LOG_DEBUG, - "VQ: %s - size=%d; free=%d; used=%d; queued=%d; " - "desc_head_idx=%d; avail.idx=%d; used_cons_idx=%d; " + "VQ: %s - size=%d; free=%d; queued=%d; desc_head_idx=%d; " + "available_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_queued_cnt, vq->vq_desc_head_idx, vq->vq_available_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; + /* Avail.idx is updated by driver, invalidate it */ + VRING_INVALIDATE(&vq->vq_ring.avail->idx, sizeof(vq->vq_ring.avail->idx)); + if (vq->vq_available_idx == vq->vq_ring.avail->idx) { return 0; } @@ -385,7 +369,16 @@ uint32_t virtqueue_get_desc_size(struct virtqueue *vq) VQUEUE_BUSY(vq); head_idx = vq->vq_available_idx & (vq->vq_nentries - 1); + + /* Avail.ring is updated by driver, invalidate it */ + VRING_INVALIDATE(&vq->vq_ring.avail->ring[head_idx], + sizeof(vq->vq_ring.avail->ring[head_idx])); avail_idx = vq->vq_ring.avail->ring[head_idx]; + + /* Invalidate the desc entry written by driver before accessing it */ + VRING_INVALIDATE(&vq->vq_ring.desc[avail_idx].len, + sizeof(vq->vq_ring.desc[avail_idx].len)); + len = vq->vq_ring.desc[avail_idx].len; VQUEUE_IDLE(vq); @@ -397,7 +390,7 @@ uint32_t virtqueue_get_desc_size(struct virtqueue *vq) * Helper Functions * **************************************************************************/ -/** +/* * * vq_ring_add_buffer * @@ -419,6 +412,7 @@ static uint16_t vq_ring_add_buffer(struct virtqueue *vq, VQASSERT(vq, idx != VQ_RING_DESC_CHAIN_END, "premature end of free desc chain"); + /* CACHE: No need to invalidate desc because it is only written by driver */ dp = &desc[idx]; dp->addr = virtqueue_virt_to_phys(vq, buf_list[i].buf); dp->len = buf_list[i].len; @@ -433,12 +427,19 @@ static uint16_t vq_ring_add_buffer(struct virtqueue *vq, */ if (i >= readable) dp->flags |= VRING_DESC_F_WRITE; + + /* + * Instead of flushing the whole desc region, we flush only the + * single entry hopefully saving some cycles + */ + VRING_FLUSH(&desc[idx], sizeof(desc[idx])); + } - return (idx); + return idx; } -/** +/* * * vq_ring_free_chain * @@ -448,6 +449,7 @@ static void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) struct vring_desc *dp; struct vq_desc_extra *dxp; + /* CACHE: desc is never written by remote, no need to invalidate */ VQ_RING_ASSERT_VALID_IDX(vq, desc_idx); dp = &vq->vq_ring.desc[desc_idx]; dxp = &vq->vq_descx[desc_idx]; @@ -467,19 +469,21 @@ static void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) } } - VQASSERT(vq, (dxp->ndescs == 0), + 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). + * + * CACHE: desc.next is never read by remote, no need to flush it. */ dp->next = vq->vq_desc_head_idx; vq->vq_desc_head_idx = desc_idx; } -/** +/* * * vq_ring_init * @@ -487,19 +491,25 @@ static void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) static void vq_ring_init(struct virtqueue *vq, void *ring_mem, int alignment) { struct vring *vr; - int i, size; + int size; size = vq->vq_nentries; vr = &vq->vq_ring; - vring_init(vr, size, (unsigned char *)ring_mem, alignment); + vring_init(vr, size, ring_mem, alignment); + +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + int i; - for (i = 0; i < size - 1; i++) - vr->desc[i].next = i + 1; - vr->desc[i].next = VQ_RING_DESC_CHAIN_END; + for (i = 0; i < size - 1; i++) + vr->desc[i].next = i + 1; + vr->desc[i].next = VQ_RING_DESC_CHAIN_END; + } +#endif /*VIRTIO_DEVICE_ONLY*/ } -/** +/* * * vq_ring_update_avail * @@ -514,19 +524,28 @@ static void vq_ring_update_avail(struct virtqueue *vq, uint16_t desc_idx) * 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. + * + * CACHE: avail is never written by remote, so it is safe to not invalidate here */ avail_idx = vq->vq_ring.avail->idx & (vq->vq_nentries - 1); vq->vq_ring.avail->ring[avail_idx] = desc_idx; + /* We still need to flush the ring */ + VRING_FLUSH(&vq->vq_ring.avail->ring[avail_idx], + sizeof(vq->vq_ring.avail->ring[avail_idx])); + atomic_thread_fence(memory_order_seq_cst); vq->vq_ring.avail->idx++; + /* And the index */ + VRING_FLUSH(&vq->vq_ring.avail->idx, sizeof(vq->vq_ring.avail->idx)); + /* Keep pending count until virtqueue_notify(). */ vq->vq_queued_cnt++; } -/** +/* * * vq_ring_enable_interrupt * @@ -537,10 +556,38 @@ 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; + if (vq->vq_dev->features & VIRTIO_RING_F_EVENT_IDX) { +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + vring_used_event(&vq->vq_ring) = + vq->vq_used_cons_idx + ndesc; + VRING_FLUSH(&vring_used_event(&vq->vq_ring), + sizeof(vring_used_event(&vq->vq_ring))); + } +#endif /*VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + vring_avail_event(&vq->vq_ring) = + vq->vq_available_idx + ndesc; + VRING_FLUSH(&vring_avail_event(&vq->vq_ring), + sizeof(vring_avail_event(&vq->vq_ring))); + } +#endif /*VIRTIO_DRIVER_ONLY*/ } else { - vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; + VRING_FLUSH(&vq->vq_ring.avail->flags, + sizeof(vq->vq_ring.avail->flags)); + } +#endif /*VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + vq->vq_ring.used->flags &= ~VRING_USED_F_NO_NOTIFY; + VRING_FLUSH(&vq->vq_ring.used->flags, + sizeof(vq->vq_ring.used->flags)); + } +#endif /*VIRTIO_DRIVER_ONLY*/ } atomic_thread_fence(memory_order_seq_cst); @@ -550,14 +597,25 @@ static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) * since we last checked. Let our caller know so it processes the new * entries. */ - if (virtqueue_nused(vq) > ndesc) { - return 1; +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (virtqueue_nused(vq) > ndesc) { + return 1; + } } +#endif /*VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (virtqueue_navail(vq) > ndesc) { + return 1; + } + } +#endif /*VIRTIO_DRIVER_ONLY*/ return 0; } -/** +/* * * virtqueue_interrupt * @@ -569,46 +627,85 @@ void virtqueue_notification(struct virtqueue *vq) vq->callback(vq); } -/** +/* * - * vq_ring_must_notify_host + * vq_ring_must_notify * */ -static int vq_ring_must_notify_host(struct virtqueue *vq) +static int vq_ring_must_notify(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); + if (vq->vq_dev->features & VIRTIO_RING_F_EVENT_IDX) { +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + /* CACHE: no need to invalidate avail */ + new_idx = vq->vq_ring.avail->idx; + prev_idx = new_idx - vq->vq_queued_cnt; + VRING_INVALIDATE(&vring_avail_event(&vq->vq_ring), + sizeof(vring_avail_event(&vq->vq_ring))); + event_idx = vring_avail_event(&vq->vq_ring); + return vring_need_event(event_idx, new_idx, + prev_idx) != 0; + } +#endif /*VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + /* CACHE: no need to invalidate used */ + new_idx = vq->vq_ring.used->idx; + prev_idx = new_idx - vq->vq_queued_cnt; + VRING_INVALIDATE(&vring_used_event(&vq->vq_ring), + sizeof(vring_used_event(&vq->vq_ring))); + event_idx = vring_used_event(&vq->vq_ring); + return vring_need_event(event_idx, new_idx, + prev_idx) != 0; + } +#endif /*VIRTIO_DRIVER_ONLY*/ + } else { +#ifndef VIRTIO_DEVICE_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + VRING_INVALIDATE(&vq->vq_ring.used->flags, + sizeof(vq->vq_ring.used->flags)); + return (vq->vq_ring.used->flags & + VRING_USED_F_NO_NOTIFY) == 0; + } +#endif /*VIRTIO_DEVICE_ONLY*/ +#ifndef VIRTIO_DRIVER_ONLY + if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + VRING_INVALIDATE(&vq->vq_ring.avail->flags, + sizeof(vq->vq_ring.avail->flags)); + return (vq->vq_ring.avail->flags & + VRING_AVAIL_F_NO_INTERRUPT) == 0; + } +#endif /*VIRTIO_DRIVER_ONLY*/ } - return ((vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) == 0); + return 0; } -/** +/* * - * vq_ring_notify_host + * vq_ring_notify * */ -static void vq_ring_notify_host(struct virtqueue *vq) +static void vq_ring_notify(struct virtqueue *vq) { if (vq->notify) vq->notify(vq); } -/** +/* * * virtqueue_nused * */ +#ifndef VIRTIO_DEVICE_ONLY static int virtqueue_nused(struct virtqueue *vq) { uint16_t used_idx, nused; + /* Used is written by remote */ + VRING_INVALIDATE(&vq->vq_ring.used->idx, sizeof(vq->vq_ring.used->idx)); used_idx = vq->vq_ring.used->idx; nused = (uint16_t)(used_idx - vq->vq_used_cons_idx); @@ -616,3 +713,26 @@ static int virtqueue_nused(struct virtqueue *vq) return nused; } +#endif /*VIRTIO_DEVICE_ONLY*/ + +/* + * + * virtqueue_navail + * + */ +#ifndef VIRTIO_DRIVER_ONLY +static int virtqueue_navail(struct virtqueue *vq) +{ + uint16_t avail_idx, navail; + + /* Avail is written by driver */ + VRING_INVALIDATE(&vq->vq_ring.avail->idx, sizeof(vq->vq_ring.avail->idx)); + + avail_idx = vq->vq_ring.avail->idx; + + navail = (uint16_t)(avail_idx - vq->vq_available_idx); + VQASSERT(vq, navail <= vq->vq_nentries, "avail more than available"); + + return navail; +} +#endif /*VIRTIO_DRIVER_ONLY*/ diff --git a/src/gpio_handler.c b/src/gpio_handler.c index a5b129c..9849e2f 100644 --- a/src/gpio_handler.c +++ b/src/gpio_handler.c @@ -48,6 +48,30 @@ extern struct IRQ_numbers IRQ_pinmap[]; * FUNCTION DEFINITION **************************************************************************************/ +static void configure_pins_shorted_together(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) { + if (GPIO_InitStruct->Pin == GPIO_PIN_10 && GPIOx == GPIOB) { + GPIO_InitStruct->Mode = GPIO_MODE_INPUT; + GPIO_InitStruct->Pull = GPIO_NOPULL; + GPIO_InitStruct->Pin = GPIO_PIN_7; + HAL_GPIO_Init(GPIOG, GPIO_InitStruct); + } + if (GPIO_InitStruct->Pin == GPIO_PIN_15 && GPIOx == GPIOD) { + GPIO_InitStruct->Mode = GPIO_MODE_INPUT; + GPIO_InitStruct->Pull = GPIO_NOPULL; + GPIO_InitStruct->Pin = GPIO_PIN_6; + HAL_GPIO_Init(GPIOG, GPIO_InitStruct); + } +} + +static void write_pins_shorted_together(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) { + if (GPIO_Pin == GPIO_PIN_10 && GPIOx == GPIOB) { + HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, PinState); + } + if (GPIO_Pin == GPIO_PIN_15 && GPIOx == GPIOD) { + HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, PinState); + } +} + int gpio_handler(uint8_t const opcode, uint8_t const * data, uint16_t const size) { uint16_t const gpio_data = *((uint16_t*)data); @@ -66,6 +90,7 @@ int gpio_handler(uint8_t const opcode, uint8_t const * data, uint16_t const size GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIO_pinmap[index].port, &GPIO_InitStruct); + configure_pins_shorted_together(GPIO_pinmap[index].port, &GPIO_InitStruct); dbg_printf("GPIO%d: CONFIGURE %d\n", index, value); break; case IRQ_TYPE: @@ -92,6 +117,7 @@ int gpio_handler(uint8_t const opcode, uint8_t const * data, uint16_t const size break; case WRITE: HAL_GPIO_WritePin(GPIO_pinmap[index].port, GPIO_pinmap[index].pin, value); + write_pins_shorted_together(GPIO_pinmap[index].port, GPIO_pinmap[index].pin, value); dbg_printf("GPIO%d: WRITE %d\n", index, value); break; case READ: diff --git a/src/pwm_handler.c b/src/pwm_handler.c index e3672c9..32f5745 100644 --- a/src/pwm_handler.c +++ b/src/pwm_handler.c @@ -32,7 +32,7 @@ int pwm_handler(uint8_t const opcode, uint8_t const * data, uint16_t const size) { - if (opcode == CAPTURE) + if (opcode & CAPTURE) { uint8_t const channel = opcode & 0x0F; if (isValidPwmChannelNumber(channel)) @@ -40,7 +40,7 @@ int pwm_handler(uint8_t const opcode, uint8_t const * data, uint16_t const size) else dbg_printf("pwm_handler: invalid PWM channel number provided for mode CAPTURE: %d\n", channel); } - else if (opcode == CONFIGURE) + else { uint8_t const channel = opcode; struct pwmPacket config = *((struct pwmPacket*)data); @@ -49,9 +49,5 @@ int pwm_handler(uint8_t const opcode, uint8_t const * data, uint16_t const size) else dbg_printf("pwm_handler: invalid PWM channel number provided for mode PWM: %d\n", channel); } - else - { - dbg_printf("pwm_handler: error invalid opcode (:%d)\n", opcode); - } return 0; } diff --git a/src/rpc.c b/src/rpc.c index bb43e4f..dde303d 100644 --- a/src/rpc.c +++ b/src/rpc.c @@ -24,6 +24,8 @@ #include "arduino_openamp.h" #include "stm32h7xx_hal.h" #include "ringbuffer.h" +#include "stm32h7xx_ll_rcc.h" +#include "debug.h" /************************************************************************************** * TYPEDEF @@ -31,7 +33,7 @@ enum endpoints_t { ENDPOINT_RAW = 0, - ENDPOINT_RESPONSE + ENDPOINT_RPC }; /************************************************************************************** @@ -48,13 +50,6 @@ extern ring_buffer_t virtual_uart_ring_buffer; int rpmsg_recv_raw_callback(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) { -/* - printf("raw: received %d bytes from M4, content:", len); - for (int i = 0; i= 1000) { + dbg_printf("M4 RPC timeout\n"); + return 0; + } + } return 1; } @@ -101,8 +102,8 @@ void serial_rpc_available() { } void serial_rpc_write(uint8_t const * buf, size_t len) { - // check second byte of the message to split requests and responses - OPENAMP_send(&rp_endpoints[buf[1] == 1], buf, len); + // we'll only get rpc requests from "upstairs" + OPENAMP_send(&rp_endpoints[ENDPOINT_RPC], buf, len); } void HSEM1_IRQHandler(void) diff --git a/src/system.c b/src/system.c index a928153..c983324 100644 --- a/src/system.c +++ b/src/system.c @@ -162,11 +162,12 @@ static void MPU_Config(void) MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; - MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER3; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); /* Enable MPU */ diff --git a/src/timer.c b/src/timer.c index fd09526..d58d1d8 100644 --- a/src/timer.c +++ b/src/timer.c @@ -161,6 +161,26 @@ void pwm_timer_config(uint32_t index, uint32_t channel, HAL_HRTIM_SimplePWMChannelConfig(&hhrtim, index, channel, pSimplePWMChannelCfg); HAL_HRTIM_SoftwareUpdate(&hhrtim, timers); + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + if (enable && index == 3) { + GPIO_InitStruct.Pin = GPIO_PIN_7; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF2_HRTIM1; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + } + + if (enable && index == 5) { + GPIO_InitStruct.Pin = GPIO_PIN_6; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF2_HRTIM1; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + } + if (enable) { HAL_HRTIM_SimplePWMStart(&hhrtim, index, channel); } else {