diff --git a/kernel/include/bsp/drivers/dma/gpdma.h b/kernel/include/bsp/drivers/dma/gpdma.h index 1df04f59..018024d7 100644 --- a/kernel/include/bsp/drivers/dma/gpdma.h +++ b/kernel/include/bsp/drivers/dma/gpdma.h @@ -16,133 +16,22 @@ #include #include -#include +#include /** * @brief generic state value definition for a DMA channel * * This enumerate aliasing UAPI to keep unified gpdma_ prefixed content at driver level - * @see dma_chan_state_t definition for corresponding content. + * @see dma_chan_state_t definition in uapi/dma.h for corresponding content. */ -typedef dma_chan_state_t gpdma_chan_state_t; /** - * @enum gpdma_chan_trigger - * - * @brief type of DMA tranfer triggers request. This enum is made for bitfield manipulation, - * allowing multitple triggers at the same time if needed. - */ -typedef enum gpdma_chan_int { - GPDMA_INT_TC = 1, /**< DMA channel trigger on transfer complete */ - GPDMA_INT_HT = 2, /**< DMA channel trigger on half transfer and transfer complete */ - GPDMA_INT_ERROR = 4, /**< triggers on DMA transfer or config error, get status for complete information */ -} gpdma_chan_int_t; - -/** - * @brief generic DMA streams and channel status - * - * list DMA-generic status types that can be used by upper layer, - * whatever the DMA controller and driver is. - */ -typedef struct __PACKED gpdma_chan_status { - uint32_t state: 3; - uint32_t half_reached: 1; - uint32_t completed: 1; - uint32_t reserved: 2; -} gpdma_chan_status_t; - -/** - * @enum gpdma_transfer_type - * - * @brief possible DMA transfer types - */ -typedef enum gpdma_transfer_type { - GPDMA_TRANSFER_MEMORY_TO_DEVICE = 0, - GPDMA_TRANSFER_DEVICE_TO_MEMORY = 1, - GPDMA_TRANSFER_MEMORY_TO_MEMORY = 2, - GPDMA_TRANSFER_DEVICE_TO_DEVICE = 3, -} gpdma_transfer_type_t; - -/** - * @enum gpdma_transfer_mode - * - * @brief possible DMA transfer mode - * - * This enumerate behaves as a bitfield, allowing multiple values to be set - * at the same time. - */ -typedef enum gpdma_transfer_mode { - GPDMA_TRANSFER_MODE_INCREMENT_NONE = 0, /**< no increment at all of src and dest */ - GPDMA_TRANSFER_MODE_INCREMENT_SRC = 1, /**< increment src at each burst */ - GPDMA_TRANSFER_MODE_INCREMENT_DEST = 2, /**< increment dest at each burst */ -} gpdma_transfer_mode_t; - -/** - * @enum gpdma_beat_len - * - * @brief possible DMA single manipulation data len (denoted beat) - * the beat len, associated to the transfer mode and the burst number defined how the - * DMA behaves. - * - * This defines the way burst works and impact the increment calculation. This - * is defined for both source and dest and may differ, allowing differenciated increment - */ -typedef enum gpdma_beat_len { - GPDMA_BEAT_LEN_BYTE = 0, /**< data len to manipulate is a byte */ - GPDMA_BEAT_LEN_HALFWORD = 1, /**< data len to manipulate is a half word */ - GPDMA_BEAT_LEN_WORD = 2, /**< data len to manipulate is a word */ -} gpdma_beat_len_t; - -/** - * @enum gpdma_priority - * - * @brief DMA stream priority in comparison with others - */ -typedef enum gpdma_priority { - GPDMA_PRIORITY_LOW = 0, - GPDMA_PRIORITY_MEDIUM = 1, - GPDMA_PRIORITY_HIGH = 2, - GPDMA_PRIORITY_VERY_HIGH = 3, -} gpdma_priority_t; - -/** - * @struct gpdma_stream_cfg - * - * @brief DMA transfer definition - * - * Depending on the hardware, the notion of channels and stream may vary, - * as sometime the controller hold stream with various channels configuration, - * or hold channels with various stream (request type) configuration. - * - * In order to avoid any difficulties at upper layer: - * - a channel is always denoted 'channel' - * - a stream can be a request - * This couple is always defined in the device-tree file, so that it - * properly identify a configuration, meaning that the DMA controller - * configuration is correctly shared between requester at configure time. - * - * This means that whatever the driver is, the correct selection of a working - * stream/channel configuration is fixed and is not automatically detected at - * run time. + * NOTE: the gpdma_stream_cfg_t is a shared data content with user interface + * the goal is to allow easy user access to stream config through a dedicated syscall, + * without any manipulation of the device tree. + * This structure is arch-independent and IP-independent. + * @see uapi/types.h for the structure definition. */ -typedef struct gpdma_stream_cfg { - uint16_t channel; /**< channel identifier */ - uint16_t stream; /**< request identifier */ - uint16_t controller; /**< controller identifier */ - uint16_t transfer_type; /**< type of transfer, @see gpdma_transfer_type */ - size_t source; /**< source address, for memory-to-x requests */ - size_t dest; /**< destination address, for x-to-memory requests */ - size_t transfer_len; /**< overall steam transfer length in bytes */ - bool circular_source; /**< make DMA stream restart from initial source addr at trigger time */ - bool circular_dest; /**< make DMA stream restart from initial dest addr at trigger time */ - uint8_t interrupts; /**< interrupt requested, @see gpdma_chan_int */ - bool is_triggered; /**< specify if the DMA stream is triggered or not */ - uint8_t trigger; /**< trigger id that (re)arm DMA data transfer */ - uint8_t priority; /**< DMA stream priority in comparison with others, @see gpdma_priority */ - uint8_t transfer_mode; /**< DMA transfer mode, @see gpdma_transfer_mode*/ - uint8_t src_beat_len; /**< source burst length @see gpdma_beat_len */ - uint8_t dest_beat_len; /**< source burst length @see gpdma_beat_len */ -} gpdma_stream_cfg_t; /** * @brief probe given GPDMA controller identifier diff --git a/kernel/include/sentry/managers/dma.h b/kernel/include/sentry/managers/dma.h index 5a92af33..e147fdeb 100644 --- a/kernel/include/sentry/managers/dma.h +++ b/kernel/include/sentry/managers/dma.h @@ -5,8 +5,8 @@ #define SENTRY_MANAGERS_DMA_H #include -#include #include +#include #include #include @@ -39,16 +39,10 @@ kstatus_t mgr_dma_get_handle(uint32_t label, dmah_t * handle); kstatus_t mgr_dma_get_dmah_from_interrupt(uint16_t IRQn, dmah_t *dmah); -kstatus_t mgr_dma_get_state(dmah_t d, dma_chan_state_t *state); +kstatus_t mgr_dma_get_state(dmah_t d, gpdma_chan_state_t *state); #endif/* HAS_GPDMA */ -/** - * Iterate over the device list, starting with id==id. - * Return the devinfo of the current id increment, or set devinfo to NULL and return K_ERROR_NOENT if - * the dev list walk is terminated - */ -//kstatus_t mgr_dma_walk(const devinfo_t **devinfo, uint8_t id); #ifdef __cplusplus } /* extern "C" */ diff --git a/kernel/include/sentry/managers/task.h b/kernel/include/sentry/managers/task.h index 08a19090..d2a1432f 100644 --- a/kernel/include/sentry/managers/task.h +++ b/kernel/include/sentry/managers/task.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -182,8 +183,8 @@ kstatus_t mgr_task_autotest(void); #endif #if CONFIG_HAS_GPDMA -kstatus_t mgr_task_push_dma_event(taskh_t target, dmah_t dma_stream, dma_chan_state_t dma_event); -kstatus_t mgr_task_load_dma_event(taskh_t target, dmah_t *dma_stream, dma_chan_state_t *dma_event); +kstatus_t mgr_task_push_dma_event(taskh_t target, dmah_t dma_stream, gpdma_chan_state_t dma_event); +kstatus_t mgr_task_load_dma_event(taskh_t target, dmah_t *dma_stream, gpdma_chan_state_t *dma_event); #endif /* specialized event pushing API, do not use directly but instead Generic below */ diff --git a/kernel/src/managers/dma/dma-dt.h.in b/kernel/src/managers/dma/dma-dt.h.in index 14b63b10..bc7f0c2d 100644 --- a/kernel/src/managers/dma/dma-dt.h.in +++ b/kernel/src/managers/dma/dma-dt.h.in @@ -8,7 +8,7 @@ * @file Sentry DMA streams access API */ #include -#include +#include /** * @brief Manager level stream configuration diff --git a/kernel/src/managers/dma/dma.c b/kernel/src/managers/dma/dma.c index 05778023..de92f28f 100644 --- a/kernel/src/managers/dma/dma.c +++ b/kernel/src/managers/dma/dma.c @@ -77,6 +77,21 @@ static dma_stream_config_t *mgr_dma_get_config(const dmah_t dmah) return cfg; } +static kstatus_t mgr_dma_get_info(const dmah_t dmah, gpdma_stream_cfg_t const ** infos) +{ + kstatus_t status = K_ERROR_INVPARAM; + if (unlikely(infos == NULL)) { + goto end; + } + for (size_t streamid = 0; streamid < STREAM_LIST_SIZE; ++streamid) { + if (stream_config[streamid].handle == dmah) { + *infos = &stream_config[streamid].meta->config; + goto end; + } + } +end: + return status; +} kstatus_t mgr_dma_watchdog(void) { @@ -149,7 +164,7 @@ kstatus_t mgr_dma_get_owner(dmah_t d, taskh_t *owner) /*@ requires \valid(state); */ -kstatus_t mgr_dma_get_state(dmah_t d, dma_chan_state_t *state) +kstatus_t mgr_dma_get_state(dmah_t d, gpdma_chan_state_t *state) { kstatus_t status = K_ERROR_INVPARAM; /*@ assert \valid(state); */ diff --git a/kernel/src/managers/dma/dma.h b/kernel/src/managers/dma/dma.h index 1460ae96..14d21529 100644 --- a/kernel/src/managers/dma/dma.h +++ b/kernel/src/managers/dma/dma.h @@ -31,7 +31,7 @@ typedef struct dma_stream_config { dmah_t handle; /**< associated DMA handle (opaque format) */ taskh_t owner; /**< stream owner task handle */ dma_stream_state_t state; /**< DMA stream state (configuration relative state) */ - dma_chan_state_t status; /**< DMA channel status, stream-relative dynamic */ + gpdma_chan_state_t status; /**< DMA channel status, stream-relative dynamic */ } dma_stream_config_t; diff --git a/kernel/src/managers/interrupt/interrupt.c b/kernel/src/managers/interrupt/interrupt.c index 60457968..9839eaff 100644 --- a/kernel/src/managers/interrupt/interrupt.c +++ b/kernel/src/managers/interrupt/interrupt.c @@ -79,7 +79,7 @@ static inline stack_frame_t *devisr_handler(stack_frame_t *frame, int IRQn) * * This function is agnostic of the DMA vent properties only push the event to the target task input FIFO. */ -static inline void dma_push_and_schedule(taskh_t owner, dmah_t handle, dma_chan_state_t event) +static inline void dma_push_and_schedule(taskh_t owner, dmah_t handle, gpdma_chan_state_t event) { job_state_t owner_state; @@ -109,7 +109,7 @@ static inline stack_frame_t *dmaisr_handler(stack_frame_t *frame, int IRQn) { dmah_t dma; taskh_t owner = 0; - dma_chan_state_t event; + gpdma_chan_state_t event; /* get the dmah owning the interrupt */ if (unlikely(mgr_dma_get_dmah_from_interrupt(IRQn, &dma) != K_STATUS_OKAY)) { diff --git a/kernel/src/managers/task/task_core.c b/kernel/src/managers/task/task_core.c index 72880732..a23c1ff5 100644 --- a/kernel/src/managers/task/task_core.c +++ b/kernel/src/managers/task/task_core.c @@ -629,7 +629,7 @@ kstatus_t mgr_task_load_ipc_event(taskh_t context) * @param[in] dma_event: DMA stream event that has just risen * */ -kstatus_t mgr_task_push_dma_event(taskh_t target, dmah_t dma_stream, dma_chan_state_t dma_event) +kstatus_t mgr_task_push_dma_event(taskh_t target, dmah_t dma_stream, gpdma_chan_state_t dma_event) { kstatus_t status = K_ERROR_INVPARAM; task_t * tsk = task_get_from_handle(target); @@ -657,7 +657,7 @@ kstatus_t mgr_task_push_dma_event(taskh_t target, dmah_t dma_stream, dma_chan_st /** * @fn mgr_task_load_dma_event - get back firstly pushed DMA event not yet fetched */ -kstatus_t mgr_task_load_dma_event(taskh_t context, dmah_t *handle, dma_chan_state_t *event) +kstatus_t mgr_task_load_dma_event(taskh_t context, dmah_t *handle, gpdma_chan_state_t *event) { kstatus_t status = K_ERROR_NOENT; diff --git a/kernel/src/syscalls/sysgate_waitforevent.c b/kernel/src/syscalls/sysgate_waitforevent.c index c3145b6f..53118a65 100644 --- a/kernel/src/syscalls/sysgate_waitforevent.c +++ b/kernel/src/syscalls/sysgate_waitforevent.c @@ -6,9 +6,10 @@ #include #include #include +#include -static inline void gate_waitforevent_populate_dma(taskh_t current, dmah_t dma, dma_chan_state_t event) +static inline void gate_waitforevent_populate_dma(taskh_t current, dmah_t dma, gpdma_chan_state_t event) { task_meta_t const *meta; uint8_t *svc; @@ -92,7 +93,7 @@ stack_frame_t *gate_waitforevent(stack_frame_t *frame, #if CONFIG_HAS_GPDMA if (mask & EVENT_TYPE_DMA) { dmah_t dmah; - dma_chan_state_t event; + gpdma_chan_state_t event; if (mgr_task_load_dma_event(current, &dmah, &event) == K_STATUS_OKAY) { gate_waitforevent_populate_dma(current, dmah, event); mgr_task_set_sysreturn(current, STATUS_OK); diff --git a/uapi/include/uapi/device.h b/uapi/include/uapi/device.h index 8890bad5..bfe6df26 100644 --- a/uapi/include/uapi/device.h +++ b/uapi/include/uapi/device.h @@ -4,6 +4,10 @@ #ifndef UAPI_DEVICE_H #define UAPI_DEVICE_H +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + #include #include #include @@ -63,6 +67,8 @@ typedef struct shminfo { size_t size; /**< for mappable devices, mapped size */ } shminfo_t; - +#ifdef __cplusplus +} /* extern "C" */ +#endif // __cplusplus #endif/*UAPI_DEVICE_H*/ diff --git a/uapi/include/uapi/dma.h b/uapi/include/uapi/dma.h new file mode 100644 index 00000000..79e41770 --- /dev/null +++ b/uapi/include/uapi/dma.h @@ -0,0 +1,166 @@ +// SPDX-FileCopyrightText: 2023 Ledger SAS +// SPDX-License-Identifier: Apache-2.0 + +#ifndef UAPI_DMA_H +#define UAPI_DMA_H + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include +#include +#include +#include + + +/** + * @file DMA-related types declaration + * + * In order to properly parse various infos the kernel can deliver to user-space + * this header declare various types that are DMA related. These types are + * used by both kernel and userspace in order to avoid any divergence. + * +*/ + +/** + * @enum gpdma_chan_trigger + * + * @brief type of DMA tranfer triggers request. This enum is made for bitfield manipulation, + * allowing multitple triggers at the same time if needed. + */ +typedef enum gpdma_chan_int { + GPDMA_INT_TC = 1, /**< DMA channel trigger on transfer complete */ + GPDMA_INT_HT = 2, /**< DMA channel trigger on half transfer and transfer complete */ + GPDMA_INT_ERROR = 4, /**< triggers on DMA transfer or config error, get status for complete information */ +} gpdma_chan_int_t; + +/** + * @brief generic DMA streams and channel status + * + * list DMA-generic status types that can be used by upper layer, + * whatever the DMA controller and driver is. + */ +typedef struct __attribute__((packed)) gpdma_chan_status { + uint32_t state: 3; + uint32_t half_reached: 1; + uint32_t completed: 1; + uint32_t reserved: 3; +} gpdma_chan_status_t; + +static_assert(sizeof(gpdma_chan_status_t) == sizeof(uint8_t), "O,vamod gpdma_chan_status_t size"); + +/** + * @enum gpdma_transfer_type + * + * @brief possible DMA transfer types + */ +typedef enum gpdma_transfer_type { + GPDMA_TRANSFER_MEMORY_TO_DEVICE = 0, + GPDMA_TRANSFER_DEVICE_TO_MEMORY = 1, + GPDMA_TRANSFER_MEMORY_TO_MEMORY = 2, + GPDMA_TRANSFER_DEVICE_TO_DEVICE = 3, +} gpdma_transfer_type_t; + +/** + * @enum gpdma_transfer_mode + * + * @brief possible DMA transfer mode + * + * This enumerate behaves as a bitfield, allowing multiple values to be set + * at the same time. + */ +typedef enum gpdma_transfer_mode { + GPDMA_TRANSFER_MODE_INCREMENT_NONE = 0, /**< no increment at all of src and dest */ + GPDMA_TRANSFER_MODE_INCREMENT_SRC = 1, /**< increment src at each burst */ + GPDMA_TRANSFER_MODE_INCREMENT_DEST = 2, /**< increment dest at each burst */ +} gpdma_transfer_mode_t; + +/** + * @enum gpdma_beat_len + * + * @brief possible DMA single manipulation data len (denoted beat) + * the beat len, associated to the transfer mode and the burst number defined how the + * DMA behaves. + * + * This defines the way burst works and impact the increment calculation. This + * is defined for both source and dest and may differ, allowing differenciated increment + */ +typedef enum gpdma_beat_len { + GPDMA_BEAT_LEN_BYTE = 0, /**< data len to manipulate is a byte */ + GPDMA_BEAT_LEN_HALFWORD = 1, /**< data len to manipulate is a half word */ + GPDMA_BEAT_LEN_WORD = 2, /**< data len to manipulate is a word */ +} gpdma_beat_len_t; + +/** + * @enum gpdma_priority + * + * @brief DMA stream priority in comparison with others + */ +typedef enum gpdma_priority { + GPDMA_PRIORITY_LOW = 0, + GPDMA_PRIORITY_MEDIUM = 1, + GPDMA_PRIORITY_HIGH = 2, + GPDMA_PRIORITY_VERY_HIGH = 3, +} gpdma_priority_t; + +/** + * @struct gpdma_stream_cfg + * + * @brief DMA transfer definition + * + * Depending on the hardware, the notion of channels and stream may vary, + * as sometime the controller hold stream with various channels configuration, + * or hold channels with various stream (request type) configuration. + * + * In order to avoid any difficulties at upper layer: + * - a channel is always denoted 'channel' + * - a stream can be a request + * This couple is always defined in the device-tree file, so that it + * properly identify a configuration, meaning that the DMA controller + * configuration is correctly shared between requester at configure time. + * + * This means that whatever the driver is, the correct selection of a working + * stream/channel configuration is fixed and is not automatically detected at + * run time. + */ +typedef struct gpdma_stream_cfg { + uint16_t channel; /**< channel identifier */ + uint16_t stream; /**< request identifier */ + uint16_t controller; /**< controller identifier */ + uint16_t transfer_type; /**< type of transfer, @see gpdma_transfer_type */ + size_t source; /**< source address, for memory-to-x requests */ + size_t dest; /**< destination address, for x-to-memory requests */ + size_t transfer_len; /**< overall steam transfer length in bytes */ + bool circular_source; /**< make DMA stream restart from initial source addr at trigger time */ + bool circular_dest; /**< make DMA stream restart from initial dest addr at trigger time */ + uint8_t interrupts; /**< interrupt requested, @see gpdma_chan_int */ + bool is_triggered; /**< specify if the DMA stream is triggered or not */ + uint8_t trigger; /**< trigger id that (re)arm DMA data transfer */ + uint8_t priority; /**< DMA stream priority in comparison with others, @see gpdma_priority */ + uint8_t transfer_mode; /**< DMA transfer mode, @see gpdma_transfer_mode*/ + uint8_t src_beat_len; /**< source burst length @see gpdma_beat_len */ + uint8_t dest_beat_len; /**< source burst length @see gpdma_beat_len */ +} gpdma_stream_cfg_t; + +/** + * @brief generic state value definition for a DMA stream, used to get back DMA statuses + */ +typedef enum dma_chan_state { + GPDMA_STATE_IDLE = 1, /**< DMA channel idle (not set or unused) */ + GPDMA_STATE_RUNNING = 2, /**< DMA channel is running */ + GPDMA_STATE_ABORTED = 3, /**< DMA stream aborted on SW request */ + GPDMA_STATE_SUSPENDED = 4, /**< DMA stream suspended on SW request*/ + GPDMA_STATE_TRANSMISSION_FAILURE = 5, /**< DMA transmission failure */ + GPDMA_STATE_CONFIGURATION_FAILURE = 6, /**< DMA channel configuration failure */ + GPDMA_STATE_OVERRUN = 7, /**< DMA transmission overrun */ + GPDMA_STATE_TRANSFER_COMPLETE = 8, /**< DMA transfer complete for this channel */ + GPDMA_STATE_HALF_TRANSFER = 9, /**< DMA transfer half-complete for this channel */ +} gpdma_chan_state_t; + +#ifdef __cplusplus +} /* extern "C" */ +#endif // __cplusplus + + +#endif/*UAPI_DMA_H*/ diff --git a/uapi/include/uapi/meson.build b/uapi/include/uapi/meson.build index 27e6d696..4d743a1b 100644 --- a/uapi/include/uapi/meson.build +++ b/uapi/include/uapi/meson.build @@ -4,7 +4,8 @@ uapi_headers = files([ 'device.h', 'handle.h', - 'types.h' + 'types.h', + 'dma.h', ]) uapi_h = files(['uapi.h']) diff --git a/uapi/include/uapi/types.h b/uapi/include/uapi/types.h index 104284e4..b55fc625 100644 --- a/uapi/include/uapi/types.h +++ b/uapi/include/uapi/types.h @@ -303,22 +303,6 @@ typedef struct shm_infos { uint32_t perms; /*< SHM permissions (mask of SHMPermission) */ } shm_infos_t; -/** - * @brief generic state value definition for a DMA stream, used to get back DMA statuses - */ -typedef enum dma_chan_state { - GPDMA_STATE_IDLE = 1, /**< DMA channel idle (not set or unused) */ - GPDMA_STATE_RUNNING = 2, /**< DMA channel is running */ - GPDMA_STATE_ABORTED = 3, /**< DMA stream aborted on SW request */ - GPDMA_STATE_SUSPENDED = 4, /**< DMA stream suspended on SW request*/ - GPDMA_STATE_TRANSMISSION_FAILURE = 5, /**< DMA transmission failure */ - GPDMA_STATE_CONFIGURATION_FAILURE = 6, /**< DMA channel configuration failure */ - GPDMA_STATE_OVERRUN = 7, /**< DMA transmission overrun */ - GPDMA_STATE_TRANSFER_COMPLETE = 8, /**< DMA transfer complete for this channel */ - GPDMA_STATE_HALF_TRANSFER = 9, /**< DMA transfer half-complete for this channel */ -} dma_chan_state_t; - - #ifdef __cplusplus } /* extern "C" */ #endif // __cplusplus