From 6d8bd7375123967986f07ce3e7acd09e252667ca Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 22 Dec 2023 17:00:55 +0100 Subject: [PATCH 1/3] libraries/openamp_arduino: Update Open-AMP to version v2023.10.0 - 1.5.0. Signed-off-by: iabdalkader --- libraries/openamp_arduino/src/elf_loader.c | 707 +++++++ .../src/metal/compiler/gcc/atomic.h | 247 +-- .../src/metal/compiler/gcc/compiler.h | 72 +- .../openamp_arduino/src/openamp/elf_loader.h | 873 +++++---- .../openamp_arduino/src/openamp/open_amp.h | 33 +- .../openamp_arduino/src/openamp/remoteproc.h | 1729 ++++++++--------- .../src/openamp/remoteproc_loader.h | 219 ++- .../src/openamp/remoteproc_virtio.h | 283 ++- libraries/openamp_arduino/src/openamp/rpmsg.h | 925 +++++---- .../src/openamp/rpmsg_retarget.h | 253 +-- .../src/openamp/rpmsg_rpc_client_server.h | 210 ++ .../src/openamp/rpmsg_virtio.h | 494 +++-- .../src/openamp/rsc_table_parser.h | 147 +- .../openamp_arduino/src/openamp/version.h | 81 + .../openamp_arduino/src/openamp/virtio.h | 675 +++++-- .../openamp_arduino/src/openamp/virtio_mmio.h | 221 +++ .../openamp_arduino/src/openamp/virtio_ring.h | 370 ++-- .../openamp_arduino/src/openamp/virtqueue.h | 652 ++++--- libraries/openamp_arduino/src/remoteproc.c | 1030 ++++++++++ .../openamp_arduino/src/remoteproc_virtio.c | 186 +- libraries/openamp_arduino/src/rpmsg.c | 238 ++- .../openamp_arduino/src/rpmsg_internal.h | 221 ++- libraries/openamp_arduino/src/rpmsg_virtio.c | 692 ++++--- .../openamp_arduino/src/rsc_table_parser.c | 212 ++ libraries/openamp_arduino/src/virtio.c | 48 +- .../openamp_arduino/src/virtio_mmio_drv.c | 391 ++++ libraries/openamp_arduino/src/virtqueue.c | 412 ++-- 27 files changed, 7911 insertions(+), 3710 deletions(-) create mode 100644 libraries/openamp_arduino/src/elf_loader.c create mode 100644 libraries/openamp_arduino/src/openamp/rpmsg_rpc_client_server.h create mode 100644 libraries/openamp_arduino/src/openamp/version.h create mode 100644 libraries/openamp_arduino/src/openamp/virtio_mmio.h create mode 100644 libraries/openamp_arduino/src/remoteproc.c create mode 100644 libraries/openamp_arduino/src/rsc_table_parser.c create mode 100644 libraries/openamp_arduino/src/virtio_mmio_drv.c diff --git a/libraries/openamp_arduino/src/elf_loader.c b/libraries/openamp_arduino/src/elf_loader.c new file mode 100644 index 000000000..c90b8d46b --- /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/metal/compiler/gcc/atomic.h b/libraries/openamp_arduino/src/metal/compiler/gcc/atomic.h index 4470342db..7d662992e 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 7295ca899..e4d1bc9b1 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/openamp/elf_loader.h b/libraries/openamp_arduino/src/openamp/elf_loader.h index acf3d2991..a2950f8d7 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 1b0eeac2d..f5d93ede5 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 6b2495c37..23f917861 100755 --- a/libraries/openamp_arduino/src/openamp/remoteproc.h +++ b/libraries/openamp_arduino/src/openamp/remoteproc.h @@ -1,871 +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]; - uint32_t offset[0]; -} 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; - uint8_t data[0]; -} 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]; - struct fw_rsc_vdev_vring vring[0]; -} OPENAMP_PACKED_END; - -/** - * struct fw_rsc_vendor - remote processor vendor specific resource - * @len: length of the resource - * - * This resource entry tells the host the vendor specific resource - * required by the remote. - * - * These request entries should precede other shared resource entries - * such as vdevs, vrings. - */ -OPENAMP_PACKED_BEGIN -struct fw_rsc_vendor { - uint32_t type; - uint32_t len; -} OPENAMP_PACKED_END; - -/** - * struct fw_rsc_rproc_mem - remote processor memory - * @da: device address - * @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 dce3dbb0b..d928fcfce 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 fc1627e45..0b747cacc 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 a9f47c26d..9cf1e7444 100755 --- a/libraries/openamp_arduino/src/openamp/rpmsg.h +++ b/libraries/openamp_arduino/src/openamp/rpmsg.h @@ -1,357 +1,568 @@ -/* - * Remote processor messaging - * - * Copyright (C) 2011 Texas Instruments, Inc. - * Copyright (C) 2011 Google, Inc. - * All rights reserved. - * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef _RPMSG_H_ -#define _RPMSG_H_ - -#include "compiler.h" -#include -#include -#include -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -/* Configurable parameters */ -#define RPMSG_NAME_SIZE (32) -#define RPMSG_ADDR_BMP_SIZE (4) - -#define RPMSG_NS_EPT_ADDR (0x35) -#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) - -struct rpmsg_endpoint; -struct rpmsg_device; - -typedef int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data, - size_t len, uint32_t src, void *priv); -typedef void (*rpmsg_ns_unbind_cb)(struct rpmsg_endpoint *ept); -typedef void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev, - const char *name, uint32_t dest); - -/** - * struct rpmsg_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 - * - * 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 { - char name[RPMSG_NAME_SIZE]; - struct rpmsg_device *rdev; - uint32_t addr; - uint32_t dest_addr; - rpmsg_ept_cb cb; - rpmsg_ns_unbind_cb ns_unbind_cb; - struct metal_list node; - void *priv; -}; - -/** - * struct rpmsg_device_ops - RPMsg device operations - * @send_offchannel_raw: send RPMsg data - */ -struct rpmsg_device_ops { - int (*send_offchannel_raw)(struct rpmsg_device *rdev, - uint32_t src, uint32_t dst, - const void *data, int size, int wait); -}; - -/** - * struct rpmsg_device - representation of a RPMsg device - * @endpoints: list of endpoints - * @ns_ept: name service endpoint - * @bitmap: table endpoin address allocation. - * @lock: mutex lock for rpmsg management - * @ns_bind_cb: callback handler for name service announcement without local - * endpoints waiting to bind. - * @ops: RPMsg device operations - */ -struct rpmsg_device { - struct metal_list endpoints; - struct rpmsg_endpoint ns_ept; - unsigned long bitmap[RPMSG_ADDR_BMP_SIZE]; - metal_mutex_t lock; - rpmsg_ns_bind_cb ns_bind_cb; - struct rpmsg_device_ops ops; -}; - -/** - * rpmsg_send_offchannel_raw() - send a message across to the remote processor, - * specifying source and destination address. - * @ept: the rpmsg endpoint - * @data: payload of the message - * @len: length of the payload - * - * This function sends @data of length @len to the remote @dst address from - * the source @src address. - * The message will be sent to the remote processor which the channel belongs - * to. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. - * - * Returns 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, - 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 - * - * This function sends @data of length @len based on the @ept. - * The message will be sent to the remote processor which the channel belongs - * to, using @ept's source and destination addresses. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. - * - * Returns 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; - 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 - * - * This function sends @data of length @len to the remote @dst address. - * The message will be sent to the remote processor which the @ept - * channel belongs to, using @ept's source address. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. - * - * Returns 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) -{ - 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 - * - * This function sends @data of length @len to the remote @dst address, - * and uses @src as the source address. - * The message will be sent to the remote processor which the @ept - * channel belongs to. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. - * - * Returns 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, - const void *data, int len) -{ - return rpmsg_send_offchannel_raw(ept, src, dst, data, len, true); -} - -/** - * rpmsg_trysend() - send a message across to the remote processor - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload - * - * This function sends @data of length @len on the @ept channel. - * The message will be sent to the remote processor which the @ept - * channel belongs to, using @ept's source and destination addresses. - * In case there are no TX buffers available, the function will immediately - * return -ENOMEM without waiting until one becomes available. - * - * Returns 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; - 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 - * - * This function sends @data of length @len to the remote @dst address. - * The message will be sent to the remote processor which the @ept - * channel belongs to, using @ept's source address. - * In case there are no TX buffers available, the function will immediately - * return -ENOMEM without waiting until one becomes available. - * - * Returns 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) -{ - 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 - * - * This function sends @data of length @len to the remote @dst address, - * and uses @src as the source address. - * The message will be sent to the remote processor which the @ept - * channel belongs to. - * 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. - */ -static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, - uint32_t src, uint32_t dst, - const void *data, int len) -{ - return rpmsg_send_offchannel_raw(ept, src, dst, data, len, false); -} - -/** - * 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. - */ -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) -{ - strncpy(ept->name, name, sizeof(ept->name)); - ept->addr = src; - ept->dest_addr = dest; - ept->cb = cb; - ept->ns_unbind_cb = ns_unbind_cb; -} - -/** - * rpmsg_create_ept - 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, - * 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. - * - * Rpmsg client should create an endpoint to discuss with remote. rpmsg client - * provide at least a channel name, a callback for message notification and by - * default endpoint source address should be set to RPMSG_ADDR_ANY. - * - * As an option Some rpmsg clients can specify an endpoint with a specific - * source address. - */ - -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 - * - * It unregisters the rpmsg endpoint from the rpmsg device and calls the - * destroy endpoint callback if it is provided. - */ -void rpmsg_destroy_ept(struct rpmsg_endpoint *ept); - -/** - * is_rpmsg_ept_ready - check if the rpmsg endpoint ready to send - * - * @ept: pointer to rpmsg endpoint - * - * Returns 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); -} - -#if defined __cplusplus -} -#endif - -#endif /* _RPMSG_H_ */ +/* + * Remote processor messaging + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * All rights reserved. + * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _RPMSG_H_ +#define _RPMSG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +/* Configurable parameters */ +#define RPMSG_NAME_SIZE (32) +#define RPMSG_ADDR_BMP_SIZE (128) + +#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_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); +typedef void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev, + const char *name, uint32_t dest); + +/** + * @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. + */ +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; +}; + +/** @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 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); +}; + +/** @brief Representation of a RPMsg device */ +struct rpmsg_device { + /** List of endpoints */ + struct metal_list endpoints; + + /** Name service endpoint */ + struct rpmsg_endpoint ns_ept; + + /** 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; +}; + +/** + * @brief Send a message across to the remote processor, + * specifying source and destination address. + * + * 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. + * + * @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 len, + int wait); + +/** + * @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 + * to, using @ept's source and destination addresses. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * @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) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, + len, true); +} + +/** + * @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 + * channel belongs to, using @ept's source address. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * @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); +} + +/** + * @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. + * The message will be sent to the remote processor which the @ept + * channel belongs to. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * @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, + const void *data, int len) +{ + return rpmsg_send_offchannel_raw(ept, src, dst, data, len, true); +} + +/** + * @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 + * channel belongs to, using @ept's source and destination addresses. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * @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) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data, + len, false); +} + +/** + * @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 + * channel belongs to, using @ept's source address. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * @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); +} + +/** + * @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. + * The message will be sent to the remote processor which the @ept + * channel belongs to. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * @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, + const void *data, int len) +{ + return rpmsg_send_offchannel_raw(ept, src, dst, data, len, false); +} + +/** + * @brief Holds the rx buffer for usage outside the receive callback. + * + * Calling this function prevents the RPMsg receive buffer from being released + * back to the pool of shmem buffers. This API can only be called at rx + * callback context (rpmsg_rx_cb_t). With this API, the application doesn't + * need to copy the message in rx callback. Instead, the rx buffer base address + * is saved in application context and further processed in application + * process. After the message is processed, the application can release the rx + * buffer for future reuse in vring by calling the rpmsg_release_rx_buffer() + * function. + * + * @param 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 + */ +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) +{ + if (!ept) + return RPMSG_ERR_PARAM; + + return rpmsg_send_offchannel_nocopy(ept, ept->addr, + ept->dest_addr, data, len); +} + +/** + * @brief Create rpmsg endpoint and register it to rpmsg device + * + * Create a RPMsg endpoint, initialize it with a name, source address, + * remoteproc address, endpoint callback, and destroy endpoint callback, + * and register it to the RPMsg device. + * + * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as + * it binds an rpmsg address with an rx callback handler. + * + * Rpmsg client should create an endpoint to discuss with remote. rpmsg client + * provide at least a channel name, a callback for message notification and by + * default endpoint source address should be set to RPMSG_ADDR_ANY. + * + * As an option Some rpmsg clients can specify an endpoint with a specific + * source address. + * + * @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); + +/** + * @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); + +/** + * @brief Check if the rpmsg endpoint ready to send + * + * @param ept Pointer to rpmsg endpoint + * + * @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 && ept->rdev && ept->dest_addr != RPMSG_ADDR_ANY; +} + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_H_ */ diff --git a/libraries/openamp_arduino/src/openamp/rpmsg_retarget.h b/libraries/openamp_arduino/src/openamp/rpmsg_retarget.h index 0df3a794a..f020f6a79 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 000000000..f9407849e --- /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 ea0a255d5..aea2edf56 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 6802d03fd..d86da7497 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 000000000..9ee78389d --- /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 51a4740f5..9febd1eaf 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 000000000..db678f6b5 --- /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 3f348e3fa..60a9710dc 100755 --- a/libraries/openamp_arduino/src/openamp/virtio_ring.h +++ b/libraries/openamp_arduino/src/openamp/virtio_ring.h @@ -1,152 +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; - uint16_t ring[0]; -}; - -/* uint32_t is used here for ids for padding reasons. */ -struct vring_used_elem { - /* Index of start of used descriptor chain. */ - uint32_t id; - /* Total length of the descriptor chain which was written to. */ - uint32_t len; -}; - -struct vring_used { - uint16_t flags; - uint16_t idx; - struct vring_used_elem ring[0]; -}; - -struct vring { - unsigned int num; - - struct vring_desc *desc; - struct vring_avail *avail; - struct vring_used *used; -}; - -/* The standard layout for the ring is a continuous chunk of memory which - * looks like this. We assume num is a power of 2. - * - * struct vring { - * // The actual descriptors (16 bytes each) - * struct vring_desc desc[num]; - * - * // A ring of available descriptor heads with free-running index. - * __u16 avail_flags; - * __u16 avail_idx; - * __u16 available[num]; - * __u16 used_event_idx; - * - * // Padding to the next align boundary. - * char pad[]; - * - * // A ring of used descriptor heads with free-running index. - * __u16 used_flags; - * __u16 used_idx; - * struct vring_used_elem used[num]; - * __u16 avail_event_idx; - * }; - * - * NOTE: for VirtIO PCI, align is 4096. - */ - -/* - * We publish the used event index at the end of the available ring, and vice - * versa. They are at the end for backwards compatibility. - */ -#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) -#define vring_avail_event(vr) ((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 99d6ff580..1a9d2e8fe 100755 --- a/libraries/openamp_arduino/src/openamp/virtqueue.h +++ b/libraries/openamp_arduino/src/openamp/virtqueue.h @@ -1,238 +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. - */ - - struct vq_desc_extra { - void *cookie; - uint16_t ndescs; - } vq_descx[0]; -}; - -/* 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/remoteproc.c b/libraries/openamp_arduino/src/remoteproc.c new file mode 100644 index 000000000..ad16a2d7e --- /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 82b99c477..7ef1064d8 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 9268889e0..5a9237f47 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 535a83545..6721ecf88 100644 --- a/libraries/openamp_arduino/src/rpmsg_internal.h +++ b/libraries/openamp_arduino/src/rpmsg_internal.h @@ -1,105 +1,116 @@ -/* - * SPDX-License-Identifier: BSD-3-Clause - * - * $FreeBSD$ - */ - -#ifndef _RPMSG_INTERNAL_H_ -#define _RPMSG_INTERNAL_H_ - -#include -#include - -#if defined __cplusplus -extern "C" { -#endif - -#ifdef RPMSG_DEBUG -#define RPMSG_ASSERT(_exp, _msg) do { \ - if (!(_exp)) { \ - openamp_print("FATAL: %s - _msg", __func__); \ - while (1) { \ - ; \ - } \ - } \ - } while (0) -#else -#define RPMSG_ASSERT(_exp, _msg) do { \ - if (!(_exp)) \ - while (1) { \ - ; \ - } \ - } while (0) -#endif - -#define RPMSG_LOCATE_DATA(p) ((unsigned char *)(p) + sizeof(struct rpmsg_hdr)) -/** - * enum rpmsg_ns_flags - dynamic name service announcement flags - * - * @RPMSG_NS_CREATE: a new remote service was just created - * @RPMSG_NS_DESTROY: a known remote service was just destroyed - * @RPMSG_NS_CREATE_WITH_ACK: a new remote service was just created waiting - * acknowledgment. - */ -enum rpmsg_ns_flags { - RPMSG_NS_CREATE = 0, - RPMSG_NS_DESTROY = 1, -}; - -/** - * struct rpmsg_hdr - common header for all rpmsg messages - * @src: source address - * @dst: destination address - * @reserved: reserved for future use - * @len: length of payload (in bytes) - * @flags: message flags - * - * Every message sent(/received) on the rpmsg bus begins with this header. - */ -OPENAMP_PACKED_BEGIN -struct rpmsg_hdr { - uint32_t src; - uint32_t dst; - uint32_t reserved; - uint16_t len; - uint16_t flags; -} OPENAMP_PACKED_END; - -/** - * struct rpmsg_ns_msg - dynamic name service announcement message - * @name: name of remote service that is published - * @addr: address of remote service that is published - * @flags: indicates whether service is created or destroyed - * - * This message is sent across to publish a new service, or announce - * about its removal. When we receive these messages, an appropriate - * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe() - * or ->remove() handler of the appropriate rpmsg driver will be invoked - * (if/as-soon-as one is registered). - */ -OPENAMP_PACKED_BEGIN -struct rpmsg_ns_msg { - char name[RPMSG_NAME_SIZE]; - uint32_t addr; - uint32_t flags; -} OPENAMP_PACKED_END; - -int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags); - -struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rvdev, - const char *name, uint32_t addr, - uint32_t dest_addr); -int rpmsg_register_endpoint(struct rpmsg_device *rdev, - struct rpmsg_endpoint *ept); - -static inline struct rpmsg_endpoint * -rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr) -{ - return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY); -} - -#if defined __cplusplus -} -#endif - -#endif /* _RPMSG_INTERNAL_H_ */ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * $FreeBSD$ + */ + +#ifndef _RPMSG_INTERNAL_H_ +#define _RPMSG_INTERNAL_H_ + +#include +#include + +#if defined __cplusplus +extern "C" { +#endif + +#ifdef RPMSG_DEBUG +#include + +#define RPMSG_ASSERT(_exp, _msg) do { \ + if (!(_exp)) { \ + metal_log(METAL_LOG_EMERGENCY, \ + "FATAL: %s - "_msg, __func__); \ + metal_assert(_exp); \ + } \ + } while (0) +#else +#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 + * + * @RPMSG_NS_CREATE: a new remote service was just created + * @RPMSG_NS_DESTROY: a known remote service was just destroyed + * @RPMSG_NS_CREATE_WITH_ACK: a new remote service was just created waiting + * acknowledgment. + */ +enum rpmsg_ns_flags { + RPMSG_NS_CREATE = 0, + RPMSG_NS_DESTROY = 1, +}; + +/** + * @brief Common header for all RPMsg messages + * + * Every message sent(/received) on the RPMsg bus begins with this header. + */ +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; +} METAL_PACKED_END; + +/** + * @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 + * (if/as-soon-as one is registered). + */ +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; +} 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); +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) +{ + return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY); +} + +#if defined __cplusplus +} +#endif + +#endif /* _RPMSG_INTERNAL_H_ */ diff --git a/libraries/openamp_arduino/src/rpmsg_virtio.c b/libraries/openamp_arduino/src/rpmsg_virtio.c index 207edc3ed..ea4cc0d9e 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_parser.c b/libraries/openamp_arduino/src/rsc_table_parser.c new file mode 100644 index 000000000..c099f840b --- /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/virtio.c b/libraries/openamp_arduino/src/virtio.c index 5cf87222b..794212a23 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 000000000..5f42180a6 --- /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 e90a6940b..2544ee360 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*/ From 3e5f4784d02f3a2dc34ff978b9cafe931fffa530 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 27 Dec 2023 09:01:48 +0100 Subject: [PATCH 2/3] libraries/openamp_arduino: Update libmetal to version v2023.10.0 - 1.5.0. Signed-off-by: iabdalkader --- libraries/openamp_arduino/src/device.c | 21 +- libraries/openamp_arduino/src/dma.c | 56 ++ .../openamp_arduino/src/generic_device.c | 2 +- libraries/openamp_arduino/src/generic_io.c | 4 +- libraries/openamp_arduino/src/init.c | 7 + libraries/openamp_arduino/src/io.c | 16 +- libraries/openamp_arduino/src/irq.c | 325 +++----- libraries/openamp_arduino/src/log.c | 6 +- libraries/openamp_arduino/src/metal/alloc.h | 99 +-- libraries/openamp_arduino/src/metal/assert.h | 50 +- libraries/openamp_arduino/src/metal/atomic.h | 145 +++- libraries/openamp_arduino/src/metal/cache.h | 114 +-- .../openamp_arduino/src/metal/compiler.h | 50 +- .../openamp_arduino/src/metal/condition.h | 147 ++-- libraries/openamp_arduino/src/metal/config.h | 4 +- libraries/openamp_arduino/src/metal/cpu.h | 34 +- libraries/openamp_arduino/src/metal/device.h | 353 ++++----- libraries/openamp_arduino/src/metal/dma.h | 159 ++-- libraries/openamp_arduino/src/metal/errno.h | 47 +- libraries/openamp_arduino/src/metal/io.h | 728 +++++++++--------- libraries/openamp_arduino/src/metal/irq.h | 220 +++--- .../src/metal/irq_controller.h | 134 ++++ libraries/openamp_arduino/src/metal/list.h | 220 +++--- libraries/openamp_arduino/src/metal/log.h | 209 ++--- libraries/openamp_arduino/src/metal/mutex.h | 175 ++--- .../src/metal/processor/arm/atomic.h | 30 +- .../src/metal/processor/arm/cpu.h | 34 +- libraries/openamp_arduino/src/metal/shmem.h | 167 ++-- libraries/openamp_arduino/src/metal/sleep.h | 89 +-- libraries/openamp_arduino/src/metal/softirq.h | 69 ++ .../openamp_arduino/src/metal/spinlock.h | 141 ++-- libraries/openamp_arduino/src/metal/sys.h | 300 ++++---- .../src/metal/system/generic/alloc.h | 4 +- .../src/metal/system/generic/cortexm/sys.h | 65 -- .../src/metal/system/generic/sys.h | 2 - libraries/openamp_arduino/src/metal/time.h | 83 +- .../openamp_arduino/src/metal/utilities.h | 317 ++++---- libraries/openamp_arduino/src/metal/version.h | 153 ++-- libraries/openamp_arduino/src/shmem.c | 10 +- libraries/openamp_arduino/src/softirq.c | 101 +++ libraries/openamp_arduino/src/version.c | 27 + 41 files changed, 2630 insertions(+), 2287 deletions(-) create mode 100644 libraries/openamp_arduino/src/dma.c create mode 100644 libraries/openamp_arduino/src/metal/irq_controller.h create mode 100644 libraries/openamp_arduino/src/metal/softirq.h delete mode 100755 libraries/openamp_arduino/src/metal/system/generic/cortexm/sys.h create mode 100644 libraries/openamp_arduino/src/softirq.c create mode 100644 libraries/openamp_arduino/src/version.c diff --git a/libraries/openamp_arduino/src/device.c b/libraries/openamp_arduino/src/device.c index a3bc12caf..45e08eccd 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 000000000..7edaa549c --- /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/generic_device.c b/libraries/openamp_arduino/src/generic_device.c index d01fd3cd7..ec6e53834 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 670f239d5..966bfc561 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 315217741..5a6a0063d 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 fccf1100e..7faf40502 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 e61bc7e83..c8578fa3c 100644 --- a/libraries/openamp_arduino/src/irq.c +++ b/libraries/openamp_arduino/src/irq.c @@ -1,279 +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); -static struct metal_irqs_state _irqs = { - .irqs = METAL_INIT_LIST(_irqs.irqs), - .irq_lock = METAL_MUTEX_INIT(_irqs.irq_lock), -}; - -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 719fbd82b..22c8b9bd5 100644 --- a/libraries/openamp_arduino/src/log.c +++ b/libraries/openamp_arduino/src/log.c @@ -10,15 +10,13 @@ #include #include -#define DEFAULT_LOGGER_ON - void metal_default_log_handler(enum metal_log_level level, const char *format, ...) { #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: ", @@ -36,7 +34,7 @@ void metal_default_log_handler(enum metal_log_level level, if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG) level = METAL_LOG_EMERGENCY; - printf("%s%s", level_strs[level], msg); + fprintf(stderr, "%s%s", level_strs[level], msg); #else (void)level; (void)format; diff --git a/libraries/openamp_arduino/src/metal/alloc.h b/libraries/openamp_arduino/src/metal/alloc.h index b82a09af1..02f860b12 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 8357fdf5b..4476b641a 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 14f771eb8..ce8595dbf 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 54a015594..02917b411 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 ec4c67517..08c20943d 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/condition.h b/libraries/openamp_arduino/src/metal/condition.h index 953293680..b5c7b2dbe 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 ce08057fc..3de906067 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 5537afba4..26dbaa2af 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 c78b50dd1..fab1c147d 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 1c8e8b11c..9bb7e54c8 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 2f200e8b7..e84a2bc7d 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 95512d826..e534d1765 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 9f0344e7f..43562abe1 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 000000000..c821ef48c --- /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 a9395ba77..eb0e7b339 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 d439ef8f4..528e4c6b0 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 c241bd0db..71d9eaa21 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 c5e25cdfb..ab5ee4060 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 3e4f8483b..0ea96102a 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 19f282caf..561a2c85d 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 0dad40129..b366ee5b1 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 000000000..52ea00f18 --- /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 f6a711eb7..6992267e6 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 12f7f6995..24822ca14 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 5338dd7de..6dc767fa1 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 35597d616..000000000 --- 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 f5a236852..0a19b2362 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 b05e6794a..bc24e6134 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 95a6670a9..6b592e017 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 96666b3aa..32be7ae69 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/shmem.c b/libraries/openamp_arduino/src/shmem.c index 5ead8e755..0ded4ec4a 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 000000000..4ba745fa1 --- /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 000000000..bc23ee480 --- /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; +} From f85307f4fbc221bcda31fef46c8015653ace1bec Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 29 Dec 2023 09:54:50 +0100 Subject: [PATCH 3/3] variants: Update definitions for boards that use Open-AMP. - Update deprecated Open-AMP definitions. - Update RPMSG buffer size to match the default configuration. Signed-off-by: iabdalkader --- variants/GENERIC_STM32H747_M4/conf/mbed_app.json | 4 ++-- variants/GENERIC_STM32H747_M4/defines.txt | 2 +- variants/GIGA/conf/mbed_app.json | 4 ++-- variants/GIGA/defines.txt | 4 ++-- variants/NICLA_VISION/conf/mbed_app.json | 2 +- variants/NICLA_VISION/defines.txt | 4 ++-- variants/OPTA/conf/mbed_app.json | 4 ++-- variants/OPTA/defines.txt | 4 ++-- variants/PORTENTA_H7_M7/conf/mbed_app.json | 2 +- variants/PORTENTA_H7_M7/defines.txt | 2 +- variants/PORTENTA_X8/conf/mbed_app.json | 4 ++-- variants/PORTENTA_X8/defines.txt | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/variants/GENERIC_STM32H747_M4/conf/mbed_app.json b/variants/GENERIC_STM32H747_M4/conf/mbed_app.json index 16b28e07a..0f4e6b6a8 100644 --- a/variants/GENERIC_STM32H747_M4/conf/mbed_app.json +++ b/variants/GENERIC_STM32H747_M4/conf/mbed_app.json @@ -19,11 +19,11 @@ "BT_UART_NO_3M_SUPPORT", "NO_VTOR_RELOCATE", "METAL_INTERNAL", - "VIRTIO_SLAVE_ONLY", + "VIRTIO_DEVICE_ONLY", "NO_ATOMIC_64_SUPPORT", "METAL_MAX_DEVICE_REGIONS=2", "RPMSG_BUFFER_SIZE=2048" ] } } -} \ No newline at end of file +} diff --git a/variants/GENERIC_STM32H747_M4/defines.txt b/variants/GENERIC_STM32H747_M4/defines.txt index fcae69fb1..0b8e7d85a 100644 --- a/variants/GENERIC_STM32H747_M4/defines.txt +++ b/variants/GENERIC_STM32H747_M4/defines.txt @@ -77,7 +77,7 @@ -DTRANSACTION_QUEUE_SIZE_SPI=2 -DUSE_FULL_LL_DRIVER -DUSE_HAL_DRIVER --DVIRTIO_SLAVE_ONLY +-DVIRTIO_DEVICE_ONLY -DMBED_NO_GLOBAL_USING_DIRECTIVE=1 -DCORE_MAJOR= -DCORE_MINOR= diff --git a/variants/GIGA/conf/mbed_app.json b/variants/GIGA/conf/mbed_app.json index 603807837..18b610287 100644 --- a/variants/GIGA/conf/mbed_app.json +++ b/variants/GIGA/conf/mbed_app.json @@ -13,10 +13,10 @@ "target.mbed_app_start": "0x8040000", "target.macros_add": [ "METAL_INTERNAL", - "VIRTIO_MASTER_ONLY", + "VIRTIO_DRIVER_ONLY", "NO_ATOMIC_64_SUPPORT", "METAL_MAX_DEVICE_REGIONS=2", - "RPMSG_BUFFER_SIZE=100" + "RPMSG_BUFFER_SIZE=2048" ] } } diff --git a/variants/GIGA/defines.txt b/variants/GIGA/defines.txt index 75e5cc434..1cb7a6441 100644 --- a/variants/GIGA/defines.txt +++ b/variants/GIGA/defines.txt @@ -53,7 +53,7 @@ -DMETAL_MAX_DEVICE_REGIONS=2 -DNO_ATOMIC_64_SUPPORT -DQSPI_NO_SAMPLE_SHIFT --DRPMSG_BUFFER_SIZE=100 +-DRPMSG_BUFFER_SIZE=2048 -DSTM32H747xx -DTARGET_CORDIO -DTARGET_CORTEX @@ -78,7 +78,7 @@ -DTRANSACTION_QUEUE_SIZE_SPI=2 -DUSE_FULL_LL_DRIVER -DUSE_HAL_DRIVER --DVIRTIO_MASTER_ONLY +-DVIRTIO_DRIVER_ONLY -DMBED_NO_GLOBAL_USING_DIRECTIVE=1 -DCORE_MAJOR= -DCORE_MINOR= diff --git a/variants/NICLA_VISION/conf/mbed_app.json b/variants/NICLA_VISION/conf/mbed_app.json index 405307426..553ab954e 100644 --- a/variants/NICLA_VISION/conf/mbed_app.json +++ b/variants/NICLA_VISION/conf/mbed_app.json @@ -14,7 +14,7 @@ "target.mbed_app_start": "0x8040000", "target.macros_add": [ "METAL_INTERNAL", - "VIRTIO_MASTER_ONLY", + "VIRTIO_DRIVER_ONLY", "NO_ATOMIC_64_SUPPORT", "METAL_MAX_DEVICE_REGIONS=2", "RPMSG_BUFFER_SIZE=100" diff --git a/variants/NICLA_VISION/defines.txt b/variants/NICLA_VISION/defines.txt index e3bbb651f..eaea43f31 100644 --- a/variants/NICLA_VISION/defines.txt +++ b/variants/NICLA_VISION/defines.txt @@ -54,7 +54,7 @@ -DMETAL_MAX_DEVICE_REGIONS=2 -DNO_ATOMIC_64_SUPPORT -DQSPI_NO_SAMPLE_SHIFT --DRPMSG_BUFFER_SIZE=100 +-DRPMSG_BUFFER_SIZE=2048 -DSTM32H747xx -DT1oI2C -DT1oI2C_UM11225 @@ -81,7 +81,7 @@ -DTRANSACTION_QUEUE_SIZE_SPI=2 -DUSE_FULL_LL_DRIVER -DUSE_HAL_DRIVER --DVIRTIO_MASTER_ONLY +-DVIRTIO_DRIVER_ONLY -DMBED_NO_GLOBAL_USING_DIRECTIVE=1 -DCORE_MAJOR= -DCORE_MINOR= diff --git a/variants/OPTA/conf/mbed_app.json b/variants/OPTA/conf/mbed_app.json index 603807837..18b610287 100644 --- a/variants/OPTA/conf/mbed_app.json +++ b/variants/OPTA/conf/mbed_app.json @@ -13,10 +13,10 @@ "target.mbed_app_start": "0x8040000", "target.macros_add": [ "METAL_INTERNAL", - "VIRTIO_MASTER_ONLY", + "VIRTIO_DRIVER_ONLY", "NO_ATOMIC_64_SUPPORT", "METAL_MAX_DEVICE_REGIONS=2", - "RPMSG_BUFFER_SIZE=100" + "RPMSG_BUFFER_SIZE=2048" ] } } diff --git a/variants/OPTA/defines.txt b/variants/OPTA/defines.txt index 2b5a37cea..fb131c3fe 100644 --- a/variants/OPTA/defines.txt +++ b/variants/OPTA/defines.txt @@ -53,7 +53,7 @@ -DMETAL_MAX_DEVICE_REGIONS=2 -DNO_ATOMIC_64_SUPPORT -DQSPI_NO_SAMPLE_SHIFT --DRPMSG_BUFFER_SIZE=100 +-DRPMSG_BUFFER_SIZE=2048 -DSTM32H747xx -DTARGET_CORDIO -DTARGET_CORTEX @@ -78,7 +78,7 @@ -DTRANSACTION_QUEUE_SIZE_SPI=2 -DUSE_FULL_LL_DRIVER -DUSE_HAL_DRIVER --DVIRTIO_MASTER_ONLY +-DVIRTIO_DRIVER_ONLY -DMBED_NO_GLOBAL_USING_DIRECTIVE=1 -DCORE_MAJOR= -DCORE_MINOR= diff --git a/variants/PORTENTA_H7_M7/conf/mbed_app.json b/variants/PORTENTA_H7_M7/conf/mbed_app.json index 5ac9c9bb7..4bae63635 100644 --- a/variants/PORTENTA_H7_M7/conf/mbed_app.json +++ b/variants/PORTENTA_H7_M7/conf/mbed_app.json @@ -19,7 +19,7 @@ "BT_UART_NO_3M_SUPPORT", "USB_DYNAMIC_CONFIGURATION", "METAL_INTERNAL", - "VIRTIO_MASTER_ONLY", + "VIRTIO_DRIVER_ONLY", "NO_ATOMIC_64_SUPPORT", "METAL_MAX_DEVICE_REGIONS=2", "RPMSG_BUFFER_SIZE=2048", diff --git a/variants/PORTENTA_H7_M7/defines.txt b/variants/PORTENTA_H7_M7/defines.txt index b26b4d44f..2f2a91609 100644 --- a/variants/PORTENTA_H7_M7/defines.txt +++ b/variants/PORTENTA_H7_M7/defines.txt @@ -81,7 +81,7 @@ -DUSB_DYNAMIC_CONFIGURATION -DUSE_FULL_LL_DRIVER -DUSE_HAL_DRIVER --DVIRTIO_MASTER_ONLY +-DVIRTIO_DRIVER_ONLY -DMBED_NO_GLOBAL_USING_DIRECTIVE=1 -DCORE_MAJOR= -DCORE_MINOR= diff --git a/variants/PORTENTA_X8/conf/mbed_app.json b/variants/PORTENTA_X8/conf/mbed_app.json index 08b653062..cf1ab3cff 100644 --- a/variants/PORTENTA_X8/conf/mbed_app.json +++ b/variants/PORTENTA_X8/conf/mbed_app.json @@ -13,11 +13,11 @@ "target.macros_add": [ "NO_VTOR_RELOCATE", "METAL_INTERNAL", - "VIRTIO_SLAVE_ONLY", + "VIRTIO_DEVICE_ONLY", "NO_ATOMIC_64_SUPPORT", "METAL_MAX_DEVICE_REGIONS=2", "RPMSG_BUFFER_SIZE=2048" ] } } -} \ No newline at end of file +} diff --git a/variants/PORTENTA_X8/defines.txt b/variants/PORTENTA_X8/defines.txt index e9e1d9258..049ba9c17 100644 --- a/variants/PORTENTA_X8/defines.txt +++ b/variants/PORTENTA_X8/defines.txt @@ -68,7 +68,7 @@ -DTRANSACTION_QUEUE_SIZE_SPI=2 -DUSE_FULL_LL_DRIVER -DUSE_HAL_DRIVER --DVIRTIO_SLAVE_ONLY +-DVIRTIO_DEVICE_ONLY -DMBED_NO_GLOBAL_USING_DIRECTIVE=1 -DCORE_MAJOR= -DCORE_MINOR= pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy