From 11cedc6c49b721d8a792d3cd80e1db50f66830c4 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 7 Mar 2019 13:18:51 -0600 Subject: [PATCH] ext: libmetal: Update libmetal to snapshot for bug fixes Pull in libmetal SHA 59a10acbb0bb684c1a75488f11878cb984170c81 to get some build fixes related to newlib. Signed-off-by: Kumar Gala --- CODEOWNERS | 1 + ext/hal/libmetal/libmetal/.travis.yml | 17 +- ext/hal/libmetal/libmetal/lib/CMakeLists.txt | 6 +- ext/hal/libmetal/libmetal/lib/atomic.h | 3 + .../libmetal/lib/compiler/gcc/compiler.h | 3 + .../libmetal/lib/compiler/iar/compiler.h | 3 + ext/hal/libmetal/libmetal/lib/io.c | 12 +- ext/hal/libmetal/libmetal/lib/io.h | 45 ++- ext/hal/libmetal/libmetal/lib/irq.c | 138 +++++++ ext/hal/libmetal/libmetal/lib/irq.h | 51 +-- .../libmetal/libmetal/lib/irq_controller.h | 131 +++++++ .../lib/processor/ceva/CMakeLists.txt | 3 + .../libmetal/lib/processor/ceva/cpu.h | 25 ++ .../lib/processor/csky/CMakeLists.txt | 3 + .../libmetal/lib/processor/csky/cpu.h | 17 + .../lib/processor/riscv/CMakeLists.txt | 3 + .../libmetal/lib/processor/riscv/cpu.h | 17 + ext/hal/libmetal/libmetal/lib/softirq.c | 101 +++++ ext/hal/libmetal/libmetal/lib/softirq.h | 68 ++++ ext/hal/libmetal/libmetal/lib/spinlock.h | 6 +- .../libmetal/lib/system/freertos/irq.c | 249 ------------- .../libmetal/lib/system/freertos/irq.h | 15 - .../freertos/xlnx_common/CMakeLists.txt | 5 + .../lib/system/freertos/xlnx_common/irq.c | 72 ++++ .../lib/system/freertos/xlnx_common/sys.h | 47 +++ .../lib/system/freertos/zynq7/CMakeLists.txt | 1 + .../libmetal/lib/system/freertos/zynq7/sys.h | 3 + .../system/freertos/zynqmp_a53/CMakeLists.txt | 1 + .../lib/system/freertos/zynqmp_a53/sys.h | 3 + .../system/freertos/zynqmp_r5/CMakeLists.txt | 1 + .../lib/system/freertos/zynqmp_r5/sys.h | 3 + .../libmetal/lib/system/generic/condition.c | 6 +- .../libmetal/lib/system/generic/condition.h | 14 +- .../libmetal/lib/system/generic/irq.c | 249 ------------- .../libmetal/lib/system/generic/irq.h | 15 - .../generic/microblaze_generic/CMakeLists.txt | 1 + .../system/generic/microblaze_generic/sys.c | 26 +- .../system/generic/microblaze_generic/sys.h | 6 + .../system/generic/xlnx_common/CMakeLists.txt | 5 + .../lib/system/generic/xlnx_common/irq.c | 72 ++++ .../lib/system/generic/xlnx_common/sys.h | 47 +++ .../lib/system/generic/zynq7/CMakeLists.txt | 1 + .../libmetal/lib/system/generic/zynq7/sys.h | 3 + .../system/generic/zynqmp_a53/CMakeLists.txt | 1 + .../lib/system/generic/zynqmp_a53/sys.h | 3 + .../system/generic/zynqmp_r5/CMakeLists.txt | 1 + .../lib/system/generic/zynqmp_r5/sys.h | 5 +- .../libmetal/lib/system/linux/condition.c | 6 +- .../libmetal/lib/system/linux/condition.h | 15 +- .../libmetal/lib/system/linux/device.c | 34 +- .../libmetal/libmetal/lib/system/linux/irq.c | 346 ++++++------------ .../libmetal/libmetal/lib/system/linux/irq.h | 16 + .../libmetal/lib/system/linux/shmem.c | 7 +- .../libmetal/lib/system/nuttx/CMakeLists.txt | 20 + .../libmetal/lib/system/nuttx/alloc.h | 39 ++ .../libmetal/lib/system/nuttx/assert.h | 27 ++ .../libmetal/lib/system/nuttx/cache.h | 39 ++ .../libmetal/lib/system/nuttx/condition.c | 32 ++ .../libmetal/lib/system/nuttx/condition.h | 51 +++ .../libmetal/lib/system/nuttx/device.c | 17 + .../libmetal/libmetal/lib/system/nuttx/init.c | 29 ++ .../libmetal/libmetal/lib/system/nuttx/io.c | 116 ++++++ .../libmetal/libmetal/lib/system/nuttx/io.h | 49 +++ .../libmetal/libmetal/lib/system/nuttx/irq.c | 87 +++++ .../libmetal/libmetal/lib/system/nuttx/irq.h | 29 ++ .../libmetal/libmetal/lib/system/nuttx/log.h | 29 ++ .../libmetal/lib/system/nuttx/mutex.h | 72 ++++ .../libmetal/lib/system/nuttx/shmem.c | 18 + .../libmetal/lib/system/nuttx/sleep.h | 36 ++ .../libmetal/libmetal/lib/system/nuttx/sys.h | 40 ++ .../libmetal/libmetal/lib/system/nuttx/time.c | 27 ++ .../libmetal/lib/system/zephyr/condition.c | 10 +- .../libmetal/lib/system/zephyr/condition.h | 14 +- .../libmetal/libmetal/lib/system/zephyr/irq.c | 250 ------------- .../libmetal/libmetal/lib/system/zephyr/irq.h | 7 - .../libmetal/lib/system/zephyr/time.c | 4 +- ext/hal/libmetal/libmetal/lib/utilities.h | 11 +- 77 files changed, 1845 insertions(+), 1140 deletions(-) create mode 100644 ext/hal/libmetal/libmetal/lib/irq.c create mode 100644 ext/hal/libmetal/libmetal/lib/irq_controller.h create mode 100644 ext/hal/libmetal/libmetal/lib/processor/ceva/CMakeLists.txt create mode 100644 ext/hal/libmetal/libmetal/lib/processor/ceva/cpu.h create mode 100644 ext/hal/libmetal/libmetal/lib/processor/csky/CMakeLists.txt create mode 100644 ext/hal/libmetal/libmetal/lib/processor/csky/cpu.h create mode 100644 ext/hal/libmetal/libmetal/lib/processor/riscv/CMakeLists.txt create mode 100644 ext/hal/libmetal/libmetal/lib/processor/riscv/cpu.h create mode 100644 ext/hal/libmetal/libmetal/lib/softirq.c create mode 100644 ext/hal/libmetal/libmetal/lib/softirq.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/CMakeLists.txt create mode 100644 ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/irq.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/sys.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/CMakeLists.txt create mode 100644 ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/irq.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/sys.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/CMakeLists.txt create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/alloc.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/assert.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/cache.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/condition.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/condition.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/device.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/init.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/io.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/io.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/irq.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/irq.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/log.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/mutex.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/shmem.c create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/sleep.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/sys.h create mode 100644 ext/hal/libmetal/libmetal/lib/system/nuttx/time.c diff --git a/CODEOWNERS b/CODEOWNERS index cd88dca82f..09bc4e4818 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -140,6 +140,7 @@ /dts/bindings/*/nxp* @MaureenHelm /ext/fs/ @nashif @ramakrishnapallala /ext/hal/cmsis/ @MaureenHelm @galak +/ext/hal/libmetal/ @galak /ext/hal/nordic/ @carlescufi @anangl /ext/hal/nxp/ @MaureenHelm /ext/hal/qmsi/ @nashif diff --git a/ext/hal/libmetal/libmetal/.travis.yml b/ext/hal/libmetal/libmetal/.travis.yml index ace1010acf..4bfe8188ea 100644 --- a/ext/hal/libmetal/libmetal/.travis.yml +++ b/ext/hal/libmetal/libmetal/.travis.yml @@ -11,12 +11,14 @@ env: - ZEPHYR_TOOLCHAIN_VARIANT=zephyr - ZEPHYR_SDK_INSTALL_DIR=/opt/zephyr-sdk - ZEPHYR_BASE=$TRAVIS_BUILD_DIR/deps/zephyr - - ZEPHYR_SDK_VERSION=0.9.3 + - ZEPHYR_SDK_VERSION=0.9.5 - ZEPHYR_SDK_DOWNLOAD_FOLDER=https://github.com/zephyrproject-rtos/meta-zephyr-sdk/releases/download/$ZEPHYR_SDK_VERSION - ZEPHYR_SDK_SETUP_BINARY=zephyr-sdk-$ZEPHYR_SDK_VERSION-setup.run - ZEPHYR_SDK_DOWNLOAD_URL=$ZEPHYR_SDK_DOWNLOAD_FOLDER/$ZEPHYR_SDK_SETUP_BINARY - FREERTOS_ZIP_URL=https://cfhcable.dl.sourceforge.net/project/freertos/FreeRTOS/V10.0.1/FreeRTOSv10.0.1.zip - GCC_ARM_COMPILER_PACKAGE=gcc-arm-embedded_7-2018q2-1~trusty1_amd64.deb + - CC=gcc-4.9 + - CXX=g++-4.9 matrix: fast_finish: true @@ -34,8 +36,16 @@ cache: directories: - $ZEPHYR_SDK_INSTALL_DIR - /usr/local/bin + - $HOME/bin/cmake before_install: + - if [ ! -f $HOME/bin/cmake/cmake-3.13.1-Linux-x86_64/bin/cmake ]; then + mkdir -p $HOME/bin/cmake && cd $HOME/bin/cmake && + wget https://github.com/Kitware/CMake/releases/download/v3.13.1/cmake-3.13.1-Linux-x86_64.sh && + yes | sh cmake-3.13.1-Linux-x86_64.sh | cat && + cd -; + fi && + export PATH=$HOME/bin/cmake/cmake-3.13.1-Linux-x86_64/bin:$PATH - if [[ "$TARGET" == "zephyr" ]]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test && sudo apt-get update -qq && @@ -43,8 +53,9 @@ before_install: sudo pip3 install pyelftools; fi - if [[ "$TARGET" == "linux" ]]; then + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test && sudo apt-get update -qq && - sudo apt-get install libsysfs-dev libhugetlbfs-dev make gcc; + sudo apt-get install libsysfs-dev libhugetlbfs-dev make gcc-4.9; fi # This is to kick start CI on generic platform. Will need to have a proper way to get the required packages - if [[ "$TARGET" == "generic" || "$TARGET" == "freertos" ]]; then @@ -77,7 +88,7 @@ script: - if [[ "$TARGET" == "zephyr" ]]; then mkdir -p ../libmetal/build-zephyr && cd ../libmetal/build-zephyr && - cmake .. -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 -DWITH_TESTS=on && + cmake .. -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 && make VERBOSE=1; fi - if [[ "$TARGET" == "linux" ]]; then diff --git a/ext/hal/libmetal/libmetal/lib/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/CMakeLists.txt index 1a3355de5a..a139eb8bb8 100644 --- a/ext/hal/libmetal/libmetal/lib/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/CMakeLists.txt @@ -16,11 +16,13 @@ collect (PROJECT_LIB_HEADERS device.h) collect (PROJECT_LIB_HEADERS dma.h) collect (PROJECT_LIB_HEADERS io.h) collect (PROJECT_LIB_HEADERS irq.h) +collect (PROJECT_LIB_HEADERS irq_controller.h) collect (PROJECT_LIB_HEADERS list.h) collect (PROJECT_LIB_HEADERS log.h) collect (PROJECT_LIB_HEADERS mutex.h) collect (PROJECT_LIB_HEADERS shmem.h) collect (PROJECT_LIB_HEADERS sleep.h) +collect (PROJECT_LIB_HEADERS softirq.h) collect (PROJECT_LIB_HEADERS spinlock.h) collect (PROJECT_LIB_HEADERS sys.h) collect (PROJECT_LIB_HEADERS time.h) @@ -31,8 +33,10 @@ collect (PROJECT_LIB_SOURCES dma.c) collect (PROJECT_LIB_SOURCES device.c) collect (PROJECT_LIB_SOURCES init.c) collect (PROJECT_LIB_SOURCES io.c) +collect (PROJECT_LIB_SOURCES irq.c) collect (PROJECT_LIB_SOURCES log.c) collect (PROJECT_LIB_SOURCES shmem.c) +collect (PROJECT_LIB_SOURCES softirq.c) collect (PROJECT_LIB_SOURCES version.c) add_subdirectory (compiler) @@ -62,7 +66,7 @@ endif (WITH_DEFAULT_LOGGER) if (WITH_ZEPHYR) zephyr_library_named(metal) - add_dependencies(metal ${OFFSETS_H_TARGET}) + add_dependencies(metal offsets_h) zephyr_library_sources(${_sources}) zephyr_include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) else (WITH_ZEPHYR) diff --git a/ext/hal/libmetal/libmetal/lib/atomic.h b/ext/hal/libmetal/libmetal/lib/atomic.h index 39d21d4f8e..29a7f9e66a 100644 --- a/ext/hal/libmetal/libmetal/lib/atomic.h +++ b/ext/hal/libmetal/libmetal/lib/atomic.h @@ -16,7 +16,10 @@ #if defined(HAVE_STDATOMIC_H) && !defined(__STDC_NO_ATOMICS__) && \ !defined(__cplusplus) +# include # include +#elif defined(__cplusplus) +# include #elif defined(__GNUC__) # include #else diff --git a/ext/hal/libmetal/libmetal/lib/compiler/gcc/compiler.h b/ext/hal/libmetal/libmetal/lib/compiler/gcc/compiler.h index fe6a11552f..76fdfcd9e4 100644 --- a/ext/hal/libmetal/libmetal/lib/compiler/gcc/compiler.h +++ b/ext/hal/libmetal/libmetal/lib/compiler/gcc/compiler.h @@ -20,6 +20,9 @@ extern "C" { #define metal_align(n) __attribute__((aligned(n))) #define metal_weak __attribute__((weak)) +#define METAL_PACKED_BEGIN +#define METAL_PACKED_END __attribute__((__packed__)) + #ifdef __cplusplus } #endif diff --git a/ext/hal/libmetal/libmetal/lib/compiler/iar/compiler.h b/ext/hal/libmetal/libmetal/lib/compiler/iar/compiler.h index 618ba2cc16..1a790d8748 100644 --- a/ext/hal/libmetal/libmetal/lib/compiler/iar/compiler.h +++ b/ext/hal/libmetal/libmetal/lib/compiler/iar/compiler.h @@ -20,6 +20,9 @@ extern "C" { #define metal_align(n) __attribute__((aligned(n))) #define metal_weak __attribute__((weak)) +#define METAL_PACKED_BEGIN __packed +#define METAL_PACKED_END + #ifdef __cplusplus } #endif diff --git a/ext/hal/libmetal/libmetal/lib/io.c b/ext/hal/libmetal/libmetal/lib/io.c index 218cfe7f72..d4f2fb5fac 100644 --- a/ext/hal/libmetal/libmetal/lib/io.c +++ b/ext/hal/libmetal/libmetal/lib/io.c @@ -14,7 +14,9 @@ void metal_io_init(struct metal_io_region *io, void *virt, unsigned 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 (offset >= io->size) 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 (offset >= io->size) 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 (offset >= io->size) 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/ext/hal/libmetal/libmetal/lib/io.h b/ext/hal/libmetal/libmetal/lib/io.h index dfd9a4f197..24e318f87d 100644 --- a/ext/hal/libmetal/libmetal/lib/io.h +++ b/ext/hal/libmetal/libmetal/lib/io.h @@ -62,6 +62,11 @@ struct metal_io_ops { 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. */ @@ -126,7 +131,7 @@ static inline size_t metal_io_region_size(struct metal_io_region *io) static inline void * metal_io_virt(struct metal_io_region *io, unsigned long offset) { - return (io->virt != METAL_BAD_VA && offset <= io->size + return (io->virt != METAL_BAD_VA && offset < io->size ? (uint8_t *)io->virt + offset : NULL); } @@ -154,12 +159,16 @@ metal_io_virt_to_offset(struct metal_io_region *io, void *virt) 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); + if (!io->ops.offset_to_phys) { + 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); + } + + return io->ops.offset_to_phys(io, offset); } /** @@ -171,15 +180,19 @@ metal_io_phys(struct metal_io_region *io, unsigned long 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; + 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); } /** diff --git a/ext/hal/libmetal/libmetal/lib/irq.c b/ext/hal/libmetal/libmetal/lib/irq.c new file mode 100644 index 0000000000..4745985ccb --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/irq.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +/** List of registered IRQ controller */ +static METAL_DECLARE_LIST(irq_cntrs); + +static int metal_irq_allocate(int irq_base, int irq_num) +{ + struct metal_list *node; + struct metal_irq_controller *cntr; + int irq_tocheck = irq_base, irq_end_tocheck; + + if (irq_num == 0) { + return METAL_IRQ_ANY; + } + if (irq_tocheck == METAL_IRQ_ANY) { + irq_tocheck = 0; + } + 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_tocheck = cntr_irq_end; + irq_end_tocheck = irq_tocheck + irq_num; + } + } + return irq_tocheck; +} + +int metal_irq_register_controller(struct metal_irq_controller *cntr) +{ + int irq_base; + struct metal_list *node; + + if (cntr == NULL) { + return -EINVAL; + } + metal_list_for_each(&irq_cntrs, node) { + if (node == &cntr->node) { + return 0; + } + } + + /* 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_list_add_tail(&irq_cntrs, &cntr->node); + return 0; +} + +static struct metal_irq_controller *metal_irq_get_controller(int irq) +{ + 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; +} + +static void _metal_irq_set_enable(int irq, unsigned int state) +{ + struct metal_irq_controller *cntr; + + cntr = metal_irq_get_controller(irq); + if (cntr == NULL) { + return; + } + cntr->irq_set_enable(cntr, irq, state); +} + +int metal_irq_register(int irq, + metal_irq_handler irq_handler, + void *arg) +{ + 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_enable(unsigned int vector) +{ + _metal_irq_set_enable((int)vector, METAL_IRQ_ENABLE); +} + +void metal_irq_disable(unsigned int vector) +{ + _metal_irq_set_enable((int)vector, METAL_IRQ_DISABLE); +} diff --git a/ext/hal/libmetal/libmetal/lib/irq.h b/ext/hal/libmetal/libmetal/lib/irq.h index ce34c6c318..dbc7775414 100644 --- a/ext/hal/libmetal/libmetal/lib/irq.h +++ b/ext/hal/libmetal/libmetal/lib/irq.h @@ -19,6 +19,7 @@ extern "C" { /** \defgroup irq Interrupt Handling Interfaces * @{ */ +#include #include /** IRQ handled status */ @@ -27,53 +28,39 @@ extern "C" { /** * @brief type of interrupt handler - * @param[in] irq interrupt id - * @param[in] priv private data - * @return irq handled status + * @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 *priv); - -struct metal_device; +typedef int (*metal_irq_handler) (int irq, void *arg); /** - * @brief Register interrupt handler for driver ID/device. + * @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] 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. + * @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, - struct metal_device *dev, - void *drv_id); + void *arg); /** - * @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 + * @brief Unregister interrupt handler for interrupt. * * @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); +static inline +void metal_irq_unregister(int irq) +{ + metal_irq_register(irq, 0, NULL); +} /** * @brief disable interrupts diff --git a/ext/hal/libmetal/libmetal/lib/irq_controller.h b/ext/hal/libmetal/libmetal/lib/irq_controller.h new file mode 100644 index 0000000000..ba3ce3b3af --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/irq_controller.h @@ -0,0 +1,131 @@ +/* + * 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 eanble */ + 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 != NULL && irq_data->hd != NULL) { + return irq_data->hd(irq, irq_data->arg); + } else { + return METAL_IRQ_NOT_HANDLED; + } +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_IRQ__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/processor/ceva/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/processor/ceva/CMakeLists.txt new file mode 100644 index 0000000000..c06e95176b --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/processor/ceva/CMakeLists.txt @@ -0,0 +1,3 @@ +collect (PROJECT_LIB_HEADERS cpu.h) + +# vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/processor/ceva/cpu.h b/ext/hal/libmetal/libmetal/lib/processor/ceva/cpu.h new file mode 100644 index 0000000000..21bcf1a61c --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/processor/ceva/cpu.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cpu.h + * @brief CPU specific primitives + */ + +#ifndef __METAL_CEVA_CPU__H__ +#define __METAL_CEVA_CPU__H__ + +#define metal_cpu_yield() + +#ifdef TEAKLITE4 +/* + * The dummy implementation is enough here since + * tl42x don't support the out of order and multi core + */ +#define __sync_synchronize() +#endif + +#endif /* __METAL_CEVA_CPU__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/processor/csky/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/processor/csky/CMakeLists.txt new file mode 100644 index 0000000000..c06e95176b --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/processor/csky/CMakeLists.txt @@ -0,0 +1,3 @@ +collect (PROJECT_LIB_HEADERS cpu.h) + +# vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/processor/csky/cpu.h b/ext/hal/libmetal/libmetal/lib/processor/csky/cpu.h new file mode 100644 index 0000000000..a393848844 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/processor/csky/cpu.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cpu.h + * @brief CPU specific primitives + */ + +#ifndef __METAL_CSKY_CPU__H__ +#define __METAL_CSKY_CPU__H__ + +#define metal_cpu_yield() + +#endif /* __METAL_CSKY_CPU__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/processor/riscv/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/processor/riscv/CMakeLists.txt new file mode 100644 index 0000000000..c06e95176b --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/processor/riscv/CMakeLists.txt @@ -0,0 +1,3 @@ +collect (PROJECT_LIB_HEADERS cpu.h) + +# vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/processor/riscv/cpu.h b/ext/hal/libmetal/libmetal/lib/processor/riscv/cpu.h new file mode 100644 index 0000000000..ff02d9f871 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/processor/riscv/cpu.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file cpu.h + * @brief CPU specific primitives + */ + +#ifndef __METAL_RISCV_CPU__H__ +#define __METAL_RISCV_CPU__H__ + +#define metal_cpu_yield() + +#endif /* __METAL_RISCV_CPU__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/softirq.c b/ext/hal/libmetal/libmetal/lib/softirq.c new file mode 100644 index 0000000000..23bcd48865 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/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 = 0; +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() +{ + 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() +{ + 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/ext/hal/libmetal/libmetal/lib/softirq.h b/ext/hal/libmetal/libmetal/lib/softirq.h new file mode 100644 index 0000000000..1a670010a9 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/softirq.h @@ -0,0 +1,68 @@ +/* + * 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__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup soft irq Interrupt Handling Interfaces + * @{ */ + +#include + +/** + * @brief metal_softirq_init + * + * Initialize libmetal soft IRQs controller + * + * @return 0 on success, or negative value for failure + */ +int metal_softirq_init(); + +/** + * @brief metal_softirq_dispatch + * + * Dispatch the pending soft IRQs + */ +void metal_softirq_dispatch(); + +/** + * @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/ext/hal/libmetal/libmetal/lib/spinlock.h b/ext/hal/libmetal/libmetal/lib/spinlock.h index ac9f0eb890..cfdfba6502 100644 --- a/ext/hal/libmetal/libmetal/lib/spinlock.h +++ b/ext/hal/libmetal/libmetal/lib/spinlock.h @@ -22,11 +22,11 @@ extern "C" { /** \defgroup spinlock Spinlock Interfaces * @{ */ struct metal_spinlock { - atomic_int v; + atomic_flag v; }; /** Static metal spinlock initialization. */ -#define METAL_SPINLOCK_INIT {ATOMIC_VAR_INIT(0)} +#define METAL_SPINLOCK_INIT {ATOMIC_FLAG_INIT} /** * @brief Initialize a libmetal spinlock. @@ -34,7 +34,7 @@ struct metal_spinlock { */ static inline void metal_spinlock_init(struct metal_spinlock *slock) { - atomic_store(&slock->v, 0); + atomic_flag_clear(&slock->v); } /** diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/irq.c b/ext/hal/libmetal/libmetal/lib/system/freertos/irq.c index 9e035da61d..08889152e9 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/irq.c +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/irq.c @@ -18,220 +18,6 @@ #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 */ -}; - -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) -{ - struct metal_irq_desc *irq_p = NULL; - struct metal_irq_hddesc *hdl_p; - struct metal_list *node; - unsigned int irq_flags_save; - - if (irq < 0) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d need to be a positive number\n", - __func__, irq); - return -EINVAL; - } - - if ((drv_id == NULL) || (hd == NULL)) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n", - __func__, irq); - 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; - - /* 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 found and drv_id not used, get out of metal_list_for_each */ - break; - } - } - - /* 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); -} - -int metal_irq_unregister(int irq, - metal_irq_handler hd, - struct metal_device *dev, - void *drv_id) -{ - struct metal_irq_desc *irq_p; - struct metal_list *node; - - if (irq < 0) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need to be a positive number\n", - __func__, irq); - 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); - delete_count++; - h_node = h_prenode; - } - } - - /* 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); - return 0; - } - } - - metal_log(METAL_LOG_DEBUG, "%s: No matching IRQ entry\n", __func__); - - metal_mutex_release(&_irqs.irq_lock); - return -ENOENT; -} - unsigned int metal_irq_save_disable(void) { return sys_irq_save_disable(); @@ -242,38 +28,3 @@ void metal_irq_restore_enable(unsigned int flags) sys_irq_restore_enable(flags); } -void metal_irq_enable(unsigned int vector) -{ - sys_irq_enable(vector); -} - -void metal_irq_disable(unsigned int vector) -{ - sys_irq_disable(vector); -} - -/** - * @brief default handler - */ -void metal_irq_isr(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); - } - } - } -} diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/irq.h b/ext/hal/libmetal/libmetal/lib/system/freertos/irq.h index 63147b55f3..72c11d421e 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/irq.h +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/irq.h @@ -16,19 +16,4 @@ #ifndef __METAL_FREERTOS_IRQ__H__ #define __METAL_FREERTOS_IRQ__H__ -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief default interrupt handler - * @param[in] vector interrupt vector - */ -void metal_irq_isr(unsigned int vector); - - -#ifdef __cplusplus -} -#endif - #endif /* __METAL_FREERTOS_IRQ__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/CMakeLists.txt new file mode 100644 index 0000000000..c443fb20cc --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/CMakeLists.txt @@ -0,0 +1,5 @@ +collect (PROJECT_LIB_HEADERS sys.h) + +collect (PROJECT_LIB_SOURCES irq.c) + +# vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/irq.c b/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/irq.c new file mode 100644 index 0000000000..2e6f8aa63c --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/irq.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 - 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/xlnx_common/irq.c + * @brief generic libmetal Xilinx irq controller definitions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_IRQS XLNX_MAXIRQS + +static struct metal_irq irqs[MAX_IRQS]; /**< Linux IRQs array */ + +static void metal_xlnx_irq_set_enable(struct metal_irq_controller *irq_cntr, + int irq, unsigned int state) +{ + if (irq < irq_cntr->irq_base || + irq >= irq_cntr->irq_base + irq_cntr->irq_num) { + metal_log(METAL_LOG_ERROR, "%s: invalid irq %d\n", + __func__, irq); + return; + } else if (state == METAL_IRQ_ENABLE) { + sys_irq_enable((unsigned int)irq); + } else { + sys_irq_disable((unsigned int)irq); + } +} + +/**< Xilinx common platform IRQ controller */ +static METAL_IRQ_CONTROLLER_DECLARE(xlnx_irq_cntr, + 0, MAX_IRQS, + NULL, + metal_xlnx_irq_set_enable, NULL, + irqs) + +/** + * @brief default handler + */ +void metal_xlnx_irq_isr(void *arg) +{ + unsigned int vector; + + vector = (uintptr_t)arg; + if (vector >= MAX_IRQS) { + return; + } + (void)metal_irq_handle(&irqs[vector], (int)vector); +} + +int metal_xlnx_irq_init(void) +{ + int ret; + + ret = metal_irq_register_controller(&xlnx_irq_cntr); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, "%s: register irq controller failed.\n", + __func__); + return ret; + } + return 0; +} diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/sys.h b/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/sys.h new file mode 100644 index 0000000000..21f09550e1 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/xlnx_common/sys.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file freertos/xlnx_common/sys.h + * @brief freertos Xilinx common system primitives for libmetal. + */ + +#ifndef __METAL_FREERTOS_SYS__H__ +#error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h" +#endif + +#ifndef __METAL_FREERTOS_XLNX_COMMON_SYS__H__ +#define __METAL_FREERTOS_XLNX_COMMON_SYS__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief metal_xlnx_irq_isr + * + * Xilinx interrupt ISR can be registered to the Xilinx embeddedsw + * IRQ controller driver. + * + * @param[in] arg input argument, interrupt vector id. + */ +void metal_xlnx_irq_isr(void *arg); + +/** + * @brief metal_xlnx_irq_int + * + * Xilinx interrupt controller initialization. It will initialize + * the metal Xilinx IRQ controller data structure. + * + * @return 0 for success, or negative value for failure + */ +int metal_xlnx_irq_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_FREERTOS_XLNX_COMMON_SYS__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/CMakeLists.txt index 7d824ce188..cf12dfe020 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/CMakeLists.txt @@ -2,4 +2,5 @@ collect (PROJECT_LIB_HEADERS sys.h) collect (PROJECT_LIB_SOURCES sys.c) +add_subdirectory(../xlnx_common ${CMAKE_CURRENT_BINARY_DIR}/../xlnx_common) # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/sys.h b/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/sys.h index f1887d4b0b..80913f0851 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/zynq7/sys.h @@ -13,6 +13,7 @@ #error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h" #endif +#include #include "xscugic.h" #ifndef __METAL_FREERTOS_ZYNQ7_SYS__H__ @@ -24,6 +25,8 @@ extern "C" { #ifdef METAL_INTERNAL +#define XLNX_MAXIRQS XSCUGIC_MAX_NUM_INTR_INPUTS + static inline void sys_irq_enable(unsigned int vector) { XScuGic_EnableIntr(XPAR_SCUGIC_0_DIST_BASEADDR, vector); diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/CMakeLists.txt index 7d824ce188..cf12dfe020 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/CMakeLists.txt @@ -2,4 +2,5 @@ collect (PROJECT_LIB_HEADERS sys.h) collect (PROJECT_LIB_SOURCES sys.c) +add_subdirectory(../xlnx_common ${CMAKE_CURRENT_BINARY_DIR}/../xlnx_common) # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.h b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.h index 6efd4a3d8d..ed4085fba5 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_a53/sys.h @@ -13,6 +13,7 @@ #error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h" #endif +#include #include "xscugic.h" #ifndef __METAL_FREERTOS_ZYNQMP_A53_SYS__H__ @@ -24,6 +25,8 @@ extern "C" { #ifdef METAL_INTERNAL +#define XLNX_MAXIRQS XSCUGIC_MAX_NUM_INTR_INPUTS + static inline void sys_irq_enable(unsigned int vector) { XScuGic_EnableIntr(XPAR_SCUGIC_0_DIST_BASEADDR, vector); diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/CMakeLists.txt index 7d824ce188..cf12dfe020 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/CMakeLists.txt @@ -2,4 +2,5 @@ collect (PROJECT_LIB_HEADERS sys.h) collect (PROJECT_LIB_SOURCES sys.c) +add_subdirectory(../xlnx_common ${CMAKE_CURRENT_BINARY_DIR}/../xlnx_common) # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/sys.h b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/sys.h index 4d41933f47..bd9d4f61e8 100644 --- a/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/freertos/zynqmp_r5/sys.h @@ -13,6 +13,7 @@ #error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h" #endif +#include #include "xscugic.h" #ifndef __METAL_FREERTOS_ZYNQMP_R5_SYS__H__ @@ -24,6 +25,8 @@ extern "C" { #ifdef METAL_INTERNAL +#define XLNX_MAXIRQS XSCUGIC_MAX_NUM_INTR_INPUTS + static inline void sys_irq_enable(unsigned int vector) { XScuGic_EnableIntr(XPAR_SCUGIC_0_DIST_BASEADDR, vector); diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/condition.c b/ext/hal/libmetal/libmetal/lib/system/generic/condition.c index dbaddb8f9c..9107569dfc 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/condition.c +++ b/ext/hal/libmetal/libmetal/lib/system/generic/condition.c @@ -17,7 +17,7 @@ extern void metal_generic_default_poll(void); int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m) { - metal_mutex_t *tmpm = 0; + uintptr_t tmpmptr = 0, mptr = (uintptr_t)m; int v; unsigned int flags; @@ -25,8 +25,8 @@ int metal_condition_wait(struct metal_condition *cv, if (!cv || !m || !metal_mutex_is_acquired(m)) return -EINVAL; - if (!atomic_compare_exchange_strong(&cv->m, &tmpm, m)) { - if (m != tmpm) + if (!atomic_compare_exchange_strong(&cv->mptr, &tmpmptr, mptr)) { + if (tmpmptr != mptr) return -EINVAL; } diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/condition.h b/ext/hal/libmetal/libmetal/lib/system/generic/condition.h index 9e24a53a69..285988ca6d 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/condition.h +++ b/ext/hal/libmetal/libmetal/lib/system/generic/condition.h @@ -27,21 +27,21 @@ extern "C" { #endif struct metal_condition { - metal_mutex_t *m; /**< mutex. - The condition variable is attached to - this mutex when it is waiting. - It is also used to check correctness - in case there are multiple waiters. */ + atomic_uintptr_t mptr; /**< mutex pointer. + The condition variable is attached to + this mutex when it is waiting. + It is also used to check correctness + in case there are multiple waiters. */ atomic_int v; /**< condition variable value. */ }; /** Static metal condition variable initialization. */ -#define METAL_CONDITION_INIT { NULL, ATOMIC_VAR_INIT(0) } +#define METAL_CONDITION_INIT { ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0) } static inline void metal_condition_init(struct metal_condition *cv) { - cv->m = NULL; + atomic_init(&cv->mptr, 0); atomic_init(&cv->v, 0); } diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/irq.c b/ext/hal/libmetal/libmetal/lib/system/generic/irq.c index dc12a69d96..4242b6edad 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/irq.c +++ b/ext/hal/libmetal/libmetal/lib/system/generic/irq.c @@ -18,220 +18,6 @@ #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 */ -}; - -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) -{ - struct metal_irq_desc *irq_p = NULL; - struct metal_irq_hddesc *hdl_p; - struct metal_list *node; - unsigned int irq_flags_save; - - if (irq < 0) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d need to be a positive number\n", - __func__, irq); - return -EINVAL; - } - - if ((drv_id == NULL) || (hd == NULL)) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n", - __func__, irq); - 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; - - /* 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 found and drv_id not used, get out of metal_list_for_each */ - break; - } - } - - /* 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); -} - -int metal_irq_unregister(int irq, - metal_irq_handler hd, - struct metal_device *dev, - void *drv_id) -{ - struct metal_irq_desc *irq_p; - struct metal_list *node; - - if (irq < 0) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need to be a positive number\n", - __func__, irq); - 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); - return 0; - } - } - - metal_log(METAL_LOG_DEBUG, "%s: No matching IRQ entry\n", __func__); - - metal_mutex_release(&_irqs.irq_lock); - return -ENOENT; -} - unsigned int metal_irq_save_disable(void) { return sys_irq_save_disable(); @@ -242,38 +28,3 @@ void metal_irq_restore_enable(unsigned int flags) sys_irq_restore_enable(flags); } -void metal_irq_enable(unsigned int vector) -{ - sys_irq_enable(vector); -} - -void metal_irq_disable(unsigned int vector) -{ - sys_irq_disable(vector); -} - -/** - * @brief default handler - */ -void metal_irq_isr(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); - } - } - } -} diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/irq.h b/ext/hal/libmetal/libmetal/lib/system/generic/irq.h index 5744275dc6..dd8ac8d435 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/irq.h +++ b/ext/hal/libmetal/libmetal/lib/system/generic/irq.h @@ -16,19 +16,4 @@ #ifndef __METAL_GENERIC_IRQ__H__ #define __METAL_GENERIC_IRQ__H__ -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief default interrupt handler - * @param[in] vector interrupt vector - */ -void metal_irq_isr(unsigned int vector); - - -#ifdef __cplusplus -} -#endif - #endif /* __METAL_GENERIC_IRQ__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/CMakeLists.txt index e5896cd667..632af9c8aa 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/CMakeLists.txt @@ -7,4 +7,5 @@ if (HAS_XINTC) add_definitions(-DHAS_XINTC) endif(HAS_XINTC) +add_subdirectory(../xlnx_common ${CMAKE_CURRENT_BINARY_DIR}/../xlnx_common) # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.c b/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.c index 6f0cd8a12f..edd0ec130b 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.c +++ b/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.c @@ -35,6 +35,17 @@ unsigned int sys_irq_save_disable(void) return state &= MSR_IE; } + +void sys_irq_restore_enable(unsigned int flags) +{ + unsigned int tmp; + if (flags) + asm volatile(" msrset %0, %1 \n" + : "=r"(tmp) + : "i"(MSR_IE) + : "memory"); +} + #else /* XPAR_MICROBLAZE_USE_MSR_INSTR == 0 */ unsigned int sys_irq_save_disable(void) { @@ -49,19 +60,20 @@ unsigned int sys_irq_save_disable(void) return state &= MSR_IE; } -#endif /* XPAR_MICROBLAZE_USE_MSR_INSTR */ void sys_irq_restore_enable(unsigned int flags) { unsigned int tmp; - asm volatile(" mfs %0, rmsr \n" - " or %0, %0, %1 \n" - " mts rmsr, %0 \n" - : "=r"(tmp) - : "r"(~flags) - : "memory"); + if (flags) + asm volatile(" mfs %0, rmsr \n" + " or %0, %0, %1 \n" + " mts rmsr, %0 \n" + : "=r"(tmp) + : "r"(flags) + : "memory"); } +#endif /* XPAR_MICROBLAZE_USE_MSR_INSTR */ static void sys_irq_change(unsigned int vector, int is_enable) { diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.h b/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.h index 61a497641f..538917ec0d 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/generic/microblaze_generic/sys.h @@ -13,6 +13,8 @@ #error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h" #endif +#include + #ifndef __METAL_GENERIC_MICROBLAZE_SYS__H__ #define __METAL_GENERIC_MICROBLAZE_SYS__H__ @@ -24,6 +26,10 @@ extern "C" { #ifdef METAL_INTERNAL +#ifndef XLNX_MAXIRQS +#define XLNX_MAXIRQS 32 +#endif + void metal_weak sys_irq_enable(unsigned int vector); void metal_weak sys_irq_disable(unsigned int vector); diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/CMakeLists.txt new file mode 100644 index 0000000000..c443fb20cc --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/CMakeLists.txt @@ -0,0 +1,5 @@ +collect (PROJECT_LIB_HEADERS sys.h) + +collect (PROJECT_LIB_SOURCES irq.c) + +# vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/irq.c b/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/irq.c new file mode 100644 index 0000000000..5cbce32304 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/irq.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 - 2017, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/xlnx_common/irq.c + * @brief generic libmetal Xilinx irq controller definitions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_IRQS XLNX_MAXIRQS + +static struct metal_irq irqs[MAX_IRQS]; /**< Linux IRQs array */ + +static void metal_xlnx_irq_set_enable(struct metal_irq_controller *irq_cntr, + int irq, unsigned int state) +{ + if (irq < irq_cntr->irq_base || + irq >= irq_cntr->irq_base + irq_cntr->irq_num) { + metal_log(METAL_LOG_ERROR, "%s: invalid irq %d\n", + __func__, irq); + return; + } else if (state == METAL_IRQ_ENABLE) { + sys_irq_enable((unsigned int)irq); + } else { + sys_irq_disable((unsigned int)irq); + } +} + +/**< Xilinx common platform IRQ controller */ +static METAL_IRQ_CONTROLLER_DECLARE(xlnx_irq_cntr, + 0, MAX_IRQS, + NULL, + metal_xlnx_irq_set_enable, NULL, + irqs) + +/** + * @brief default handler + */ +void metal_xlnx_irq_isr(void *arg) +{ + unsigned int vector; + + vector = (uintptr_t)arg; + if (vector >= MAX_IRQS) { + return; + } + (void)metal_irq_handle(&irqs[vector], (int)vector); +} + +int metal_xlnx_irq_init(void) +{ + int ret; + + ret = metal_irq_register_controller(&xlnx_irq_cntr); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, "%s: register irq controller failed.\n", + __func__); + return ret; + } + return 0; +} diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/sys.h b/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/sys.h new file mode 100644 index 0000000000..7d41cfae69 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/generic/xlnx_common/sys.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file generic/xlnx_common/sys.h + * @brief generic xlnx_common system primitives for libmetal. + */ + +#ifndef __METAL_GENERIC_SYS__H__ +#error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h" +#endif + +#ifndef __METAL_GENERIC_XLNX_COMMON_SYS__H__ +#define __METAL_GENERIC_XLNX_COMMON_SYS__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief metal_xlnx_irq_isr + * + * Xilinx interrupt ISR can be registered to the Xilinx embeddedsw + * IRQ controller driver. + * + * @param[in] arg input argument, interrupt vector id. + */ +void metal_xlnx_irq_isr(void *arg); + +/** + * @brief metal_xlnx_irq_int + * + * Xilinx interrupt controller initialization. It will initialize + * the metal Xilinx IRQ controller data structure. + * + * @return 0 for success, or negative value for failure + */ +int metal_xlnx_irq_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_GENERIC_XLNX_COMMON_SYS__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/CMakeLists.txt index 7d824ce188..cf12dfe020 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/CMakeLists.txt @@ -2,4 +2,5 @@ collect (PROJECT_LIB_HEADERS sys.h) collect (PROJECT_LIB_SOURCES sys.c) +add_subdirectory(../xlnx_common ${CMAKE_CURRENT_BINARY_DIR}/../xlnx_common) # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/sys.h b/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/sys.h index 673eb2bdf8..5dd830ef36 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/generic/zynq7/sys.h @@ -13,6 +13,7 @@ #error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h" #endif +#include #include "xscugic.h" #ifndef __METAL_GENERIC_ZYNQ7_SYS__H__ @@ -24,6 +25,8 @@ extern "C" { #ifdef METAL_INTERNAL +#define XLNX_MAXIRQS XSCUGIC_MAX_NUM_INTR_INPUTS + static inline void sys_irq_enable(unsigned int vector) { XScuGic_EnableIntr(XPAR_SCUGIC_0_DIST_BASEADDR, vector); diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/CMakeLists.txt index 7d824ce188..cf12dfe020 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/CMakeLists.txt @@ -2,4 +2,5 @@ collect (PROJECT_LIB_HEADERS sys.h) collect (PROJECT_LIB_SOURCES sys.c) +add_subdirectory(../xlnx_common ${CMAKE_CURRENT_BINARY_DIR}/../xlnx_common) # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.h b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.h index 62e86acb66..bc2858b672 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_a53/sys.h @@ -13,6 +13,7 @@ #error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h" #endif +#include #include "xscugic.h" #ifndef __METAL_GENERIC_ZYNQMP_A53_SYS__H__ @@ -24,6 +25,8 @@ extern "C" { #ifdef METAL_INTERNAL +#define XLNX_MAXIRQS XSCUGIC_MAX_NUM_INTR_INPUTS + static inline void sys_irq_enable(unsigned int vector) { XScuGic_EnableIntr(XPAR_SCUGIC_0_DIST_BASEADDR, vector); diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/CMakeLists.txt index 7d824ce188..cf12dfe020 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/CMakeLists.txt +++ b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/CMakeLists.txt @@ -2,4 +2,5 @@ collect (PROJECT_LIB_HEADERS sys.h) collect (PROJECT_LIB_SOURCES sys.c) +add_subdirectory(../xlnx_common ${CMAKE_CURRENT_BINARY_DIR}/../xlnx_common) # vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/sys.h b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/sys.h index cdc94d831b..62586dd805 100644 --- a/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/sys.h +++ b/ext/hal/libmetal/libmetal/lib/system/generic/zynqmp_r5/sys.h @@ -10,9 +10,10 @@ */ #ifndef __METAL_GENERIC_SYS__H__ -#error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h" +#error "Include metal/sys.h instead of metal/system/generic/@PROJECT_MACHINE@/sys.h" #endif +#include #include "xscugic.h" #ifndef __METAL_GENERIC_ZYNQMP_R5_SYS__H__ @@ -24,6 +25,8 @@ extern "C" { #ifdef METAL_INTERNAL +#define XLNX_MAXIRQS XSCUGIC_MAX_NUM_INTR_INPUTS + static inline void sys_irq_enable(unsigned int vector) { XScuGic_EnableIntr(XPAR_SCUGIC_0_DIST_BASEADDR, vector); diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/condition.c b/ext/hal/libmetal/libmetal/lib/system/linux/condition.c index 5625877e63..9acf19e2ac 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/condition.c +++ b/ext/hal/libmetal/libmetal/lib/system/linux/condition.c @@ -14,15 +14,15 @@ int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m) { - metal_mutex_t *tmpm = 0; + uintptr_t tmpmptr = 0, mptr = (uintptr_t)m; int v = 0; /* Check if the mutex has been acquired */ if (!cv || !m || !metal_mutex_is_acquired(m)) return -EINVAL; - if (!atomic_compare_exchange_strong(&cv->m, &tmpm, m)) { - if (m != tmpm) + if (!atomic_compare_exchange_strong(&cv->mptr, &tmpmptr, mptr)) { + if (tmpmptr != mptr) return -EINVAL; } diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/condition.h b/ext/hal/libmetal/libmetal/lib/system/linux/condition.h index 27b1881747..ca368a6c4b 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/condition.h +++ b/ext/hal/libmetal/libmetal/lib/system/linux/condition.h @@ -29,22 +29,23 @@ extern "C" { #endif struct metal_condition { - metal_mutex_t *m; /**< mutex. - The condition variable is attached to - this mutex when it is waiting. - It is also used to check correctness - in case there are multiple waiters. */ + atomic_uintptr_t mptr; /**< mutex pointer. + The condition variable is attached to + this mutex when it is waiting. + It is also used to check correctness + in case there are multiple waiters. */ atomic_int waiters; /**< number of waiters. */ atomic_int wakeups; /**< number of wakeups. */ }; /** Static metal condition variable initialization. */ -#define METAL_CONDITION_INIT { NULL, ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0) } +#define METAL_CONDITION_INIT { ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0), \ + ATOMIC_VAR_INIT(0) } static inline void metal_condition_init(struct metal_condition *cv) { - cv->m = NULL; + atomic_init(&cv->mptr, 0); atomic_init(&cv->waiters, 0); atomic_init(&cv->wakeups, 0); } diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/device.c b/ext/hal/libmetal/libmetal/lib/system/linux/device.c index 85af0d77f5..9accba4215 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/device.c +++ b/ext/hal/libmetal/libmetal/lib/system/linux/device.c @@ -31,13 +31,13 @@ struct linux_driver { void (*dev_irq_ack)(struct linux_bus *lbus, struct linux_device *ldev, int irq); - int (*dev_dma_map)(struct linux_bus *lbus, + int (*dev_dma_map)(struct linux_bus *lbus, struct linux_device *ldev, uint32_t dir, struct metal_sg *sg_in, int nents_in, struct metal_sg *sg_out); - void (*dev_dma_unmap)(struct linux_bus *lbus, + void (*dev_dma_unmap)(struct linux_bus *lbus, struct linux_device *ldev, uint32_t dir, struct metal_sg *sg, @@ -156,6 +156,7 @@ static int metal_uio_dev_open(struct linux_bus *lbus, struct linux_device *ldev) ldev->fd = -1; + ldev->device.irq_info = (void *)-1; ldev->sdev = sysfs_open_device(lbus->bus_name, ldev->dev_name); if (!ldev->sdev) { @@ -249,6 +250,7 @@ static int metal_uio_dev_open(struct linux_bus *lbus, struct linux_device *ldev) } else { ldev->device.irq_num = 1; ldev->device.irq_info = (void *)(intptr_t)ldev->fd; + metal_linux_irq_register_dev(&ldev->device, ldev->fd); } return 0; @@ -259,12 +261,6 @@ static void metal_uio_dev_close(struct linux_bus *lbus, { (void)lbus; - if ((intptr_t)ldev->device.irq_info >= 0) - /* Normally this call would not be needed, and is added as precaution. - Also for uio there is only 1 interrupt associated to the fd/device, - we therefore do not need to specify a particular device */ - metal_irq_unregister(ldev->fd, NULL, NULL, NULL); - if (ldev->override) { sysfs_write_attribute(ldev->override, "", 1); ldev->override = NULL; @@ -586,34 +582,32 @@ static int metal_linux_probe_driver(struct linux_bus *lbus, return ldrv->sdrv ? 0 : -ENODEV; } +static void metal_linux_bus_close(struct metal_bus *bus); + static int metal_linux_probe_bus(struct linux_bus *lbus) { struct linux_driver *ldrv; - int error = -ENODEV; + int ret, error = -ENODEV; lbus->sbus = sysfs_open_bus(lbus->bus_name); if (!lbus->sbus) return -ENODEV; for_each_linux_driver(lbus, ldrv) { - error = metal_linux_probe_driver(lbus, ldrv); - if (!error) - break; + ret = metal_linux_probe_driver(lbus, ldrv); + /* Clear the error if any driver is available */ + if (!ret) + error = ret; } if (error) { - sysfs_close_bus(lbus->sbus); - lbus->sbus = NULL; + metal_linux_bus_close(&lbus->bus); return error; } error = metal_linux_register_bus(lbus); - if (error) { - sysfs_close_driver(ldrv->sdrv); - ldrv->sdrv = NULL; - sysfs_close_bus(lbus->sbus); - lbus->sbus = NULL; - } + if (error) + metal_linux_bus_close(&lbus->bus); return error; } diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/irq.c b/ext/hal/libmetal/libmetal/lib/system/linux/irq.c index 89e5f2f6fb..0151bc4422 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/irq.c +++ b/ext/hal/libmetal/libmetal/lib/system/linux/irq.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -20,203 +21,93 @@ #include #include #include +#include +#include #include -#include -#include #include #include +#include -#define MAX_IRQS FD_SETSIZE /**< maximum number of irqs */ -#define METAL_IRQ_STOP 0xFFFFFFFF /**< stop interrupts handling thread */ +#define MAX_IRQS (FD_SETSIZE - 1) /**< maximum number of irqs */ -/** IRQ handler descriptor structure */ -struct metal_irq_hddesc { - metal_irq_handler hd; /**< irq handler */ - struct metal_device *dev; /**< metal device */ - void *drv_id; /**< id to identify the driver - of the irq handler*/ - struct metal_list list; /**< handler list container */ -}; +static struct metal_device *irqs_devs[MAX_IRQS]; /**< Linux devices for IRQs */ +static int irq_notify_fd; /**< irq handling state change notification file + descriptor */ +static metal_mutex_t irq_lock; /**< irq handling lock */ -struct metal_irqs_state { - struct metal_irq_hddesc hds[MAX_IRQS]; /**< irqs handlers descriptor */ - signed char irq_reg_stat[MAX_IRQS]; /**< irqs registration statistics. - It restore how many handlers have - been registered for each IRQ. */ +static bool irq_handling_stop; /**< stop interrupts handling */ - int irq_reg_fd; /**< irqs registration notification file - descriptor */ +static pthread_t irq_pthread; /**< irq handling thread id */ - metal_mutex_t irq_lock; /**< irq handling lock */ +/**< Indicate which IRQ is enabled */ +static unsigned long +irqs_enabled[metal_div_round_up(MAX_IRQS, METAL_BITS_PER_ULONG)]; - unsigned int irq_state; /**< global irq handling state */ +static struct metal_irq irqs[MAX_IRQS]; /**< Linux IRQs array */ - pthread_t irq_pthread; /**< irq handling thread id */ -}; +/* Static functions */ +static void metal_linux_irq_set_enable(struct metal_irq_controller *irq_cntr, + int irq, unsigned int state); -struct metal_irqs_state _irqs; - -int metal_irq_register(int irq, - metal_irq_handler hd, - struct metal_device *dev, - void *drv_id) -{ - uint64_t val = 1; - struct metal_irq_hddesc *hd_desc; - struct metal_list *h_node; - int ret; - - if ((irq < 0) || (irq >= MAX_IRQS)) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d is larger than the max supported %d.\n", - __func__, irq, MAX_IRQS - 1); - return -EINVAL; - } - - if ((drv_id == NULL) || (hd == NULL)) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n", - __func__, irq); - return -EINVAL; - } - - metal_mutex_acquire(&_irqs.irq_lock); - if (_irqs.irq_state == METAL_IRQ_STOP) { - metal_log(METAL_LOG_ERROR, - "%s: failed. metal IRQ handling has stopped.\n", - __func__); - metal_mutex_release(&_irqs.irq_lock); - return -EINVAL; - } - - metal_list_for_each(&_irqs.hds[irq].list, h_node) { - hd_desc = metal_container_of(h_node, struct metal_irq_hddesc, list); - - /* if drv_id already exist reject */ - if ((hd_desc->drv_id == drv_id) && - ((dev == NULL) || (hd_desc->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; - } - /* drv_id not used, get out of metal_list_for_each */ - break; - } - - /* Add to the end */ - hd_desc = metal_allocate_memory(sizeof(struct metal_irq_hddesc)); - if (hd_desc == 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; - } - hd_desc->hd = hd; - hd_desc->drv_id = drv_id; - hd_desc->dev = dev; - metal_list_add_tail(&_irqs.hds[irq].list, &hd_desc->list); - - _irqs.irq_reg_stat[irq]++; - metal_mutex_release(&_irqs.irq_lock); - - ret = write(_irqs.irq_reg_fd, &val, sizeof(val)); - if (ret < 0) { - metal_log(METAL_LOG_DEBUG, "%s: write failed IRQ %d\n", __func__, irq); - } - - metal_log(METAL_LOG_DEBUG, "%s: registered IRQ %d\n", __func__, irq); - return 0; -} - -int metal_irq_unregister(int irq, - metal_irq_handler hd, - struct metal_device *dev, - void *drv_id) -{ - uint64_t val = 1; - struct metal_irq_hddesc *hd_desc; - struct metal_list *h_node; - int ret; - unsigned int delete_count = 0; - - if ((irq < 0) || (irq >= MAX_IRQS)) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d is larger than the max supported %d.\n", - __func__, irq, MAX_IRQS); - return -EINVAL; - } - - metal_mutex_acquire(&_irqs.irq_lock); - if (_irqs.irq_state == METAL_IRQ_STOP) { - metal_log(METAL_LOG_ERROR, - "%s: failed. metal IRQ handling has stopped.\n", __func__); - metal_mutex_release(&_irqs.irq_lock); - return -EINVAL; - } - - if (!hd && !drv_id && !dev) { - if (0 == _irqs.irq_reg_stat[irq]) - goto no_entry; - - _irqs.irq_reg_stat[irq] = 0; - goto out; - } - - /* Search through handlers */ - metal_list_for_each(&_irqs.hds[irq].list, h_node) { - hd_desc = metal_container_of(h_node, struct metal_irq_hddesc, list); - - if (((hd == NULL) || (hd_desc->hd == hd)) && - ((drv_id == NULL) || (hd_desc->drv_id == drv_id)) && - ((dev == NULL) || (hd_desc->dev == dev))) { - if (_irqs.irq_reg_stat[irq] > 0) - _irqs.irq_reg_stat[irq]--; - h_node = h_node->prev; - metal_list_del(h_node->next); - metal_free_memory(hd_desc); - delete_count++; - } - } - - if (delete_count) - goto out; - -no_entry: - metal_log(METAL_LOG_DEBUG, "%s: No matching entry.\n", __func__); - metal_mutex_release(&_irqs.irq_lock); - return -ENOENT; -out: - metal_mutex_release(&_irqs.irq_lock); - ret = write(_irqs.irq_reg_fd, &val, sizeof(val)); - if (ret < 0) { - metal_log(METAL_LOG_DEBUG, "%s: write failed IRQ %d\n", __func__, irq); - } - metal_log(METAL_LOG_DEBUG, "%s: unregistered IRQ %d (%d)\n", __func__, irq, delete_count); - return 0; -} +/**< Linux IRQ controller */ +static METAL_IRQ_CONTROLLER_DECLARE(linux_irq_cntr, + 0, MAX_IRQS, + NULL, + metal_linux_irq_set_enable, NULL, + irqs) unsigned int metal_irq_save_disable() { - metal_mutex_acquire(&_irqs.irq_lock); + /* This is to avoid deadlock if it is called in ISR */ + if (pthread_self() == irq_pthread) + return 0; + metal_mutex_acquire(&irq_lock); return 0; } void metal_irq_restore_enable(unsigned flags) { (void)flags; - metal_mutex_release(&_irqs.irq_lock); + if (pthread_self() != irq_pthread) + metal_mutex_release(&irq_lock); } -void metal_irq_enable(unsigned int vector) +static int metal_linux_irq_notify() { - (void)vector; + uint64_t val = 1; + int ret; + + ret = write(irq_notify_fd, &val, sizeof(val)); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, "%s failed\n", __func__); + } + return ret; } -void metal_irq_disable(unsigned int vector) +static void metal_linux_irq_set_enable(struct metal_irq_controller *irq_cntr, + int irq, unsigned int state) { - (void)vector; + int offset, ret; + + if (irq < irq_cntr->irq_base || + irq >= irq_cntr->irq_base + irq_cntr->irq_num) { + metal_log(METAL_LOG_ERROR, "%s: invalid irq %d\n", + __func__, irq); + return; + } + offset = irq - linux_irq_cntr.irq_base; + metal_mutex_acquire(&irq_lock); + if (state == METAL_IRQ_ENABLE) + metal_bitmap_set_bit(irqs_enabled, offset); + else + metal_bitmap_clear_bit(irqs_enabled, offset); + metal_mutex_release(&irq_lock); + /* Notify IRQ thread that IRQ state has changed */ + ret = metal_linux_irq_notify(); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, "%s: failed to notify set %d enable\n", + __func__, irq); + } } /** @@ -233,7 +124,7 @@ static void *metal_linux_irq_handling(void *args) (void) args; - pfds = (struct pollfd *)malloc(MAX_IRQS * sizeof(struct pollfd)); + pfds = (struct pollfd *)malloc(FD_SETSIZE * sizeof(struct pollfd)); if (!pfds) { metal_log(METAL_LOG_ERROR, "%s: failed to allocate irq fds mem.\n", __func__); @@ -244,30 +135,30 @@ static void *metal_linux_irq_handling(void *args) /* Ignore the set scheduler error */ ret = sched_setscheduler(0, SCHED_FIFO, ¶m); if (ret) { - metal_log(METAL_LOG_WARNING, "%s: Failed to set scheduler: %d.\n", - __func__, ret); + metal_log(METAL_LOG_WARNING, "%s: Failed to set scheduler: %s.\n", + __func__, strerror(ret)); } while (1) { - metal_mutex_acquire(&_irqs.irq_lock); - if (_irqs.irq_state == METAL_IRQ_STOP) { + metal_mutex_acquire(&irq_lock); + if (irq_handling_stop == true) { /* Killing this IRQ handling thread */ - metal_mutex_release(&_irqs.irq_lock); + metal_mutex_release(&irq_lock); break; } /* Get the fdset */ memset(pfds, 0, MAX_IRQS * sizeof(struct pollfd)); - pfds[0].fd = _irqs.irq_reg_fd; + pfds[0].fd = irq_notify_fd; pfds[0].events = POLLIN; - for(i = 0, j = 1; i < MAX_IRQS && j < MAX_IRQS; i++) { - if (_irqs.irq_reg_stat[i] > 0) { - pfds[j].fd = i; - pfds[j].events = POLLIN; - j++; - } + j = 1; + metal_bitmap_for_each_set_bit(irqs_enabled, i, + linux_irq_cntr.irq_num) { + pfds[j].fd = i; + pfds[j].events = POLLIN; + j++; } - metal_mutex_release(&_irqs.irq_lock); + metal_mutex_release(&irq_lock); /* Wait for interrupt */ ret = poll(pfds, j, -1); if (ret < 0) { @@ -278,37 +169,32 @@ static void *metal_linux_irq_handling(void *args) /* Waken up from interrupt */ pfds_total = j; for (i = 0; i < pfds_total; i++) { - if ( (pfds[i].fd == _irqs.irq_reg_fd) && + if ( (pfds[i].fd == irq_notify_fd) && (pfds[i].revents & (POLLIN | POLLRDNORM))) { /* IRQ registration change notification */ if (read(pfds[i].fd, (void*)&val, sizeof(uint64_t)) < 0) metal_log(METAL_LOG_ERROR, - "%s, read irq fd %d failed.\n", - __func__, pfds[i].fd); + "%s, read irq fd %d failed.\n", + __func__, pfds[i].fd); } else if ((pfds[i].revents & (POLLIN | POLLRDNORM))) { - struct metal_irq_hddesc *hd_desc; /**< irq handler descriptor */ - struct metal_device *dev = NULL; /**< metal device IRQ belongs to */ - int irq_handled = 0; /**< flag to indicate if irq is handled */ - struct metal_list *h_node; + struct metal_device *dev = NULL; + int irq_handled = 0; + int fd; - metal_list_for_each(&_irqs.hds[pfds[i].fd].list, h_node) { - hd_desc = metal_container_of(h_node, struct metal_irq_hddesc, list); - - metal_mutex_acquire(&_irqs.irq_lock); - if (!dev) - dev = hd_desc->dev; - metal_mutex_release(&_irqs.irq_lock); - - if ((hd_desc->hd)(pfds[i].fd, hd_desc->drv_id) == METAL_IRQ_HANDLED) - irq_handled = 1; - } + fd = pfds[i].fd; + dev = irqs_devs[fd]; + metal_mutex_acquire(&irq_lock); + if (metal_irq_handle(&irqs[fd], fd) + == METAL_IRQ_HANDLED) + irq_handled = 1; if (irq_handled) { if (dev && dev->bus->ops.dev_irq_ack) - dev->bus->ops.dev_irq_ack(dev->bus, dev, i); + dev->bus->ops.dev_irq_ack(dev->bus, dev, fd); } + metal_mutex_release(&irq_lock); } else if (pfds[i].revents) { metal_log(METAL_LOG_DEBUG, - "%s: poll unexpected. fd %d: %d\n", + "%s: poll unexpected. fd %d: %d\n", __func__, pfds[i].fd, pfds[i].revents); } } @@ -323,23 +209,25 @@ static void *metal_linux_irq_handling(void *args) */ int metal_linux_irq_init() { - int ret, irq; + int ret; - memset(&_irqs, 0, sizeof(_irqs)); + memset(&irqs, 0, sizeof(irqs)); - /* init handlers list for each interrupt in table */ - for (irq=0; irq < MAX_IRQS; irq++) { - metal_list_init(&_irqs.hds[irq].list); - } - - _irqs.irq_reg_fd = eventfd(0,0); - if (_irqs.irq_reg_fd < 0) { + irq_notify_fd = eventfd(0,0); + if (irq_notify_fd < 0) { metal_log(METAL_LOG_ERROR, "Failed to create eventfd for IRQ handling.\n"); return -EAGAIN; } - metal_mutex_init(&_irqs.irq_lock); - ret = pthread_create(&_irqs.irq_pthread, NULL, + metal_mutex_init(&irq_lock); + irq_handling_stop = false; + ret = metal_irq_register_controller(&linux_irq_cntr); + if (ret < 0) { + metal_log(METAL_LOG_ERROR, + "Linux IRQ controller failed to register.\n"); + return -EINVAL; + } + ret = pthread_create(&irq_pthread, NULL, metal_linux_irq_handling, NULL); if (ret != 0) { metal_log(METAL_LOG_ERROR, "Failed to create IRQ thread: %d.\n", ret); @@ -355,20 +243,24 @@ int metal_linux_irq_init() void metal_linux_irq_shutdown() { int ret; - uint64_t val = 1; metal_log(METAL_LOG_DEBUG, "%s\n", __func__); - metal_mutex_acquire(&_irqs.irq_lock); - _irqs.irq_state = METAL_IRQ_STOP; - metal_mutex_release(&_irqs.irq_lock); - ret = write (_irqs.irq_reg_fd, &val, sizeof(val)); - if (ret < 0) { - metal_log(METAL_LOG_ERROR, "Failed to write.\n"); - } - ret = pthread_join(_irqs.irq_pthread, NULL); + irq_handling_stop = true; + metal_linux_irq_notify(); + ret = pthread_join(irq_pthread, NULL); if (ret) { metal_log(METAL_LOG_ERROR, "Failed to join IRQ thread: %d.\n", ret); } - close(_irqs.irq_reg_fd); - metal_mutex_deinit(&_irqs.irq_lock); + close(irq_notify_fd); + metal_mutex_deinit(&irq_lock); +} + +void metal_linux_irq_register_dev(struct metal_device *dev, int irq) +{ + if (irq > MAX_IRQS) { + metal_log(METAL_LOG_ERROR, "Failed to register device to irq %d\n", + irq); + return; + } + irqs_devs[irq] = dev; } diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/irq.h b/ext/hal/libmetal/libmetal/lib/system/linux/irq.h index f0cd27b65b..ebb87cd40c 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/irq.h +++ b/ext/hal/libmetal/libmetal/lib/system/linux/irq.h @@ -14,6 +14,22 @@ #endif #ifndef __METAL_LINUX_IRQ__H__ +#ifdef METAL_INTERNAL + +#include + +/** + * @brief metal_linux_register_dev + * + * Metal Linux internal function to register metal device to a IRQ + * which is generated from the device. + * + * @param[in] dev pointer to metal device + * @param[in] irq interrupt id + */ +void metal_linux_irq_register_dev(struct metal_device *dev, int irq); + +#endif /* METAL_INTERNAL */ #define __METAL_LINUX_IRQ__H__ #endif /* __METAL_LINUX_IRQ__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/linux/shmem.c b/ext/hal/libmetal/libmetal/lib/system/linux/shmem.c index 3fa996be1c..067f86c5a8 100644 --- a/ext/hal/libmetal/libmetal/lib/system/linux/shmem.c +++ b/ext/hal/libmetal/libmetal/lib/system/linux/shmem.c @@ -25,7 +25,7 @@ static void metal_shmem_io_close(struct metal_io_region *io) } static const struct metal_io_ops metal_shmem_io_ops = { - NULL, NULL, NULL, NULL, NULL, metal_shmem_io_close + NULL, NULL, NULL, NULL, NULL, metal_shmem_io_close, NULL, NULL }; static int metal_shmem_try_map(struct metal_page_size *ps, int fd, size_t size, @@ -43,8 +43,9 @@ static int metal_shmem_try_map(struct metal_page_size *ps, int fd, size_t size, error = metal_map(fd, 0, size, 1, ps->mmap_flags, &mem); if (error) { - metal_log(METAL_LOG_ERROR, "failed to mmap shmem - %s\n", - strerror(-error)); + metal_log(METAL_LOG_WARNING, + "failed to mmap shmem %ld,0x%x - %s\n", + size, ps->mmap_flags, strerror(-error)); return error; } diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/CMakeLists.txt b/ext/hal/libmetal/libmetal/lib/system/nuttx/CMakeLists.txt new file mode 100644 index 0000000000..001e428fa3 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/CMakeLists.txt @@ -0,0 +1,20 @@ +collect (PROJECT_LIB_HEADERS alloc.h) +collect (PROJECT_LIB_HEADERS assert.h) +collect (PROJECT_LIB_HEADERS cache.h) +collect (PROJECT_LIB_HEADERS condition.h) +collect (PROJECT_LIB_HEADERS io.h) +collect (PROJECT_LIB_HEADERS irq.h) +collect (PROJECT_LIB_HEADERS log.h) +collect (PROJECT_LIB_HEADERS mutex.h) +collect (PROJECT_LIB_HEADERS sleep.h) +collect (PROJECT_LIB_HEADERS sys.h) + +collect (PROJECT_LIB_SOURCES condition.c) +collect (PROJECT_LIB_SOURCES device.c) +collect (PROJECT_LIB_SOURCES init.c) +collect (PROJECT_LIB_SOURCES io.c) +collect (PROJECT_LIB_SOURCES irq.c) +collect (PROJECT_LIB_SOURCES shmem.c) +collect (PROJECT_LIB_SOURCES time.c) + +# vim: expandtab:ts=2:sw=2:smartindent diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/alloc.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/alloc.h new file mode 100644 index 0000000000..4200020334 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/alloc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/alloc.h + * @brief nuttx libmetal memory allocattion definitions. + */ + +#ifndef __METAL_ALLOC__H__ +#error "Include metal/alloc.h instead of metal/nuttx/alloc.h" +#endif + +#ifndef __METAL_NUTTX_ALLOC__H__ +#define __METAL_NUTTX_ALLOC__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void *metal_allocate_memory(unsigned int size) +{ + return kmm_malloc(size); +} + +static inline void metal_free_memory(void *ptr) +{ + kmm_free(ptr); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_ALLOC__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/assert.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/assert.h new file mode 100644 index 0000000000..e14cb0b112 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/assert.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file assert.h + * @brief NuttX assertion support. + */ + +#ifndef __METAL_ASSERT__H__ +#error "Include metal/assert.h instead of metal/nuttx/assert.h" +#endif + +#ifndef __METAL_NUTTX_ASSERT__H__ +#define __METAL_NUTTX_ASSERT__H__ + +#include + +/** + * @brief Assertion macro for NuttX-based applications. + * @param cond Condition to evaluate. + */ +#define metal_sys_assert(cond) DEBUGASSERT(cond) + +#endif /* __METAL_NUTTX_ASSERT__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/cache.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/cache.h new file mode 100644 index 0000000000..e3b6052423 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/cache.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/cache.h + * @brief NuttX cache operation primitives for libmetal. + */ + +#ifndef __METAL_CACHE__H__ +#error "Include metal/cache.h instead of metal/nuttx/cache.h" +#endif + +#ifndef __METAL_NUTTX_CACHE__H__ +#define __METAL_NUTTX_CACHE__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void __metal_cache_flush(void *addr, unsigned int len) +{ + up_clean_dcache((uintptr_t)addr, (uintptr_t)addr + len); +} + +static inline void __metal_cache_invalidate(void *addr, unsigned int len) +{ + up_invalidate_dcache((uintptr_t)addr, (uintptr_t)addr + len); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_CACHE__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/condition.c b/ext/hal/libmetal/libmetal/lib/system/nuttx/condition.c new file mode 100644 index 0000000000..b4c6cb019d --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/condition.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/condition.c + * @brief NuttX libmetal condition variable handling. + */ + +#include +#include + +int metal_condition_wait(struct metal_condition *cv, + metal_mutex_t *m) +{ + unsigned int flags; + + /* Check if the mutex has been acquired */ + if (!cv || !m || !metal_mutex_is_acquired(m)) + return -EINVAL; + + flags = metal_irq_save_disable(); + /* Release the mutex first. */ + metal_mutex_release(m); + nxsem_wait_uninterruptible(&cv->cond.sem); + metal_irq_restore_enable(flags); + /* Acquire the mutex again. */ + metal_mutex_acquire(m); + return 0; +} diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/condition.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/condition.h new file mode 100644 index 0000000000..22d65073b0 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/condition.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/condition.h + * @brief NuttX condition variable primitives for libmetal. + */ + +#ifndef __METAL_CONDITION__H__ +#error "Include metal/condition.h instead of metal/nuttx/condition.h" +#endif + +#ifndef __METAL_NUTTX_CONDITION__H__ +#define __METAL_NUTTX_CONDITION__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct metal_condition { + pthread_cond_t cond; +}; + +/** Static metal condition variable initialization. */ +#define METAL_CONDITION_INIT {PTHREAD_COND_INITIALIZER} + +static inline void metal_condition_init(struct metal_condition *cv) +{ + pthread_cond_init(&cv->cond, NULL); +} + +static inline int metal_condition_signal(struct metal_condition *cv) +{ + return -pthread_cond_signal(&cv->cond); +} + +static inline int metal_condition_broadcast(struct metal_condition *cv) +{ + return -pthread_cond_broadcast(&cv->cond); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_CONDITION__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/device.c b/ext/hal/libmetal/libmetal/lib/system/nuttx/device.c new file mode 100644 index 0000000000..7e66ab3357 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/device.c @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/device.c + * @brief NuttX libmetal device definitions. + */ + +#include + +int metal_generic_dev_sys_open(struct metal_device *dev) +{ + return 0; +} diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/init.c b/ext/hal/libmetal/libmetal/lib/system/nuttx/init.c new file mode 100644 index 0000000000..7677950b1a --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/init.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/init.c + * @brief NuttX libmetal initialization. + */ + +#include +#include +#include + +struct metal_state _metal; + +int metal_sys_init(const struct metal_init_params *params) +{ + int ret = metal_cntr_irq_init(); + if (ret >= 0) + ret = metal_bus_register(&metal_generic_bus); + return ret; +} + +void metal_sys_finish(void) +{ + metal_bus_unregister(&metal_generic_bus); +} diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/io.c b/ext/hal/libmetal/libmetal/lib/system/nuttx/io.c new file mode 100644 index 0000000000..8944e01fb7 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/io.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +static uint64_t metal_io_read_(struct metal_io_region *io, + unsigned long offset, + memory_order order, + int width) +{ + uint64_t value = 0; + + metal_io_block_read(io, offset, &value, width); + return value; +} + +static void metal_io_write_(struct metal_io_region *io, + unsigned long offset, + uint64_t value, + memory_order order, + int width) +{ + metal_io_block_write(io, offset, &value, width); +} + +static int metal_io_block_read_(struct metal_io_region *io, + unsigned long offset, + void *restrict dst, + memory_order order, + int len) +{ + void *va = metal_io_virt(io, offset); + + metal_cache_invalidate(va, len); + memcpy(dst, va, len); + + return len; +} + +static int metal_io_block_write_(struct metal_io_region *io, + unsigned long offset, + const void *restrict src, + memory_order order, + int len) +{ + void *va = metal_io_virt(io, offset); + + memcpy(va, src, len); + metal_cache_flush(va, len); + + return len; +} + +static void metal_io_block_set_(struct metal_io_region *io, + unsigned long offset, + unsigned char value, + memory_order order, + int len) +{ + void *va = metal_io_virt(io, offset); + + memset(va, value, len); + metal_cache_flush(va, len); +} + +static void metal_io_close_(struct metal_io_region *io) +{ +} + +static metal_phys_addr_t metal_io_offset_to_phys_(struct metal_io_region *io, + unsigned long offset) +{ + return up_addrenv_va_to_pa((char *)io->virt + offset); +} + +static unsigned long metal_io_phys_to_offset_(struct metal_io_region *io, + metal_phys_addr_t phys) +{ + return (char *)up_addrenv_pa_to_va(phys) - (char *)io->virt; +} + +static metal_phys_addr_t metal_io_phys_start_ = 0; + +static struct metal_io_region metal_io_region_ = { + .virt = NULL, + .physmap = &metal_io_phys_start_, + .size = (size_t)-1, + .page_shift = sizeof(metal_phys_addr_t) * CHAR_BIT, + .page_mask = (metal_phys_addr_t)-1, + .mem_flags = 0, + .ops = { + .read = metal_io_read_, + .write = metal_io_write_, + .block_read = metal_io_block_read_, + .block_write = metal_io_block_write_, + .block_set = metal_io_block_set_, + .close = metal_io_close_, + .offset_to_phys = metal_io_offset_to_phys_, + .phys_to_offset = metal_io_phys_to_offset_, + }, +}; + +struct metal_io_ops *metal_io_get_ops(void) +{ + return &metal_io_region_.ops; +} + +struct metal_io_region *metal_io_get_region(void) +{ + return &metal_io_region_; +} diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/io.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/io.h new file mode 100644 index 0000000000..7f6508d06a --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/io.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/io.h + * @brief NuttX specific io definitions. + */ + +#ifndef __METAL_IO__H__ +#error "Include metal/io.h instead of metal/nuttx/io.h" +#endif + +#ifndef __METAL_NUTTX_IO__H__ +#define __METAL_NUTTX_IO__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get the default global io ops. + * @return an io ops. + */ +struct metal_io_ops *metal_io_get_ops(void); + +/** + * @brief Get the default global io region. + * @return an io region. + */ +struct metal_io_region *metal_io_get_region(void); + +#ifdef METAL_INTERNAL + +/** + * @brief memory mapping for an I/O region + */ +static inline void metal_sys_io_mem_map(struct metal_io_region *io) +{ +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_IO__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/irq.c b/ext/hal/libmetal/libmetal/lib/system/nuttx/irq.c new file mode 100644 index 0000000000..00fbc6608e --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/irq.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/irq.c + * @brief NuttX libmetal irq definitions. + */ + +#include +#include +#include +#include + +unsigned int metal_irq_save_disable(void) +{ + return up_irq_save(); +} + +void metal_irq_restore_enable(unsigned int flags) +{ + up_irq_restore(flags); +} + +/* Implement the default irq controller */ +static void metal_cntr_irq_set_enable(struct metal_irq_controller *cntr, + int irq, unsigned int enable) +{ + if (irq >= 0 && irq < cntr->irq_num) { + if (enable == METAL_IRQ_ENABLE) + up_enable_irq(irq); + else + up_disable_irq(irq); + } +} + +static int metal_cntr_irq_handler(int irq, void *context, void *data) +{ + if (context != NULL) + return metal_irq_handle(data, irq); + + /* context == NULL mean unregister */ + irqchain_detach(irq, metal_cntr_irq_handler, data); + sched_kfree(data); + return 0; +} + +static int metal_cntr_irq_attach(struct metal_irq_controller *cntr, + int irq, metal_irq_handler hd, void *arg) +{ + if (irq < 0 || irq >= cntr->irq_num) + return -EINVAL; + + if (hd) { + struct metal_irq *data; + + data = metal_allocate_memory(sizeof(*data)); + if (data == NULL) + return -ENOMEM; + + data->hd = hd; + data->arg = arg; + + irq_attach(irq, metal_cntr_irq_handler, data); + } else { + unsigned int flags; + + flags = metal_irq_save_disable(); + irq_dispatch(irq, NULL); /* fake a irq request */ + metal_irq_restore_enable(flags); + } + + return 0; +} + +int metal_cntr_irq_init(void) +{ + static METAL_IRQ_CONTROLLER_DECLARE(metal_cntr_irq, + 0, NR_IRQS, + NULL, + metal_cntr_irq_set_enable, + metal_cntr_irq_attach, + NULL) + return metal_irq_register_controller(&metal_cntr_irq); +} diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/irq.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/irq.h new file mode 100644 index 0000000000..b9d5bc7c08 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/irq.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/irq.h + * @brief NuttX libmetal irq definitions. + */ + +#ifndef __METAL_IRQ__H__ +#error "Include metal/irq.h instead of metal/nuttx/irq.h" +#endif + +#ifndef __METAL_NUTTX_IRQ__H__ +#define __METAL_NUTTX_IRQ__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int metal_cntr_irq_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_IRQ__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/log.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/log.h new file mode 100644 index 0000000000..5f318c7bfc --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/log.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/log.h + * @brief NuttX libmetal log handler definition. + */ + +#ifndef __METAL_METAL_LOG__H__ +#error "Include metal/log.h instead of metal/nuttx/log.h" +#endif + +#ifndef __METAL_NUTTX_LOG__H__ +#define __METAL_NUTTX_LOG__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_LOG__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/mutex.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/mutex.h new file mode 100644 index 0000000000..e07f447db9 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/mutex.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/mutex.h + * @brief NuttX mutex primitives for libmetal. + */ + +#ifndef __METAL_MUTEX__H__ +#error "Include metal/mutex.h instead of metal/nuttx/mutex.h" +#endif + +#ifndef __METAL_NUTTX_MUTEX__H__ +#define __METAL_NUTTX_MUTEX__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef mutex_t metal_mutex_t; + +/* + * METAL_MUTEX_INIT - used for initializing an mutex elmenet in a static struct + * or global + */ +#define METAL_MUTEX_INIT(m) MUTEX_INITIALIZER +/* + * METAL_MUTEX_DEFINE - used for defining and initializing a global or + * static singleton mutex + */ +#define METAL_MUTEX_DEFINE(m) metal_mutex_t m = MUTEX_INITIALIZER + +static inline void __metal_mutex_init(metal_mutex_t *mutex) +{ + nxmutex_init(mutex); +} + +static inline void __metal_mutex_deinit(metal_mutex_t *mutex) +{ + nxmutex_destroy(mutex); +} + +static inline int __metal_mutex_try_acquire(metal_mutex_t *mutex) +{ + return nxmutex_trylock(mutex); +} + +static inline void __metal_mutex_acquire(metal_mutex_t *mutex) +{ + nxmutex_lock(mutex); +} + +static inline void __metal_mutex_release(metal_mutex_t *mutex) +{ + nxmutex_unlock(mutex); +} + +static inline int __metal_mutex_is_acquired(metal_mutex_t *mutex) +{ + return nxmutex_is_locked(mutex); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_MUTEX__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/shmem.c b/ext/hal/libmetal/libmetal/lib/system/nuttx/shmem.c new file mode 100644 index 0000000000..1db4481e2c --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/shmem.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/shmem.c + * @brief NuttX libmetal shared memory handling. + */ + +#include + +int metal_shmem_open(const char *name, size_t size, + struct metal_io_region **io) +{ + return metal_shmem_open_generic(name, size, io); +} diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/sleep.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/sleep.h new file mode 100644 index 0000000000..b15f3b6f4b --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/sleep.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/sleep.h + * @brief NuttX sleep primitives for libmetal. + */ + +#ifndef __METAL_SLEEP__H__ +#error "Include metal/sleep.h instead of metal/nuttx/sleep.h" +#endif + +#ifndef __METAL_NUTTX_SLEEP__H__ +#define __METAL_NUTTX_SLEEP__H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int __metal_sleep_usec(unsigned int usec) +{ + return nxsig_usleep(usec); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_SLEEP__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/sys.h b/ext/hal/libmetal/libmetal/lib/system/nuttx/sys.h new file mode 100644 index 0000000000..de19568b0b --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/sys.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/sys.h + * @brief NuttX system primitives for libmetal. + */ + +#ifndef __METAL_SYS__H__ +#error "Include metal/sys.h instead of metal/nuttx/sys.h" +#endif + +#ifndef __METAL_NUTTX_SYS__H__ +#define __METAL_NUTTX_SYS__H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define METAL_INIT_DEFAULTS \ +{ \ + .log_handler = (metal_log_handler)syslog, \ + .log_level = METAL_LOG_INFO, \ +} + +/** Structure of nuttx libmetal runtime state. */ +struct metal_state { + + /** Common (system independent) data. */ + struct metal_common_state common; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __METAL_NUTTX_SYS__H__ */ diff --git a/ext/hal/libmetal/libmetal/lib/system/nuttx/time.c b/ext/hal/libmetal/libmetal/lib/system/nuttx/time.c new file mode 100644 index 0000000000..bafc957877 --- /dev/null +++ b/ext/hal/libmetal/libmetal/lib/system/nuttx/time.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * @file nuttx/time.c + * @brief NuttX libmetal time handling. + */ + +#include +#include + +unsigned long long metal_get_timestamp(void) +{ + unsigned long long t = 0; + struct timespec tp; + int r; + + r = clock_systimespec(&tp); + if (!r) { + t = (unsigned long long)tp.tv_sec * NSEC_PER_SEC; + t += tp.tv_nsec; + } + return t; +} diff --git a/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.c b/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.c index 5b368484fc..8cf38fedc4 100644 --- a/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.c +++ b/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.c @@ -17,17 +17,19 @@ extern void metal_generic_default_poll(void); int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m) { - metal_mutex_t *tmpm = 0; + uintptr_t tmpmptr = 0, mptr = (uintptr_t)m; int v; unsigned int flags; /* Check if the mutex has been acquired */ - if (!cv || !m || !metal_mutex_is_acquired(m)) + if (!cv || !m || !metal_mutex_is_acquired(m)) { return -EINVAL; + } - if (!atomic_compare_exchange_strong(&cv->m, &tmpm, m)) { - if (m != tmpm) + if (!atomic_compare_exchange_strong(&cv->mptr, &tmpmptr, mptr)) { + if (tmpmptr != mptr) { return -EINVAL; + } } v = atomic_load(&cv->v); diff --git a/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.h b/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.h index b9f34ad3da..50dcf1abc1 100644 --- a/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.h +++ b/ext/hal/libmetal/libmetal/lib/system/zephyr/condition.h @@ -26,21 +26,21 @@ extern "C" { #endif struct metal_condition { - metal_mutex_t *m; /**< mutex. - The condition variable is attached to - this mutex when it is waiting. - It is also used to check correctness - in case there are multiple waiters. */ + atomic_uintptr_t mptr; /**< mutex pointer. + The condition variable is attached to + this mutex when it is waiting. + It is also used to check correctness + in case there are multiple waiters. */ atomic_int v; /**< condition variable value. */ }; /** Static metal condition variable initialization. */ -#define METAL_CONDITION_INIT { NULL, ATOMIC_VAR_INIT(0) } +#define METAL_CONDITION_INIT { ATOMIC_VAR_INIT(0), ATOMIC_VAR_INIT(0) } static inline void metal_condition_init(struct metal_condition *cv) { - cv->m = NULL; + atomic_init(&cv->mptr, 0); atomic_init(&cv->v, 0); } diff --git a/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.c b/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.c index dbd2b989fd..38dd6294ee 100644 --- a/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.c +++ b/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.c @@ -17,221 +17,6 @@ #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 */ -}; - -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) -{ - struct metal_irq_desc *irq_p = NULL; - struct metal_irq_hddesc *hdl_p; - struct metal_list *node; - unsigned int irq_flags_save; - - if (irq < 0) { - metal_log(METAL_LOG_ERROR, - "%s: irq %d need to be a positive number\n", - __func__, irq); - return -EINVAL; - } - - if ((drv_id == NULL) || (hd == NULL)) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n", - __func__, irq); - 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; - - /* 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 found and drv_id not used, get out of metal_list_for_each */ - break; - } - } - - /* 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); -} - -int metal_irq_unregister(int irq, - metal_irq_handler hd, - struct metal_device *dev, - void *drv_id) -{ - struct metal_irq_desc *irq_p; - struct metal_list *node; - - if (irq < 0) { - metal_log(METAL_LOG_ERROR, "%s: irq %d need to be a positive number\n", - __func__, irq); - 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); - return 0; - } - } - - metal_log(METAL_LOG_DEBUG, "%s: No matching IRQ entry\n", __func__); - - metal_mutex_release(&_irqs.irq_lock); - return -ENOENT; -} unsigned int metal_irq_save_disable(void) { @@ -243,38 +28,3 @@ void metal_irq_restore_enable(unsigned int flags) irq_unlock(flags); } -void metal_irq_enable(unsigned int vector) -{ - irq_enable(vector); -} - -void metal_irq_disable(unsigned int vector) -{ - irq_disable(vector); -} - -/** - * @brief default handler - */ -void metal_irq_isr(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); - } - } - } -} diff --git a/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.h b/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.h index 3937a6111d..7f317943bd 100644 --- a/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.h +++ b/ext/hal/libmetal/libmetal/lib/system/zephyr/irq.h @@ -20,13 +20,6 @@ extern "C" { #endif -/** - * @brief default interrupt handler - * @param[in] vector interrupt vector - */ -void metal_irq_isr(unsigned int vector); - - #ifdef __cplusplus } #endif diff --git a/ext/hal/libmetal/libmetal/lib/system/zephyr/time.c b/ext/hal/libmetal/libmetal/lib/system/zephyr/time.c index 67e040ac22..3458e84131 100644 --- a/ext/hal/libmetal/libmetal/lib/system/zephyr/time.c +++ b/ext/hal/libmetal/libmetal/lib/system/zephyr/time.c @@ -12,8 +12,10 @@ #include #include +extern volatile u64_t _sys_clock_tick_count; + unsigned long long metal_get_timestamp(void) { - return (unsigned long long)z_tick_get(); + return (unsigned long long)_sys_clock_tick_count; } diff --git a/ext/hal/libmetal/libmetal/lib/utilities.h b/ext/hal/libmetal/libmetal/lib/utilities.h index eb540d2f0a..ce5aaeb0fa 100644 --- a/ext/hal/libmetal/libmetal/lib/utilities.h +++ b/ext/hal/libmetal/libmetal/lib/utilities.h @@ -13,6 +13,7 @@ #define __METAL_UTILITIES__H__ #include +#include #include #ifdef __cplusplus @@ -69,7 +70,7 @@ extern "C" { #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_BITS_PER_ULONG (CHAR_BIT * sizeof(unsigned long)) #define metal_bit(bit) (1UL << (bit)) @@ -83,8 +84,8 @@ static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit) 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)); + 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) @@ -113,7 +114,7 @@ metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start, #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))) + (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, @@ -130,7 +131,7 @@ metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start, #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))) + (bit) = metal_bitmap_next_clear_bit((bitmap), (bit + 1), (max))) static inline unsigned long metal_log2(unsigned long in) {