From: Miquel Raynal <miquel.raynal@bootlin.com>
To: Vinod Koul <vkoul@kernel.org>, Lizhi Hou <lizhi.hou@amd.com>,
Brian Xu <brian.xu@amd.com>,
Raj Kumar Rampelli <raj.kumar.rampelli@amd.com>,
dmaengine@vger.kernel.org
Cc: Michal Simek <monstr@monstr.eu>,
Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
Miquel Raynal <miquel.raynal@bootlin.com>
Subject: [PATCH 3/3] dmaengine: xilinx: xdma: Add terminate_all/synchronize callbacks
Date: Fri, 24 Nov 2023 16:09:23 +0100 [thread overview]
Message-ID: <20231124150923.257687-4-miquel.raynal@bootlin.com> (raw)
In-Reply-To: <20231124150923.257687-1-miquel.raynal@bootlin.com>
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: cd8c732ce1a5 ("dmaengine: xilinx: xdma: Support cyclic transfers")
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
This was only tested with cyclic transfers.
---
drivers/dma/xilinx/xdma.c | 68 +++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c
index caddd741a79c..3dfa4a35eb15 100644
--- a/drivers/dma/xilinx/xdma.c
+++ b/drivers/dma/xilinx/xdma.c
@@ -371,6 +371,31 @@ static int xdma_xfer_start(struct xdma_chan *xchan)
return ret;
xchan->busy = true;
+
+ return 0;
+}
+
+/**
+ * xdma_xfer_stop - Stop DMA transfer
+ * @xchan: DMA channel pointer
+ */
+static int xdma_xfer_stop(struct xdma_chan *xchan)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&xchan->vchan);
+ struct xdma_device *xdev = xchan->xdev_hdl;
+ int ret;
+
+ if (!vd || !xchan->busy)
+ return -EINVAL;
+
+ /* clear run stop bit to prevent any further auto-triggering */
+ ret = regmap_write(xdev->rmap, xchan->base + XDMA_CHAN_CONTROL_W1C,
+ CHAN_CTRL_RUN_STOP);
+ if (ret)
+ return ret;
+
+ xchan->busy = false;
+
return 0;
}
@@ -475,6 +500,47 @@ static void xdma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags);
}
+/**
+ * xdma_terminate_all - Terminate all transactions
+ * @chan: DMA channel pointer
+ */
+static int xdma_terminate_all(struct dma_chan *chan)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+ struct xdma_desc *desc = NULL;
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&xdma_chan->vchan.lock, flags);
+ xdma_xfer_stop(xdma_chan);
+
+ vd = vchan_next_desc(&xdma_chan->vchan);
+ if (vd)
+ desc = to_xdma_desc(vd);
+ if (desc) {
+ dma_cookie_complete(&desc->vdesc.tx);
+ vchan_terminate_vdesc(&desc->vdesc);
+ }
+
+ vchan_get_all_descriptors(&xdma_chan->vchan, &head);
+ spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags);
+ vchan_dma_desc_free_list(&xdma_chan->vchan, &head);
+
+ return 0;
+}
+
+/**
+ * xdma_synchronize - Synchronize terminated transactions
+ * @chan: DMA channel pointer
+ */
+static void xdma_synchronize(struct dma_chan *chan)
+{
+ struct xdma_chan *xdma_chan = to_xdma_chan(chan);
+
+ vchan_synchronize(&xdma_chan->vchan);
+}
+
/**
* xdma_prep_device_sg - prepare a descriptor for a DMA transaction
* @chan: DMA channel pointer
@@ -1090,6 +1156,8 @@ static int xdma_probe(struct platform_device *pdev)
xdev->dma_dev.device_prep_slave_sg = xdma_prep_device_sg;
xdev->dma_dev.device_config = xdma_device_config;
xdev->dma_dev.device_issue_pending = xdma_issue_pending;
+ xdev->dma_dev.device_terminate_all = xdma_terminate_all;
+ xdev->dma_dev.device_synchronize = xdma_synchronize;
xdev->dma_dev.filter.map = pdata->device_map;
xdev->dma_dev.filter.mapcnt = pdata->device_map_cnt;
xdev->dma_dev.filter.fn = xdma_filter_fn;
--
2.34.1
prev parent reply other threads:[~2023-11-24 15:09 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-24 15:09 [PATCH 0/3] dmaengine: xilinx: Better cyclic transfers Miquel Raynal
2023-11-24 15:09 ` [PATCH 1/3] dmaengine: xilinx: xdma: Fix the count of elapsed periods in cyclic mode Miquel Raynal
2023-11-28 22:44 ` Lizhi Hou
2023-11-29 0:13 ` Miquel Raynal
2023-11-24 15:09 ` [PATCH 2/3] dmaengine: xilinx: xdma: Better handling of the busy variable Miquel Raynal
2023-11-24 15:09 ` Miquel Raynal [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231124150923.257687-4-miquel.raynal@bootlin.com \
--to=miquel.raynal@bootlin.com \
--cc=brian.xu@amd.com \
--cc=dmaengine@vger.kernel.org \
--cc=lizhi.hou@amd.com \
--cc=monstr@monstr.eu \
--cc=raj.kumar.rampelli@amd.com \
--cc=thomas.petazzoni@bootlin.com \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox