@@ -300,12 +300,16 @@ struct xilinx_cdma_tx_segment {
* @segments: TX segments list
* @node: Node in the channel descriptors list
* @cyclic: Check for cyclic transfers.
+ * @err: Whether the descriptor has an error.
+ * @residue: Residue of the completed descriptor
*/
struct xilinx_dma_tx_descriptor {
struct dma_async_tx_descriptor async_tx;
struct list_head segments;
struct list_head node;
bool cyclic;
+ bool err;
+ u32 residue;
};
/**
@@ -865,6 +869,8 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
spin_lock_irqsave(&chan->lock, flags);
list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+ struct dmaengine_result result;
+
if (desc->cyclic) {
xilinx_dma_chan_handle_cyclic(chan, desc, &flags);
break;
@@ -873,9 +879,20 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
/* Remove from the list of running transactions */
list_del(&desc->node);
+ if (unlikely(desc->err)) {
+ if (chan->direction == DMA_DEV_TO_MEM)
+ result.result = DMA_TRANS_READ_FAILED;
+ else
+ result.result = DMA_TRANS_WRITE_FAILED;
+ } else {
+ result.result = DMA_TRANS_NOERROR;
+ }
+
+ result.residue = desc->residue;
+
/* Run the link descriptor callback function */
spin_unlock_irqrestore(&chan->lock, flags);
- dmaengine_desc_get_callback_invoke(&desc->async_tx, NULL);
+ dmaengine_desc_get_callback_invoke(&desc->async_tx, &result);
spin_lock_irqsave(&chan->lock, flags);
/* Run any dependencies, then free the descriptor */
@@ -1424,6 +1441,9 @@ static void xilinx_dma_complete_descriptor(struct xilinx_dma_chan *chan)
return;
list_for_each_entry_safe(desc, next, &chan->active_list, node) {
+ desc->residue = xilinx_dma_get_residue(chan, desc);
+ desc->err = chan->err;
+
list_del(&desc->node);
if (!desc->cyclic)
dma_cookie_complete(&desc->async_tx);