From 5878853fc9389e7d0988d4b465a415cf96fd14fa Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:20 +0200 Subject: [PATCH 1/3] dmaengine: Add API function dmaengine_prep_peripheral_dma_vec() This function can be used to initiate a scatter-gather DMA transfer, where the address and size of each segment is located in one entry of the dma_vec array. The major difference with dmaengine_prep_slave_sg() is that it supports specifying the lengths of each DMA transfer; as trying to override the length of the transfer with dmaengine_prep_slave_sg() is a very tedious process. The introduction of a new API function is also justified by the fact that scatterlists are on their way out. Note that dmaengine_prep_interleaved_dma() is not helpful either in that case, as it assumes that the address of each segment will be higher than the one of the previous segment, which we just cannot guarantee in case of a scatter-gather transfer. Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240620122726.41232-2-paul@crapouillou.net Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 752dbde4cec1f8..9fc03068cabcb7 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -160,6 +160,16 @@ struct dma_interleaved_template { struct data_chunk sgl[]; }; +/** + * struct dma_vec - DMA vector + * @addr: Bus address of the start of the vector + * @len: Length in bytes of the DMA vector + */ +struct dma_vec { + dma_addr_t addr; + size_t len; +}; + /** * enum dma_ctrl_flags - DMA flags to augment operation preparation, * control completion, and communicate status. @@ -910,6 +920,10 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_peripheral_dma_vec)( + struct dma_chan *chan, const struct dma_vec *vecs, + size_t nents, enum dma_transfer_direction direction, + unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_slave_sg)( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, @@ -973,6 +987,25 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single( dir, flags, NULL); } +/** + * dmaengine_prep_peripheral_dma_vec() - Prepare a DMA scatter-gather descriptor + * @chan: The channel to be used for this descriptor + * @vecs: The array of DMA vectors that should be transferred + * @nents: The number of DMA vectors in the array + * @dir: Specifies the direction of the data transfer + * @flags: DMA engine flags + */ +static inline struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec( + struct dma_chan *chan, const struct dma_vec *vecs, size_t nents, + enum dma_transfer_direction dir, unsigned long flags) +{ + if (!chan || !chan->device || !chan->device->device_prep_peripheral_dma_vec) + return NULL; + + return chan->device->device_prep_peripheral_dma_vec(chan, vecs, nents, + dir, flags); +} + static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction dir, unsigned long flags) From 74609e5686701ed8e8adc3082d15f009e327286d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:21 +0200 Subject: [PATCH 2/3] dmaengine: dma-axi-dmac: Implement device_prep_peripheral_dma_vec Add implementation of the .device_prep_peripheral_dma_vec() callback. Signed-off-by: Paul Cercueil Co-developed-by: Nuno Sa Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20240620122726.41232-3-paul@crapouillou.net Signed-off-by: Vinod Koul --- drivers/dma/dma-axi-dmac.c | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index bdb752f1186982..36943b0c6d603c 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -620,6 +620,45 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan, return sg; } +static struct dma_async_tx_descriptor * +axi_dmac_prep_peripheral_dma_vec(struct dma_chan *c, const struct dma_vec *vecs, + size_t nb, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac_desc *desc; + unsigned int num_sgs = 0; + struct axi_dmac_sg *dsg; + size_t i; + + if (direction != chan->direction) + return NULL; + + for (i = 0; i < nb; i++) + num_sgs += DIV_ROUND_UP(vecs[i].len, chan->max_length); + + desc = axi_dmac_alloc_desc(chan, num_sgs); + if (!desc) + return NULL; + + dsg = desc->sg; + + for (i = 0; i < nb; i++) { + if (!axi_dmac_check_addr(chan, vecs[i].addr) || + !axi_dmac_check_len(chan, vecs[i].len)) { + kfree(desc); + return NULL; + } + + dsg = axi_dmac_fill_linear_sg(chan, direction, vecs[i].addr, 1, + vecs[i].len, dsg); + } + + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg( struct dma_chan *c, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, @@ -1061,6 +1100,7 @@ static int axi_dmac_probe(struct platform_device *pdev) dma_dev->device_tx_status = dma_cookie_status; dma_dev->device_issue_pending = axi_dmac_issue_pending; dma_dev->device_prep_slave_sg = axi_dmac_prep_slave_sg; + dma_dev->device_prep_peripheral_dma_vec = axi_dmac_prep_peripheral_dma_vec; dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic; dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved; dma_dev->device_terminate_all = axi_dmac_terminate_all; From 380afccc2a55e8015adae4266e8beff96ab620be Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 20 Jun 2024 14:27:26 +0200 Subject: [PATCH 3/3] Documentation: dmaengine: Document new dma_vec API Document the dmaengine_prep_peripheral_dma_vec() API function, the device_prep_peripheral_dma_vec() backend function, and the dma_vec struct. Signed-off-by: Paul Cercueil Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20240620122726.41232-8-paul@crapouillou.net Signed-off-by: Vinod Koul --- Documentation/driver-api/dmaengine/client.rst | 9 +++++++++ Documentation/driver-api/dmaengine/provider.rst | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst index ecf139f73da4d5..d491e385d61a98 100644 --- a/Documentation/driver-api/dmaengine/client.rst +++ b/Documentation/driver-api/dmaengine/client.rst @@ -80,6 +80,10 @@ The details of these operations are: - slave_sg: DMA a list of scatter gather buffers from/to a peripheral + - peripheral_dma_vec: DMA an array of scatter gather buffers from/to a + peripheral. Similar to slave_sg, but uses an array of dma_vec + structures instead of a scatterlist. + - dma_cyclic: Perform a cyclic DMA operation from/to a peripheral till the operation is explicitly stopped. @@ -102,6 +106,11 @@ The details of these operations are: unsigned int sg_len, enum dma_data_direction direction, unsigned long flags); + struct dma_async_tx_descriptor *dmaengine_prep_peripheral_dma_vec( + struct dma_chan *chan, const struct dma_vec *vecs, + size_t nents, enum dma_data_direction direction, + unsigned long flags); + struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic( struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, size_t period_len, enum dma_data_direction direction); diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst index ceac2a300e328b..3085f8b460fa55 100644 --- a/Documentation/driver-api/dmaengine/provider.rst +++ b/Documentation/driver-api/dmaengine/provider.rst @@ -433,6 +433,12 @@ supported. - residue: Provides the residue bytes of the transfer for those that support residue. +- ``device_prep_peripheral_dma_vec`` + + - Similar to ``device_prep_slave_sg``, but it takes a pointer to a + array of ``dma_vec`` structures, which (in the long run) will replace + scatterlists. + - ``device_issue_pending`` - Takes the first transaction descriptor in the pending queue, @@ -544,6 +550,10 @@ dma_cookie_t - Not really relevant any more since the introduction of ``virt-dma`` that abstracts it away. +dma_vec + +- A small structure that contains a DMA address and length. + DMA_CTRL_ACK - If clear, the descriptor cannot be reused by provider until the