dma: Test repeatedly calling start/stop

Ensures that the documented behavior of the API is met by implementations
through testing. By calling stop on a stopped channel the expectation is no
error occurs and is checked.

Calling start after a channel has been started is difficult to test for
as there is transfer timing involved. A once shot transfer may have
completed and the channel transition to an inactive state by itself by
the time the second start call is performed. This isn't supported by at
least gpdma today and isn't documented behaviorally so should not be
tested.

Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
This commit is contained in:
Tom Burdick 2023-01-04 12:02:11 -06:00 committed by Lauren Murphy
commit b1e1b5e7b4

View file

@ -339,6 +339,108 @@ static int test_loop_suspend_resume(void)
}
static int test_loop_repeated_start_stop(void)
{
const struct device *dma;
static int chan_id;
test_case_id = 0;
TC_PRINT("DMA memory to memory transfer started\n");
TC_PRINT("Preparing DMA Controller\n");
#if CONFIG_NOCACHE_MEMORY
memset(tx_data, 0, sizeof(tx_data));
memcpy(tx_data, TX_DATA, sizeof(TX_DATA));
#endif
memset(rx_data, 0, sizeof(rx_data));
dma = DEVICE_DT_GET(DT_NODELABEL(test_dma));
if (!device_is_ready(dma)) {
TC_PRINT("dma controller device is not ready\n");
return TC_FAIL;
}
dma_cfg.channel_direction = MEMORY_TO_MEMORY;
dma_cfg.source_data_size = 1U;
dma_cfg.dest_data_size = 1U;
dma_cfg.source_burst_length = 1U;
dma_cfg.dest_burst_length = 1U;
#ifdef CONFIG_DMAMUX_STM32
dma_cfg.user_data = (void *)dma;
#else
dma_cfg.user_data = NULL;
#endif /* CONFIG_DMAMUX_STM32 */
dma_cfg.dma_callback = dma_user_callback;
dma_cfg.block_count = 1U;
dma_cfg.head_block = &dma_block_cfg;
#ifdef CONFIG_DMA_MCUX_TEST_SLOT_START
dma_cfg.dma_slot = CONFIG_DMA_MCUX_TEST_SLOT_START;
#endif
chan_id = dma_request_channel(dma, NULL);
if (chan_id < 0) {
TC_PRINT("this platform do not support the dma channel\n");
chan_id = CONFIG_DMA_LOOP_TRANSFER_CHANNEL_NR;
}
transfer_count = 0;
done = 0;
TC_PRINT("Starting the transfer on channel %d and waiting for 1 second\n", chan_id);
dma_block_cfg.block_size = strlen(tx_data);
dma_block_cfg.source_address = (uint32_t)tx_data;
dma_block_cfg.dest_address = (uint32_t)rx_data[transfer_count];
if (dma_config(dma, chan_id, &dma_cfg)) {
TC_PRINT("ERROR: transfer config (%d)\n", chan_id);
return TC_FAIL;
}
if (dma_stop(dma, chan_id)) {
TC_PRINT("ERROR: transfer stop on stopped channel (%d)\n", chan_id);
return TC_FAIL;
}
if (dma_start(dma, chan_id)) {
TC_PRINT("ERROR: transfer start (%d)\n", chan_id);
return TC_FAIL;
}
k_sleep(K_MSEC(SLEEPTIME));
if (transfer_count < TRANSFER_LOOPS) {
transfer_count = TRANSFER_LOOPS;
TC_PRINT("ERROR: unfinished transfer\n");
if (dma_stop(dma, chan_id)) {
TC_PRINT("ERROR: transfer stop\n");
}
return TC_FAIL;
}
TC_PRINT("Each RX buffer should contain the full TX buffer string.\n");
for (int i = 0; i < TRANSFER_LOOPS; i++) {
TC_PRINT("RX data Loop %d: %s\n", i, rx_data[i]);
if (strncmp(tx_data, rx_data[i], sizeof(rx_data[i])) != 0) {
return TC_FAIL;
}
}
TC_PRINT("Finished: DMA\n");
if (dma_stop(dma, chan_id)) {
TC_PRINT("ERROR: transfer stop (%d)\n", chan_id);
return TC_FAIL;
}
if (dma_stop(dma, chan_id)) {
TC_PRINT("ERROR: repeated transfer stop (%d)\n", chan_id);
return TC_FAIL;
}
return TC_PASS;
}
/* export test cases */
ZTEST(dma_m2m_loop, test_dma_m2m_loop)
{
@ -350,3 +452,9 @@ ZTEST(dma_m2m_loop, test_dma_m2m_loop_suspend_resume)
{
zassert_true((test_loop_suspend_resume() == TC_PASS));
}
/* export test cases */
ZTEST(dma_m2m_loop, test_dma_m2m_loop_repeated_start_stop)
{
zassert_true((test_loop_repeated_start_stop() == TC_PASS));
}