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 <kumar.gala@linaro.org>
This commit is contained in:
parent
342689057c
commit
11cedc6c49
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
#if defined(HAVE_STDATOMIC_H) && !defined(__STDC_NO_ATOMICS__) && \
|
||||
!defined(__cplusplus)
|
||||
# include <stdint.h>
|
||||
# include <stdatomic.h>
|
||||
#elif defined(__cplusplus)
|
||||
# include <atomic>
|
||||
#elif defined(__GNUC__)
|
||||
# include <metal/compiler/gcc/atomic.h>
|
||||
#else
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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
|
||||
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,6 +180,7 @@ 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)
|
||||
{
|
||||
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);
|
||||
|
@ -180,6 +190,9 @@ metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys)
|
|||
offset += io->page_mask + 1;
|
||||
} while (offset < io->size);
|
||||
return METAL_BAD_OFFSET;
|
||||
}
|
||||
|
||||
return (*io->ops.phys_to_offset)(io, phys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
138
ext/hal/libmetal/libmetal/lib/irq.c
Normal file
138
ext/hal/libmetal/libmetal/lib/irq.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Xilinx Inc. and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/irq_controller.h>
|
||||
#include <metal/list.h>
|
||||
#include <metal/utilities.h>
|
||||
|
||||
/** 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);
|
||||
}
|
|
@ -19,6 +19,7 @@ extern "C" {
|
|||
/** \defgroup irq Interrupt Handling Interfaces
|
||||
* @{ */
|
||||
|
||||
#include <metal/list.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** IRQ handled status */
|
||||
|
@ -28,52 +29,38 @@ extern "C" {
|
|||
/**
|
||||
* @brief type of interrupt handler
|
||||
* @param[in] irq interrupt id
|
||||
* @param[in] priv private data
|
||||
* @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
|
||||
|
|
131
ext/hal/libmetal/libmetal/lib/irq_controller.h
Normal file
131
ext/hal/libmetal/libmetal/lib/irq_controller.h
Normal file
|
@ -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 <metal/irq.h>
|
||||
#include <metal/list.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/** 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__ */
|
|
@ -0,0 +1,3 @@
|
|||
collect (PROJECT_LIB_HEADERS cpu.h)
|
||||
|
||||
# vim: expandtab:ts=2:sw=2:smartindent
|
25
ext/hal/libmetal/libmetal/lib/processor/ceva/cpu.h
Normal file
25
ext/hal/libmetal/libmetal/lib/processor/ceva/cpu.h
Normal file
|
@ -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__ */
|
|
@ -0,0 +1,3 @@
|
|||
collect (PROJECT_LIB_HEADERS cpu.h)
|
||||
|
||||
# vim: expandtab:ts=2:sw=2:smartindent
|
17
ext/hal/libmetal/libmetal/lib/processor/csky/cpu.h
Normal file
17
ext/hal/libmetal/libmetal/lib/processor/csky/cpu.h
Normal file
|
@ -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__ */
|
|
@ -0,0 +1,3 @@
|
|||
collect (PROJECT_LIB_HEADERS cpu.h)
|
||||
|
||||
# vim: expandtab:ts=2:sw=2:smartindent
|
17
ext/hal/libmetal/libmetal/lib/processor/riscv/cpu.h
Normal file
17
ext/hal/libmetal/libmetal/lib/processor/riscv/cpu.h
Normal file
|
@ -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__ */
|
101
ext/hal/libmetal/libmetal/lib/softirq.c
Normal file
101
ext/hal/libmetal/libmetal/lib/softirq.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2019, Xilinx Inc. and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <metal/atomic.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/irq_controller.h>
|
||||
#include <metal/log.h>
|
||||
#include <metal/sys.h>
|
||||
#include <metal/softirq.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
68
ext/hal/libmetal/libmetal/lib/softirq.h
Normal file
68
ext/hal/libmetal/libmetal/lib/softirq.h
Normal file
|
@ -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 <metal/irq.h>
|
||||
|
||||
/**
|
||||
* @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__ */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,220 +18,6 @@
|
|||
#include <metal/utilities.h>
|
||||
#include <metal/alloc.h>
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
collect (PROJECT_LIB_HEADERS sys.h)
|
||||
|
||||
collect (PROJECT_LIB_SOURCES irq.c)
|
||||
|
||||
# vim: expandtab:ts=2:sw=2:smartindent
|
|
@ -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 <errno.h>
|
||||
#include <metal/irq_controller.h>
|
||||
#include <metal/sys.h>
|
||||
#include <metal/log.h>
|
||||
#include <metal/mutex.h>
|
||||
#include <metal/list.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/alloc.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h"
|
||||
#endif
|
||||
|
||||
#include <metal/system/@PROJECT_SYSTEM@/xlnx_common/sys.h>
|
||||
#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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h"
|
||||
#endif
|
||||
|
||||
#include <metal/system/@PROJECT_SYSTEM@/xlnx_common/sys.h>
|
||||
#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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#error "Include metal/sys.h instead of metal/freertos/@PROJECT_MACHINE@/sys.h"
|
||||
#endif
|
||||
|
||||
#include <metal/system/@PROJECT_SYSTEM@/xlnx_common/sys.h>
|
||||
#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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct metal_condition {
|
||||
metal_mutex_t *m; /**< mutex.
|
||||
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
|
||||
|
@ -37,11 +37,11 @@ struct metal_condition {
|
|||
};
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,220 +18,6 @@
|
|||
#include <metal/utilities.h>
|
||||
#include <metal/alloc.h>
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
if (flags)
|
||||
asm volatile(" mfs %0, rmsr \n"
|
||||
" or %0, %0, %1 \n"
|
||||
" mts rmsr, %0 \n"
|
||||
: "=r"(tmp)
|
||||
: "r"(~flags)
|
||||
: "r"(flags)
|
||||
: "memory");
|
||||
}
|
||||
#endif /* XPAR_MICROBLAZE_USE_MSR_INSTR */
|
||||
|
||||
static void sys_irq_change(unsigned int vector, int is_enable)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h"
|
||||
#endif
|
||||
|
||||
#include <metal/system/@PROJECT_SYSTEM@/xlnx_common/sys.h>
|
||||
|
||||
#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);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
collect (PROJECT_LIB_HEADERS sys.h)
|
||||
|
||||
collect (PROJECT_LIB_SOURCES irq.c)
|
||||
|
||||
# vim: expandtab:ts=2:sw=2:smartindent
|
|
@ -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 <errno.h>
|
||||
#include <metal/irq_controller.h>
|
||||
#include <metal/sys.h>
|
||||
#include <metal/log.h>
|
||||
#include <metal/mutex.h>
|
||||
#include <metal/list.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/alloc.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h"
|
||||
#endif
|
||||
|
||||
#include <metal/system/@PROJECT_SYSTEM@/xlnx_common/sys.h>
|
||||
#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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#error "Include metal/sys.h instead of metal/generic/@PROJECT_MACHINE@/sys.h"
|
||||
#endif
|
||||
|
||||
#include <metal/system/@PROJECT_SYSTEM@/xlnx_common/sys.h>
|
||||
#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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <metal/system/@PROJECT_SYSTEM@/xlnx_common/sys.h>
|
||||
#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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct metal_condition {
|
||||
metal_mutex_t *m; /**< mutex.
|
||||
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
|
||||
|
@ -40,11 +40,12 @@ struct metal_condition {
|
|||
};
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <sched.h>
|
||||
#include <metal/device.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/irq_controller.h>
|
||||
#include <metal/sys.h>
|
||||
#include <metal/mutex.h>
|
||||
#include <metal/list.h>
|
||||
|
@ -20,203 +21,93 @@
|
|||
#include <metal/alloc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 */
|
||||
};
|
||||
|
||||
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. */
|
||||
|
||||
int irq_reg_fd; /**< irqs registration notification file
|
||||
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 */
|
||||
|
||||
metal_mutex_t irq_lock; /**< irq handling lock */
|
||||
static bool irq_handling_stop; /**< stop interrupts handling */
|
||||
|
||||
unsigned int irq_state; /**< global irq handling state */
|
||||
static pthread_t irq_pthread; /**< irq handling thread id */
|
||||
|
||||
pthread_t irq_pthread; /**< irq handling thread id */
|
||||
};
|
||||
/**< Indicate which IRQ is enabled */
|
||||
static unsigned long
|
||||
irqs_enabled[metal_div_round_up(MAX_IRQS, METAL_BITS_PER_ULONG)];
|
||||
|
||||
struct metal_irqs_state _irqs;
|
||||
static struct metal_irq irqs[MAX_IRQS]; /**< Linux IRQs array */
|
||||
|
||||
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;
|
||||
/* Static functions */
|
||||
static void metal_linux_irq_set_enable(struct metal_irq_controller *irq_cntr,
|
||||
int irq, unsigned int state);
|
||||
|
||||
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) {
|
||||
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,7 +169,7 @@ 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)
|
||||
|
@ -286,26 +177,21 @@ static void *metal_linux_irq_handling(void *args)
|
|||
"%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)
|
||||
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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,22 @@
|
|||
#endif
|
||||
|
||||
#ifndef __METAL_LINUX_IRQ__H__
|
||||
#ifdef METAL_INTERNAL
|
||||
|
||||
#include <metal/device.h>
|
||||
|
||||
/**
|
||||
* @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__ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
20
ext/hal/libmetal/libmetal/lib/system/nuttx/CMakeLists.txt
Normal file
20
ext/hal/libmetal/libmetal/lib/system/nuttx/CMakeLists.txt
Normal file
|
@ -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
|
39
ext/hal/libmetal/libmetal/lib/system/nuttx/alloc.h
Normal file
39
ext/hal/libmetal/libmetal/lib/system/nuttx/alloc.h
Normal file
|
@ -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 <nuttx/kmalloc.h>
|
||||
|
||||
#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__ */
|
27
ext/hal/libmetal/libmetal/lib/system/nuttx/assert.h
Normal file
27
ext/hal/libmetal/libmetal/lib/system/nuttx/assert.h
Normal file
|
@ -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 <assert.h>
|
||||
|
||||
/**
|
||||
* @brief Assertion macro for NuttX-based applications.
|
||||
* @param cond Condition to evaluate.
|
||||
*/
|
||||
#define metal_sys_assert(cond) DEBUGASSERT(cond)
|
||||
|
||||
#endif /* __METAL_NUTTX_ASSERT__H__ */
|
39
ext/hal/libmetal/libmetal/lib/system/nuttx/cache.h
Normal file
39
ext/hal/libmetal/libmetal/lib/system/nuttx/cache.h
Normal file
|
@ -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 <nuttx/arch.h>
|
||||
|
||||
#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__ */
|
32
ext/hal/libmetal/libmetal/lib/system/nuttx/condition.c
Normal file
32
ext/hal/libmetal/libmetal/lib/system/nuttx/condition.c
Normal file
|
@ -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 <metal/condition.h>
|
||||
#include <metal/irq.h>
|
||||
|
||||
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;
|
||||
}
|
51
ext/hal/libmetal/libmetal/lib/system/nuttx/condition.h
Normal file
51
ext/hal/libmetal/libmetal/lib/system/nuttx/condition.h
Normal file
|
@ -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 <pthread.h>
|
||||
|
||||
#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__ */
|
17
ext/hal/libmetal/libmetal/lib/system/nuttx/device.c
Normal file
17
ext/hal/libmetal/libmetal/lib/system/nuttx/device.c
Normal file
|
@ -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 <metal/device.h>
|
||||
|
||||
int metal_generic_dev_sys_open(struct metal_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
29
ext/hal/libmetal/libmetal/lib/system/nuttx/init.c
Normal file
29
ext/hal/libmetal/libmetal/lib/system/nuttx/init.c
Normal file
|
@ -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 <metal/device.h>
|
||||
#include <metal/irq.h>
|
||||
#include <metal/sys.h>
|
||||
|
||||
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);
|
||||
}
|
116
ext/hal/libmetal/libmetal/lib/system/nuttx/io.c
Normal file
116
ext/hal/libmetal/libmetal/lib/system/nuttx/io.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Pinecone Inc. and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <metal/cache.h>
|
||||
#include <metal/io.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
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_;
|
||||
}
|
49
ext/hal/libmetal/libmetal/lib/system/nuttx/io.h
Normal file
49
ext/hal/libmetal/libmetal/lib/system/nuttx/io.h
Normal file
|
@ -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__ */
|
87
ext/hal/libmetal/libmetal/lib/system/nuttx/irq.c
Normal file
87
ext/hal/libmetal/libmetal/lib/system/nuttx/irq.c
Normal file
|
@ -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 <errno.h>
|
||||
#include <metal/irq_controller.h>
|
||||
#include <metal/alloc.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
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);
|
||||
}
|
29
ext/hal/libmetal/libmetal/lib/system/nuttx/irq.h
Normal file
29
ext/hal/libmetal/libmetal/lib/system/nuttx/irq.h
Normal file
|
@ -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__ */
|
29
ext/hal/libmetal/libmetal/lib/system/nuttx/log.h
Normal file
29
ext/hal/libmetal/libmetal/lib/system/nuttx/log.h
Normal file
|
@ -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 <syslog.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __METAL_NUTTX_LOG__H__ */
|
72
ext/hal/libmetal/libmetal/lib/system/nuttx/mutex.h
Normal file
72
ext/hal/libmetal/libmetal/lib/system/nuttx/mutex.h
Normal file
|
@ -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 <nuttx/mutex.h>
|
||||
|
||||
#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__ */
|
18
ext/hal/libmetal/libmetal/lib/system/nuttx/shmem.c
Normal file
18
ext/hal/libmetal/libmetal/lib/system/nuttx/shmem.c
Normal file
|
@ -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 <metal/shmem.h>
|
||||
|
||||
int metal_shmem_open(const char *name, size_t size,
|
||||
struct metal_io_region **io)
|
||||
{
|
||||
return metal_shmem_open_generic(name, size, io);
|
||||
}
|
36
ext/hal/libmetal/libmetal/lib/system/nuttx/sleep.h
Normal file
36
ext/hal/libmetal/libmetal/lib/system/nuttx/sleep.h
Normal file
|
@ -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 <nuttx/signal.h>
|
||||
|
||||
#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__ */
|
40
ext/hal/libmetal/libmetal/lib/system/nuttx/sys.h
Normal file
40
ext/hal/libmetal/libmetal/lib/system/nuttx/sys.h
Normal file
|
@ -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__ */
|
27
ext/hal/libmetal/libmetal/lib/system/nuttx/time.c
Normal file
27
ext/hal/libmetal/libmetal/lib/system/nuttx/time.c
Normal file
|
@ -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 <metal/time.h>
|
||||
#include <nuttx/clock.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -17,18 +17,20 @@ 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);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct metal_condition {
|
||||
metal_mutex_t *m; /**< mutex.
|
||||
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
|
||||
|
@ -36,11 +36,11 @@ struct metal_condition {
|
|||
};
|
||||
|
||||
/** 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,221 +17,6 @@
|
|||
#include <metal/list.h>
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/alloc.h>
|
||||
#include <irq.h>
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
#include <metal/time.h>
|
||||
#include <sys_clock.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define __METAL_UTILITIES__H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <metal/assert.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue