struct dma_tx_state *txstate)
{
struct axi_dma_chan *chan = dchan_to_axi_dma_chan(dchan);
- enum dma_status ret;
+ struct virt_dma_desc *vdesc;
+ enum dma_status status;
+ u32 completed_length;
+ unsigned long flags;
+ u32 completed_blocks;
+ size_t bytes = 0;
+ u32 length;
+ u32 len;
- ret = dma_cookie_status(dchan, cookie, txstate);
+ status = dma_cookie_status(dchan, cookie, txstate);
+ if (status == DMA_COMPLETE || !txstate)
+ return status;
- if (chan->is_paused && ret == DMA_IN_PROGRESS)
- ret = DMA_PAUSED;
+ spin_lock_irqsave(&chan->vc.lock, flags);
- return ret;
+ vdesc = vchan_find_desc(&chan->vc, cookie);
+ if (vdesc) {
+ length = vd_to_axi_desc(vdesc)->length;
+ completed_blocks = vd_to_axi_desc(vdesc)->completed_blocks;
+ len = vd_to_axi_desc(vdesc)->hw_desc[0].len;
+ completed_length = completed_blocks * len;
+ bytes = length - completed_length;
+ } else {
+ bytes = vd_to_axi_desc(vdesc)->length;
+ }
+
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
+ dma_set_residue(txstate, bytes);
+
+ return status;
}
static void write_desc_llp(struct axi_dma_hw_desc *desc, dma_addr_t adr)
set_desc_src_master(hw_desc);
+ hw_desc->len = len;
return 0;
}
chan->direction = direction;
desc->chan = chan;
chan->cyclic = true;
+ desc->length = 0;
for (i = 0; i < num_periods; i++) {
hw_desc = &desc->hw_desc[i];
if (status < 0)
goto err_desc_get;
+ desc->length += hw_desc->len;
/* Set end-of-link to the linked descriptor, so that cyclic
* callback function can be triggered during interrupt.
*/
goto err_desc_get;
desc->chan = chan;
+ desc->length = 0;
for_each_sg(sgl, sg, sg_len, i) {
mem = sg_dma_address(sg);
status = dw_axi_dma_set_hw_desc(chan, hw_desc, mem, len);
if (status < 0)
goto err_desc_get;
+ desc->length += hw_desc->len;
}
/* Set end-of-link to the last link descriptor of list */
desc->chan = chan;
num = 0;
+ desc->length = 0;
while (len) {
xfer_len = len;
set_desc_src_master(hw_desc);
set_desc_dest_master(hw_desc, desc);
-
+ hw_desc->len = xfer_len;
+ desc->length += hw_desc->len;
/* update the length and addresses for the next loop cycle */
len -= xfer_len;
dst_adr += xfer_len;
dw->dma.dst_addr_widths = AXI_DMA_BUSWIDTHS;
dw->dma.directions = BIT(DMA_MEM_TO_MEM);
dw->dma.directions |= BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
- dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+ dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
dw->dma.dev = chip->dev;
dw->dma.device_tx_status = dma_chan_tx_status;