dma: callback with 2 status codes for successful transfers

Make use of positive status values in the DMA callback to pass
info to the DMA client after a successful DMA operation.
A completed DMA transfer uses the status 0 while a reached
water mark uses the status 1.

Signed-off-by: Cyril Fougeray <cyril.fougeray@worldcoin.org>
This commit is contained in:
Cyril Fougeray 2023-03-26 17:26:23 +02:00 committed by Carles Cufí
commit 1be72d9888
25 changed files with 60 additions and 52 deletions

View file

@ -76,7 +76,7 @@ struct mcux_adc16_data {
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA #ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
static void adc_dma_callback(const struct device *dma_dev, void *callback_arg, static void adc_dma_callback(const struct device *dma_dev, void *callback_arg,
uint32_t channel, int error_code) uint32_t channel, int status)
{ {
const struct device *dev = (const struct device *)callback_arg; const struct device *dev = (const struct device *)callback_arg;
struct mcux_adc16_data *data = dev->data; struct mcux_adc16_data *data = dev->data;

View file

@ -782,9 +782,9 @@ static void dma_callback(const struct device *dev, void *user_data,
if (channel == data->dma.channel) { if (channel == data->dma.channel) {
#if !defined(CONFIG_SOC_SERIES_STM32F1X) #if !defined(CONFIG_SOC_SERIES_STM32F1X)
if (LL_ADC_IsActiveFlag_OVR(adc) || (status == 0)) { if (LL_ADC_IsActiveFlag_OVR(adc) || (status >= 0)) {
#else #else
if (status == 0) { if (status >= 0) {
#endif /* !defined(CONFIG_SOC_SERIES_STM32F1X) */ #endif /* !defined(CONFIG_SOC_SERIES_STM32F1X) */
data->samples_count = data->channel_count; data->samples_count = data->channel_count;
data->buffer += data->channel_count; data->buffer += data->channel_count;
@ -801,7 +801,7 @@ static void dma_callback(const struct device *dev, void *user_data,
* the address is in a non-cacheable SRAM region. * the address is in a non-cacheable SRAM region.
*/ */
adc_context_on_sampling_done(&data->ctx, dev); adc_context_on_sampling_done(&data->ctx, dev);
} else { } else if (status < 0) {
LOG_ERR("DMA sampling complete, but DMA reported error %d", status); LOG_ERR("DMA sampling complete, but DMA reported error %d", status);
data->dma_error = status; data->dma_error = status;
LL_ADC_REG_StopConversion(adc); LL_ADC_REG_StopConversion(adc);

View file

@ -70,7 +70,7 @@ void dw_dma_isr(const struct device *dev)
*/ */
chan_data->dma_blkcallback(dev, chan_data->dma_blkcallback(dev,
chan_data->blkuser_data, chan_data->blkuser_data,
channel, 0); channel, DMA_STATUS_BLOCK);
} }
} }
@ -89,7 +89,7 @@ void dw_dma_isr(const struct device *dev)
LOG_DBG("Dispatching transfer callback"); LOG_DBG("Dispatching transfer callback");
chan_data->dma_tfrcallback(dev, chan_data->dma_tfrcallback(dev,
chan_data->tfruser_data, chan_data->tfruser_data,
channel, 0); channel, DMA_STATUS_COMPLETE);
} }
} }
} }

View file

@ -467,7 +467,7 @@ static int process_cmpl_event(const struct device *dev,
enum ring_idx idx, uint32_t pl_len) enum ring_idx idx, uint32_t pl_len)
{ {
struct dma_iproc_pax_data *pd = dev->data; struct dma_iproc_pax_data *pd = dev->data;
uint32_t wr_offs, rd_offs, ret = 0; uint32_t wr_offs, rd_offs, ret = DMA_STATUS_COMPLETE;
struct dma_iproc_pax_ring_data *ring = &(pd->ring[idx]); struct dma_iproc_pax_ring_data *ring = &(pd->ring[idx]);
struct cmpl_pkt *c; struct cmpl_pkt *c;
uint32_t is_outstanding; uint32_t is_outstanding;

View file

@ -120,14 +120,14 @@ static bool data_size_valid(const size_t data_size)
static void nxp_edma_callback(edma_handle_t *handle, void *param, bool transferDone, static void nxp_edma_callback(edma_handle_t *handle, void *param, bool transferDone,
uint32_t tcds) uint32_t tcds)
{ {
int ret = 1; int ret = -EIO;
struct call_back *data = (struct call_back *)param; struct call_back *data = (struct call_back *)param;
uint32_t channel = handle->channel; uint32_t channel = handle->channel;
if (transferDone) { if (transferDone) {
/* DMA is no longer busy when there are no remaining TCDs to transfer */ /* DMA is no longer busy when there are no remaining TCDs to transfer */
data->busy = (handle->tcdPool != NULL) && (handle->tcdUsed > 0); data->busy = (handle->tcdPool != NULL) && (handle->tcdUsed > 0);
ret = 0; ret = DMA_STATUS_COMPLETE;
} }
LOG_DBG("transfer %d", tcds); LOG_DBG("transfer %d", tcds);
data->dma_callback(data->dev, data->user_data, channel, ret); data->dma_callback(data->dev, data->user_data, channel, ret);

View file

@ -58,12 +58,12 @@ struct dma_mcux_lpc_dma_data {
static void nxp_lpc_dma_callback(dma_handle_t *handle, void *param, static void nxp_lpc_dma_callback(dma_handle_t *handle, void *param,
bool transferDone, uint32_t intmode) bool transferDone, uint32_t intmode)
{ {
int ret = 1; int ret = -EIO;
struct call_back *data = (struct call_back *)param; struct call_back *data = (struct call_back *)param;
uint32_t channel = handle->channel; uint32_t channel = handle->channel;
if (transferDone) { if (transferDone) {
ret = 0; ret = DMA_STATUS_COMPLETE;
} }
if (intmode == kDMA_IntError) { if (intmode == kDMA_IntError) {

View file

@ -45,22 +45,22 @@ static void nios2_msgdma_callback(void *context)
{ {
struct nios2_msgdma_dev_data *dev_data = struct nios2_msgdma_dev_data *dev_data =
(struct nios2_msgdma_dev_data *)context; (struct nios2_msgdma_dev_data *)context;
int err_code; int dma_status;
uint32_t status; uint32_t status;
status = IORD_ALTERA_MSGDMA_CSR_STATUS(dev_data->msgdma_dev->csr_base); status = IORD_ALTERA_MSGDMA_CSR_STATUS(dev_data->msgdma_dev->csr_base);
if (status & ALTERA_MSGDMA_CSR_STOPPED_ON_ERROR_MASK) { if (status & ALTERA_MSGDMA_CSR_STOPPED_ON_ERROR_MASK) {
err_code = -EIO; dma_status = -EIO;
} else if (status & ALTERA_MSGDMA_CSR_BUSY_MASK) { } else if (status & ALTERA_MSGDMA_CSR_BUSY_MASK) {
err_code = -EBUSY; dma_status = -EBUSY;
} else { } else {
err_code = 0; dma_status = DMA_STATUS_COMPLETE;
} }
LOG_DBG("msgdma csr status Reg: 0x%x", status); LOG_DBG("msgdma csr status Reg: 0x%x", status);
dev_data->dma_callback(dev_data->dev, dev_data->user_data, 0, err_code); dev_data->dma_callback(dev_data->dev, dev_data->user_data, 0, dma_status);
} }
static int nios2_msgdma_config(const struct device *dev, uint32_t channel, static int nios2_msgdma_config(const struct device *dev, uint32_t channel,

View file

@ -118,7 +118,7 @@ static void dma_stm32_irq_handler(const struct device *dev, uint32_t id)
if (!stream->hal_override) { if (!stream->hal_override) {
dma_stm32_clear_ht(dma, id); dma_stm32_clear_ht(dma, id);
} }
stream->dma_callback(dev, stream->user_data, callback_arg, 0); stream->dma_callback(dev, stream->user_data, callback_arg, DMA_STATUS_BLOCK);
} else if (stm32_dma_is_tc_irq_active(dma, id)) { } else if (stm32_dma_is_tc_irq_active(dma, id)) {
#ifdef CONFIG_DMAMUX_STM32 #ifdef CONFIG_DMAMUX_STM32
stream->busy = false; stream->busy = false;
@ -127,7 +127,7 @@ static void dma_stm32_irq_handler(const struct device *dev, uint32_t id)
if (!stream->hal_override) { if (!stream->hal_override) {
dma_stm32_clear_tc(dma, id); dma_stm32_clear_tc(dma, id);
} }
stream->dma_callback(dev, stream->user_data, callback_arg, 0); stream->dma_callback(dev, stream->user_data, callback_arg, DMA_STATUS_COMPLETE);
} else if (stm32_dma_is_unexpected_irq_happened(dma, id)) { } else if (stm32_dma_is_unexpected_irq_happened(dma, id)) {
LOG_ERR("Unexpected irq happened."); LOG_ERR("Unexpected irq happened.");
stream->dma_callback(dev, stream->user_data, stream->dma_callback(dev, stream->user_data,

View file

@ -251,13 +251,13 @@ static void dma_stm32_irq_handler(const struct device *dev, uint32_t id)
if (!stream->hal_override) { if (!stream->hal_override) {
dma_stm32_clear_ht(dma, id); dma_stm32_clear_ht(dma, id);
} }
stream->dma_callback(dev, stream->user_data, callback_arg, 0); stream->dma_callback(dev, stream->user_data, callback_arg, DMA_STATUS_BLOCK);
} else if (stm32_dma_is_tc_irq_active(dma, id)) { } else if (stm32_dma_is_tc_irq_active(dma, id)) {
/* Let HAL DMA handle flags on its own */ /* Let HAL DMA handle flags on its own */
if (!stream->hal_override) { if (!stream->hal_override) {
dma_stm32_clear_tc(dma, id); dma_stm32_clear_tc(dma, id);
} }
stream->dma_callback(dev, stream->user_data, callback_arg, 0); stream->dma_callback(dev, stream->user_data, callback_arg, DMA_STATUS_COMPLETE);
} else { } else {
LOG_ERR("Transfer Error."); LOG_ERR("Transfer Error.");
dma_stm32_dump_stream_irq(dev, id); dma_stm32_dump_stream_irq(dev, id);

View file

@ -1299,7 +1299,7 @@ static void ospi_dma_callback(const struct device *dev, void *arg,
ARG_UNUSED(dev); ARG_UNUSED(dev);
if (status != 0) { if (status < 0) {
LOG_ERR("DMA callback error with channel %d.", channel); LOG_ERR("DMA callback error with channel %d.", channel);
} }

View file

@ -524,7 +524,7 @@ static void dma_rx_callback(const struct device *dma_dev, void *arg,
void *mblk_tmp; void *mblk_tmp;
int ret; int ret;
if (status != 0) { if (status < 0) {
ret = -EIO; ret = -EIO;
stream->state = I2S_STATE_ERROR; stream->state = I2S_STATE_ERROR;
goto rx_disable; goto rx_disable;
@ -591,7 +591,7 @@ static void dma_tx_callback(const struct device *dma_dev, void *arg,
size_t mem_block_size; size_t mem_block_size;
int ret; int ret;
if (status != 0) { if (status < 0) {
ret = -EIO; ret = -EIO;
stream->state = I2S_STATE_ERROR; stream->state = I2S_STATE_ERROR;
goto tx_disable; goto tx_disable;

View file

@ -457,9 +457,9 @@ static void i2s_mcux_dma_tx_callback(const struct device *dma_dev, void *arg,
dma_start(stream->dev_dma, stream->channel); dma_start(stream->dev_dma, stream->channel);
} }
if (ret || status) { if (ret || status < 0) {
/* /*
* DMA encountered an error (status != 0) * DMA encountered an error (status < 0)
* or * or
* No buffers in input queue * No buffers in input queue
*/ */
@ -490,7 +490,7 @@ static void i2s_mcux_dma_rx_callback(const struct device *dma_dev, void *arg,
LOG_DBG("rx cb: %d", stream->state); LOG_DBG("rx cb: %d", stream->state);
if (status != 0) { if (status < 0) {
stream->state = I2S_STATE_ERROR; stream->state = I2S_STATE_ERROR;
i2s_mcux_rx_stream_disable(dev, false); i2s_mcux_rx_stream_disable(dev, false);
return; return;

View file

@ -593,7 +593,7 @@ static int uart_mcux_lpuart_dma_replace_rx_buffer(const struct device *dev)
} }
static void dma_callback(const struct device *dma_dev, void *callback_arg, uint32_t channel, static void dma_callback(const struct device *dma_dev, void *callback_arg, uint32_t channel,
int error_code) int dma_status)
{ {
struct device *dev = (struct device *)callback_arg; struct device *dev = (struct device *)callback_arg;
const struct mcux_lpuart_config *config = dev->config; const struct mcux_lpuart_config *config = dev->config;
@ -611,8 +611,8 @@ static void dma_callback(const struct device *dma_dev, void *callback_arg, uint3
status.pending_length); status.pending_length);
} }
if (error_code != 0) { if (dma_status < 0) {
LOG_ERR("Got error : %d", error_code); LOG_ERR("Got error : %d", dma_status);
} }

View file

@ -1227,7 +1227,7 @@ void uart_stm32_dma_rx_cb(const struct device *dma_dev, void *user_data,
const struct device *uart_dev = user_data; const struct device *uart_dev = user_data;
struct uart_stm32_data *data = uart_dev->data; struct uart_stm32_data *data = uart_dev->data;
if (status != 0) { if (status < 0) {
async_evt_rx_err(data, status); async_evt_rx_err(data, status);
return; return;
} }

View file

@ -61,7 +61,7 @@ static void dma_callback(const struct device *dev, void *arg,
/* arg directly holds the spi device */ /* arg directly holds the spi device */
struct spi_stm32_data *data = arg; struct spi_stm32_data *data = arg;
if (status != 0) { if (status < 0) {
LOG_ERR("DMA callback error with channel %d.", channel); LOG_ERR("DMA callback error with channel %d.", channel);
data->status_flags |= SPI_STM32_DMA_ERROR_FLAG; data->status_flags |= SPI_STM32_DMA_ERROR_FLAG;
} else { } else {

View file

@ -482,7 +482,7 @@ static void dma_callback(const struct device *dma_dev, void *callback_arg,
LOG_DBG("=dma call back @channel %d=", channel); LOG_DBG("=dma call back @channel %d=", channel);
if (error_code) { if (error_code < 0) {
LOG_ERR("error happened no callback process %d", error_code); LOG_ERR("error happened no callback process %d", error_code);
return; return;
} }

View file

@ -305,7 +305,7 @@ static void spi_mcux_dma_callback(const struct device *dev, void *arg,
const struct device *spi_dev = arg; const struct device *spi_dev = arg;
struct spi_mcux_data *data = spi_dev->data; struct spi_mcux_data *data = spi_dev->data;
if (status != 0) { if (status < 0) {
LOG_ERR("DMA callback error with channel %d.", channel); LOG_ERR("DMA callback error with channel %d.", channel);
data->status_flags |= SPI_MCUX_FLEXCOMM_DMA_ERROR_FLAG; data->status_flags |= SPI_MCUX_FLEXCOMM_DMA_ERROR_FLAG;
} else { } else {

View file

@ -254,7 +254,7 @@ static void spi_mcux_dma_callback(const struct device *dev, void *arg,
const struct device *spi_dev = arg; const struct device *spi_dev = arg;
struct spi_mcux_data *data = (struct spi_mcux_data *)spi_dev->data; struct spi_mcux_data *data = (struct spi_mcux_data *)spi_dev->data;
if (status != 0) { if (status < 0) {
LOG_ERR("DMA callback error with channel %d.", channel); LOG_ERR("DMA callback error with channel %d.", channel);
data->status_flags |= SPI_MCUX_LPSPI_DMA_ERROR_FLAG; data->status_flags |= SPI_MCUX_LPSPI_DMA_ERROR_FLAG;
} else { } else {

View file

@ -136,17 +136,25 @@ struct dma_block_config {
uint16_t reserved : 3; uint16_t reserved : 3;
}; };
#define DMA_STATUS_COMPLETE 0
#define DMA_STATUS_BLOCK 1
/** /**
* @typedef dma_callback_t * @typedef dma_callback_t
* @brief Callback function for DMA transfer completion * @brief Callback function for DMA transfer completion
* *
* If enabled, callback function will be invoked at transfer completion * If enabled, callback function will be invoked at transfer or block completion,
* or when error happens. * or when an error happens.
* In circular mode, @p status indicates that the DMA device has reached either
* the end of the buffer (DMA_STATUS_COMPLETE) or a water mark (DMA_STATUS_BLOCK).
* *
* @param dev Pointer to the DMA device calling the callback. * @param dev Pointer to the DMA device calling the callback.
* @param user_data A pointer to some user data or NULL * @param user_data A pointer to some user data or NULL
* @param channel The channel number * @param channel The channel number
* @param status 0 on success, a negative errno otherwise * @param status - 0-DMA_STATUS_COMPLETE buffer fully consumed
* - 1-DMA_STATUS_BLOCK buffer consumption reached a configured block
* or water mark
* - a negative errno otherwise
*/ */
typedef void (*dma_callback_t)(const struct device *dev, void *user_data, typedef void (*dma_callback_t)(const struct device *dev, void *user_data,
uint32_t channel, int status); uint32_t channel, int status);

View file

@ -27,13 +27,13 @@ static struct dma_config dma_cfg = {0};
static struct dma_block_config dma_block_cfg = {0}; static struct dma_block_config dma_block_cfg = {0};
static void dma_user_callback(const struct device *dma_dev, void *arg, static void dma_user_callback(const struct device *dma_dev, void *arg,
uint32_t id, int error_code) uint32_t id, int status)
{ {
if (error_code == 0) { if (status >= 0) {
TC_PRINT("DMA completed successfully\n"); TC_PRINT("DMA completed successfully\n");
dma_stat = DMA_OP_STAT_SUCCESS; dma_stat = DMA_OP_STAT_SUCCESS;
} else { } else {
TC_PRINT("DMA error occurred!! (%d)\n", error_code); TC_PRINT("DMA error occurred!! (%d)\n", status);
dma_stat = DMA_OP_STAT_ERR; dma_stat = DMA_OP_STAT_ERR;
} }
} }

View file

@ -83,7 +83,7 @@ static __aligned(32) int32_t rx_data[XFERS][BUF_SIZE] = { { 0 } };
static void dma_callback(const struct device *dma_dev, void *user_data, static void dma_callback(const struct device *dma_dev, void *user_data,
uint32_t channel, int status) uint32_t channel, int status)
{ {
if (status) { if (status < 0) {
TC_PRINT("tx callback status %d\n", status); TC_PRINT("tx callback status %d\n", status);
} else { } else {
TC_PRINT("tx giving up\n"); TC_PRINT("tx giving up\n");
@ -93,7 +93,7 @@ static void dma_callback(const struct device *dma_dev, void *user_data,
static void dma_callback_rx(const struct device *dma_dev, void *user_data, static void dma_callback_rx(const struct device *dma_dev, void *user_data,
uint32_t channel, int status) uint32_t channel, int status)
{ {
if (status) { if (status < 0) {
TC_PRINT("rx callback status %d\n", status); TC_PRINT("rx callback status %d\n", status);
} else { } else {
TC_PRINT("rx giving xfer_sem\n"); TC_PRINT("rx giving xfer_sem\n");

View file

@ -34,9 +34,9 @@ static char rx_data[RX_BUFF_SIZE] = { 0 };
#endif #endif
static void test_done(const struct device *dma_dev, void *arg, static void test_done(const struct device *dma_dev, void *arg,
uint32_t id, int error_code) uint32_t id, int status)
{ {
if (error_code == 0) { if (status >= 0) {
TC_PRINT("DMA transfer done\n"); TC_PRINT("DMA transfer done\n");
} else { } else {
TC_PRINT("DMA transfer met an error\n"); TC_PRINT("DMA transfer met an error\n");

View file

@ -40,9 +40,9 @@ static char rx_data2[RX_BUFF_SIZE] = { 0 };
#endif #endif
static void test_done(const struct device *dma_dev, void *arg, uint32_t id, static void test_done(const struct device *dma_dev, void *arg, uint32_t id,
int error_code) int status)
{ {
if (error_code == 0) { if (status >= 0) {
TC_PRINT("DMA transfer done ch %d\n", id); TC_PRINT("DMA transfer done ch %d\n", id);
} else { } else {
TC_PRINT("DMA transfer met an error\n"); TC_PRINT("DMA transfer met an error\n");

View file

@ -98,14 +98,14 @@ static void test_transfer(const struct device *dev, uint32_t id)
} }
static void dma_user_callback(const struct device *dma_dev, void *arg, static void dma_user_callback(const struct device *dma_dev, void *arg,
uint32_t id, int error_code) uint32_t id, int status)
{ {
/* test case is done so ignore the interrupt */ /* test case is done so ignore the interrupt */
if (done) { if (done) {
return; return;
} }
zassert_false(error_code, "DMA could not proceed, an error occurred\n"); zassert_false(status < 0, "DMA could not proceed, an error occurred\n");
#ifdef CONFIG_DMAMUX_STM32 #ifdef CONFIG_DMAMUX_STM32
/* the channel is the DMAMUX's one /* the channel is the DMAMUX's one

View file

@ -44,7 +44,7 @@ static struct dma_block_config dma_block_cfgs[XFERS];
static void dma_sg_callback(const struct device *dma_dev, void *user_data, static void dma_sg_callback(const struct device *dma_dev, void *user_data,
uint32_t channel, int status) uint32_t channel, int status)
{ {
if (status) { if (status < 0) {
TC_PRINT("callback status %d\n", status); TC_PRINT("callback status %d\n", status);
} else { } else {
TC_PRINT("giving xfer_sem\n"); TC_PRINT("giving xfer_sem\n");