Skip to content

Commit

Permalink
dma: Add support for DMA API: IRQ+assign/startup part (#44)
Browse files Browse the repository at this point in the history
- [x] Add UAPI part of DMA syscalls
- [x] implement support for IRQ to stream owner DMA manager API
- [x] Update or fix any of the manager-level dependencies for DMA gate
- [x] make syscall LUT pointing invalid while gate not written
- [x] Validate and complete if needed autotest-based DMA checks, ensure
tests results for both successflul and failures

Note: missing DMA features:
- DMA gate implementation
- DMA get_info support at manager level
- DMA termination (stop/unassign) related manager implementation

Note2: this PR do not impact in any way the kernel behavior for any of
the other usages than DMA. autotest must pass for all tests except DMA
ones
  • Loading branch information
pthierry-ledger authored Sep 30, 2024
2 parents 3801c19 + b477ad7 commit b8ee53a
Show file tree
Hide file tree
Showing 13 changed files with 331 additions and 52 deletions.
25 changes: 25 additions & 0 deletions autotest/src/tests/test_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,16 @@ static void test_dma_start_stream(dmah_t stream)
{
Status res;
TEST_START();
/* not assigned */
res = sys_dma_start_stream(stream);
ASSERT_EQ(res, STATUS_INVALID);
res = sys_dma_assign_stream(stream);
ASSERT_EQ(res, STATUS_OK);
/* assigned, should start */
res = sys_dma_start_stream(stream);
ASSERT_EQ(res, STATUS_OK);
res = sys_dma_assign_stream(stream);
ASSERT_EQ(res, STATUS_INVALID);
res = sys_dma_start_stream(stream);
ASSERT_EQ(res, STATUS_INVALID);
TEST_END();
Expand Down Expand Up @@ -72,6 +80,22 @@ static void test_dma_stop_stream(dmah_t stream)
ASSERT_EQ(res, STATUS_INVALID);
TEST_END();
}

static void test_dma_assign_unassign_stream(dmah_t stream)
{
Status res;
TEST_START();
res = sys_dma_assign_stream(stream);
ASSERT_EQ(res, STATUS_OK);
res = sys_dma_assign_stream(stream);
ASSERT_EQ(res, STATUS_INVALID);
res = sys_dma_unassign_stream(stream);
ASSERT_EQ(res, STATUS_OK);
res = sys_dma_unassign_stream(stream);
ASSERT_EQ(res, STATUS_INVALID);
TEST_END();
}

#endif

void test_dma(void)
Expand All @@ -82,6 +106,7 @@ void test_dma(void)
test_dma_get_handle(&stream);
test_dma_get_handle_inval();
test_dma_manipulate_stream_badhandle();
test_dma_assign_unassign_stream(stream);
test_dma_start_stream(stream);
test_dma_get_stream_status(stream);
test_dma_stop_stream(stream);
Expand Down
2 changes: 1 addition & 1 deletion kernel/include/bsp/drivers/dma/gpdma.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ typedef enum gpdma_priority {
typedef struct gpdma_stream_cfg {
uint16_t channel; /**< channel identifier */
uint16_t stream; /**< request identifier */
uint16_t controller; /**< controler 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 */
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/arch/asm-generic/handler-svc-lut.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ static const lut_svc_handler svc_lut[] = {
lut_unsuported, /* DMA Stop Stream */
lut_unsuported, /* DMA Get Stream Status */
lut_shm_get_infos,
lut_unsuported, /* DMA assign */
lut_unsuported, /* DMA unassign */
};

#define SYSCALL_NUM ARRAY_SIZE(svc_lut)
Expand Down
26 changes: 21 additions & 5 deletions kernel/src/drivers/dma/stm32-gpdma-dt.c.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
{% if port is owned or port is not enabled -%}
{% continue -%}
{% endif -%}
/* channel ordered interrupts for controller {{ port.label }} */
static const uint16_t stm32_{{ port.label}}_interrupts[] = {

/* channel ordered interrupts for each controller, controller-ordered */
static const uint16_t stm32_{{ port.label }}_interrupts[] = {
/* {{ port['dma-channels']|int }} DMA channels */
{% for chanirq in range((2*port['dma-channels'])) -%}
{% if port['interrupts'][chanirq]|int != 0 -%}
{{ port['interrupts'][chanirq] }}, /* channel {{ (chanirq / 2)|int }} interrupt identifier */
{% endif -%}
{% endfor -%}
0, /* sentinel */
};

#define IRQ_IS_{{ port.label|upper }}_OWNED(x) ( \
Expand All @@ -30,10 +32,8 @@ static const uint16_t stm32_{{ port.label}}_interrupts[] = {
{% endfor -%}
0 \
)

{% endfor -%}


bool stm32_gpdma_irq_is_dma_owned(int IRQn)
{
return ( \
Expand Down Expand Up @@ -81,9 +81,25 @@ const stm32_gpdma_desc_t * stm32_gpdma_get_desc(uint8_t ctrl)
if (unlikely(ctrl >= GPDMA_NUMBER)) {
goto end;
}
desc = &stm32_gpdmas[0];
desc = &stm32_gpdmas[ctrl];
end:
return desc;
}

/**
* @warning this is a private function, controller id must be valid and checked by caller
*/
uint16_t const * stm32_gpdma_get_interrupts(uint8_t ctrl)
{
uint16_t const * its;
if (unlikely(ctrl >= GPDMA_NUMBER)) {
its = NULL;
goto end;
}
/*@ assert \valid_read(stm32_gpdmas[ctrl].interrupts); */
its = stm32_gpdmas[ctrl].interrupts;
end:
return its;
}

bool gpdma_irq_is_dma_owned(int IRQn) __attribute__((alias("stm32_gpdma_irq_is_dma_owned")));
2 changes: 2 additions & 0 deletions kernel/src/drivers/dma/stm32-gpdma-dt.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ typedef struct stm32_gpdma_desc {

const stm32_gpdma_desc_t * stm32_gpdma_get_desc(uint8_t ctrl);

uint16_t const * stm32_gpdma_get_interrupts(uint8_t ctrl);

#endif /* __STM32_GPDMA_DT_GENERATED_H */
49 changes: 29 additions & 20 deletions kernel/src/drivers/dma/stm32u5-gpdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,17 @@ typedef union gpdma_register {
gpdma_c12br2_t cxbr2;
} gpdma_register_t;


/**
* @fn check given channel idle flag
* @fn get interrupt number associated to the given stream
*
* return true if the channel is idle, meaning:
* - not configured
* - disabled
* - suspended
*/
/*@
* requires (gpdma_controler_exists(ctrl) && gpdma_channel_is_valid(chanid));
* This function consider that the stream is strictly associated to a given {ctr,chan} couple,
* and that each chan of a given controller has a strictly defined IRQ number. This is the case
* of STM32U5 GPDMA controller.
*
* @param[in] desc: stream descriptor, has defined in gpdma.h and forged from DTS
* @param[out] IRQn: IRQ number associated to the stream, when configured
*/
static inline bool smt32u5_gpdma_is_channel_idle(uint8_t ctrl, uint16_t chanid)
{
bool is_idle = false;
stm32_gpdma_desc_t const *desc = stm32_gpdma_get_desc(ctrl);
gpdma_c0sr_t const *sr = (gpdma_c0sr_t const *)(desc->base_addr + GPDMA_CxSR(chanid));

return !!sr->idlef;
}

kstatus_t stm32u5_gpdma_get_interrupt(gpdma_stream_cfg_t const *desc, uint16_t * const IRQn)
static kstatus_t stm32u5_gpdma_get_interrupt(gpdma_stream_cfg_t const *desc, uint16_t * const IRQn)
{
kstatus_t status = K_ERROR_INVPARAM;
stm32_gpdma_desc_t const * ctrl = NULL;
Expand All @@ -106,6 +95,26 @@ kstatus_t stm32u5_gpdma_get_interrupt(gpdma_stream_cfg_t const *desc, uint16_t *
return status;
}

/**
* @fn check given channel idle flag
*
* return true if the channel is idle, meaning:
* - not configured
* - disabled
* - suspended
*/
/*@
* requires (gpdma_controler_exists(ctrl) && gpdma_channel_is_valid(chanid));
*/
static inline bool smt32u5_gpdma_is_channel_idle(uint8_t ctrl, uint16_t chanid)
{
bool is_idle = false;
stm32_gpdma_desc_t const *desc = stm32_gpdma_get_desc(ctrl);
gpdma_c0sr_t const *sr = (gpdma_c0sr_t const *)(desc->base_addr + GPDMA_CxSR(chanid));

return !!sr->idlef;
}

/**
* @fn clear GPDMA global interrupt
*
Expand All @@ -114,7 +123,7 @@ kstatus_t stm32u5_gpdma_get_interrupt(gpdma_stream_cfg_t const *desc, uint16_t *
*
* This is the driver level clear
*/
kstatus_t stm32u5_gpdma_interrupt_clear(gpdma_stream_cfg_t const*const desc)
kstatus_t stm32u5_gpdma_interrupt_clear(gpdma_stream_cfg_t const * const desc)
{
kstatus_t status = K_ERROR_INVPARAM;
const stm32_gpdma_desc_t * ctrl = NULL;
Expand Down
1 change: 1 addition & 0 deletions kernel/src/managers/dma/dma-dt.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* @file Sentry DMA streams access API
*/
#include <inttypes.h>
#include <bsp/drivers/dma/gpdma.h>

/**
* @brief Manager level stream configuration
Expand Down
Loading

0 comments on commit b8ee53a

Please sign in to comment.