Skip to content

Commit f5c392d

Browse files
miquelraynalvinodkoul
authored andcommitted
dmaengine: xilinx: xdma: Add terminate_all/synchronize callbacks
The driver is capable of starting scatter-gather transfers and needs to wait until their end. It is also capable of starting cyclic transfers and will only be "reset" next time the channel will be reused. In practice most of the time we hear no audio glitch because the sound card stops the flow on its side so the DMA transfers are just discarded. There are however some cases (when playing a bit with a number of frames and with a discontinuous sound file) when the sound card seems to be slightly too slow at stopping the flow, leading to a glitch that can be heard. In all cases, we need to earn better control of the DMA engine and adding proper ->device_terminate_all() and ->device_synchronize() callbacks feels totally relevant. With these two callbacks, no glitch can be heard anymore. Fixes: cd8c732 ("dmaengine: xilinx: xdma: Support cyclic transfers") Signed-off-by: Miquel Raynal <[email protected]> Tested-by: Lizhi Hou <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent b3072be commit f5c392d

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

drivers/dma/xilinx/xdma.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,31 @@ static int xdma_xfer_start(struct xdma_chan *xchan)
371371
return ret;
372372

373373
xchan->busy = true;
374+
375+
return 0;
376+
}
377+
378+
/**
379+
* xdma_xfer_stop - Stop DMA transfer
380+
* @xchan: DMA channel pointer
381+
*/
382+
static int xdma_xfer_stop(struct xdma_chan *xchan)
383+
{
384+
struct virt_dma_desc *vd = vchan_next_desc(&xchan->vchan);
385+
struct xdma_device *xdev = xchan->xdev_hdl;
386+
int ret;
387+
388+
if (!vd || !xchan->busy)
389+
return -EINVAL;
390+
391+
/* clear run stop bit to prevent any further auto-triggering */
392+
ret = regmap_write(xdev->rmap, xchan->base + XDMA_CHAN_CONTROL_W1C,
393+
CHAN_CTRL_RUN_STOP);
394+
if (ret)
395+
return ret;
396+
397+
xchan->busy = false;
398+
374399
return 0;
375400
}
376401

@@ -475,6 +500,47 @@ static void xdma_issue_pending(struct dma_chan *chan)
475500
spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags);
476501
}
477502

503+
/**
504+
* xdma_terminate_all - Terminate all transactions
505+
* @chan: DMA channel pointer
506+
*/
507+
static int xdma_terminate_all(struct dma_chan *chan)
508+
{
509+
struct xdma_chan *xdma_chan = to_xdma_chan(chan);
510+
struct xdma_desc *desc = NULL;
511+
struct virt_dma_desc *vd;
512+
unsigned long flags;
513+
LIST_HEAD(head);
514+
515+
spin_lock_irqsave(&xdma_chan->vchan.lock, flags);
516+
xdma_xfer_stop(xdma_chan);
517+
518+
vd = vchan_next_desc(&xdma_chan->vchan);
519+
if (vd)
520+
desc = to_xdma_desc(vd);
521+
if (desc) {
522+
dma_cookie_complete(&desc->vdesc.tx);
523+
vchan_terminate_vdesc(&desc->vdesc);
524+
}
525+
526+
vchan_get_all_descriptors(&xdma_chan->vchan, &head);
527+
spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags);
528+
vchan_dma_desc_free_list(&xdma_chan->vchan, &head);
529+
530+
return 0;
531+
}
532+
533+
/**
534+
* xdma_synchronize - Synchronize terminated transactions
535+
* @chan: DMA channel pointer
536+
*/
537+
static void xdma_synchronize(struct dma_chan *chan)
538+
{
539+
struct xdma_chan *xdma_chan = to_xdma_chan(chan);
540+
541+
vchan_synchronize(&xdma_chan->vchan);
542+
}
543+
478544
/**
479545
* xdma_prep_device_sg - prepare a descriptor for a DMA transaction
480546
* @chan: DMA channel pointer
@@ -1088,6 +1154,8 @@ static int xdma_probe(struct platform_device *pdev)
10881154
xdev->dma_dev.device_prep_slave_sg = xdma_prep_device_sg;
10891155
xdev->dma_dev.device_config = xdma_device_config;
10901156
xdev->dma_dev.device_issue_pending = xdma_issue_pending;
1157+
xdev->dma_dev.device_terminate_all = xdma_terminate_all;
1158+
xdev->dma_dev.device_synchronize = xdma_synchronize;
10911159
xdev->dma_dev.filter.map = pdata->device_map;
10921160
xdev->dma_dev.filter.mapcnt = pdata->device_map_cnt;
10931161
xdev->dma_dev.filter.fn = xdma_filter_fn;

0 commit comments

Comments
 (0)