From b1e1b5e7b4a5c9c3e1cb379cbad0f24d5ea7fbd6 Mon Sep 17 00:00:00 2001 From: Tom Burdick Date: Wed, 4 Jan 2023 12:02:11 -0600 Subject: [PATCH] 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 --- .../dma/loop_transfer/src/test_dma_loop.c | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/tests/drivers/dma/loop_transfer/src/test_dma_loop.c b/tests/drivers/dma/loop_transfer/src/test_dma_loop.c index 489d2dcd028..7c7599c75ca 100644 --- a/tests/drivers/dma/loop_transfer/src/test_dma_loop.c +++ b/tests/drivers/dma/loop_transfer/src/test_dma_loop.c @@ -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)); +}