linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
@ 2022-10-25  9:02 Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 01/32] dmaengine: at_hdmac: Fix at_lli struct definition Tudor Ambarus
                   ` (34 more replies)
  0 siblings, 35 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

v2:
- reorder patches so that fixes come first -> easier to backport to
stable kernels.
- drop the devm_request_irq() patch as we had to disable the irq anyway
in remove() in order to avoid spurios IRQs. Using devm variant brings no
palpable benefit.
- reword pm_ptr commit message


at_hdmac driver had poor list handling and concurrency bugs.
We experienced calling of the completion call twice for the
same descriptor. Peter Rosin encountered the same while
reporting a different bug:
https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/

Two sets of tests were performed:
1/ tested just the fixes, to make sure everything is fine and the
concurrency bugs are squashed even without the conversion to virt-dma.
All went fine.
2/ tested the entire series including the conversion the virt-dma
All went fine.

I tested NAND (prep_dma_memcpy), MMC (prep_dma_slave_sg),
usart (cyclic mode), dmatest (memcpy, memset).
With the conversion to virt-dma I replaced the election of a new transfer
in the tasklet with the election of the new transfer in the interrupt
handler. We should have a shorter idle window as we remove the scheduling
latency of the tasklet. Using mtd_speedtest showed similar performances
when using NAND with DMA. That could be because of using a low timming
mode on NAND.


Tudor Ambarus (32):
  dmaengine: at_hdmac: Fix at_lli struct definition
  dmaengine: at_hdmac: Don't start transactions at tx_submit level
  dmaengine: at_hdmac: Start transfer for cyclic channels in
    issue_pending
  dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
  dmaengine: at_hdmac: Do not call the complete callback on
    device_terminate_all
  dmaengine: at_hdmac: Protect atchan->status with the channel lock
  dmaengine: at_hdmac: Fix concurrency problems by removing
    atc_complete_all()
  dmaengine: at_hdmac: Fix concurrency over descriptor
  dmaengine: at_hdmac: Free the memset buf without holding the chan lock
  dmaengine: at_hdmac: Fix concurrency over the active list
  dmaengine: at_hdmac: Fix descriptor handling when issuing it to
    hardware
  dmaengine: at_hdmac: Fix completion of unissued descriptor in case of
    errors
  dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
  dmaengine: at_hdmac: Fix impossible condition
  dmaengine: at_hdmac: Check return code of dma_async_device_register
  dmaengine: at_hdmac: Do not print messages on console while holding
    the lock
  dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when
    txstate is NULL
  dmaengine: at_hdmac: Remove superfluous cast
  dmaengine: at_hdmac: Pass residue by address to avoid unnecessary
    implicit casts
  dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
  dmaengine: at_hdmac: Introduce atc_get_llis_residue()
  dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
  dmaengine: at_hdmac: Use devm_platform_ioremap_resource
  dmaengine: at_hdmac: Use devm_clk_get()
  dmaengine: at_hdmac: Use pm_ptr()
  dmaengine: at_hdmac: Set include entries in alphabetic order
  dmaengine: at_hdmac: Keep register definitions and structures private
    to at_hdmac.c
  dmaengine: at_hdmac: Use bitfield access macros
  dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
  dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
  dmaengine: at_hdmac: Remove unused member of at_dma_chan
  dmaengine: at_hdmac: Convert driver to use virt-dma

 MAINTAINERS                 |    1 -
 drivers/dma/Kconfig         |    1 +
 drivers/dma/at_hdmac.c      | 1899 ++++++++++++++++++-----------------
 drivers/dma/at_hdmac_regs.h |  478 ---------
 4 files changed, 990 insertions(+), 1389 deletions(-)
 delete mode 100644 drivers/dma/at_hdmac_regs.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v2 01/32] dmaengine: at_hdmac: Fix at_lli struct definition
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 02/32] dmaengine: at_hdmac: Don't start transactions at tx_submit level Tudor Ambarus
                   ` (33 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

Those hardware registers are all of 32 bits, while dma_addr_t ca be of
type u64 or u32 depending on CONFIG_ARCH_DMA_ADDR_T_64BIT. Force u32 to
comply with what the hardware expects.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
---
 drivers/dma/at_hdmac_regs.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index 4d1ebc040031..d4d382d74607 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -186,13 +186,13 @@
 /* LLI == Linked List Item; aka DMA buffer descriptor */
 struct at_lli {
 	/* values that are not changed by hardware */
-	dma_addr_t	saddr;
-	dma_addr_t	daddr;
+	u32 saddr;
+	u32 daddr;
 	/* value that may get written back: */
-	u32		ctrla;
+	u32 ctrla;
 	/* more values that are not changed by hardware */
-	u32		ctrlb;
-	dma_addr_t	dscr;	/* chain to next lli */
+	u32 ctrlb;
+	u32 dscr;	/* chain to next lli */
 };
 
 /**
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 02/32] dmaengine: at_hdmac: Don't start transactions at tx_submit level
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 01/32] dmaengine: at_hdmac: Fix at_lli struct definition Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 03/32] dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending Tudor Ambarus
                   ` (32 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

tx_submit is supposed to push the current transaction descriptor to a
pending queue, waiting for issue_pending() to be called. issue_pending()
must start the transfer, not tx_submit(), thus remove atc_dostart() from
atc_tx_submit(). Clients of at_xdmac that assume that tx_submit() starts
the transfer must be updated and call dma_async_issue_pending() if they
miss to call it.
The vdbg print was moved to after the lock is released. It is desirable to
do the prints without the lock held if possible, and because the if
statement disappears there's no reason why to do the print while holding
the lock.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 5a50423b7378..3f71f4d2f467 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -691,19 +691,11 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx)
 	spin_lock_irqsave(&atchan->lock, flags);
 	cookie = dma_cookie_assign(tx);
 
-	if (list_empty(&atchan->active_list)) {
-		dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
-				desc->txd.cookie);
-		atc_dostart(atchan, desc);
-		list_add_tail(&desc->desc_node, &atchan->active_list);
-	} else {
-		dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
-				desc->txd.cookie);
-		list_add_tail(&desc->desc_node, &atchan->queue);
-	}
-
+	list_add_tail(&desc->desc_node, &atchan->queue);
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
+	dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
+		 desc->txd.cookie);
 	return cookie;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 03/32] dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 01/32] dmaengine: at_hdmac: Fix at_lli struct definition Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 02/32] dmaengine: at_hdmac: Don't start transactions at tx_submit level Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 04/32] dmaengine: at_hdmac: Fix premature completion of desc " Tudor Ambarus
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

Cyclic channels must too call issue_pending in order to start a transfer.
Start the transfer in issue_pending regardless of the type of channel.
This wrongly worked before, because in the past the transfer was started
at tx_submit level when only a desc in the transfer list.

Fixes: 53830cc75974 ("dmaengine: at_hdmac: add cyclic DMA operation support")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 3f71f4d2f467..e9d0c3632868 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1536,10 +1536,6 @@ static void atc_issue_pending(struct dma_chan *chan)
 
 	dev_vdbg(chan2dev(chan), "issue_pending\n");
 
-	/* Not needed for cyclic transfers */
-	if (atc_chan_is_cyclic(atchan))
-		return;
-
 	atc_advance_work(atchan);
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 04/32] dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (2 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 03/32] dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 05/32] dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all Tudor Ambarus
                   ` (30 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

Multiple calls to atc_issue_pending() could result in a premature
completion of a descriptor from the atchan->active list, as the method
always completed the first active descriptor from the list. Instead,
issue_pending() should just take the first transaction descriptor from the
pending queue, move it to active_list and start the transfer.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index e9d0c3632868..cb5522417db6 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1527,16 +1527,26 @@ atc_tx_status(struct dma_chan *chan,
 }
 
 /**
- * atc_issue_pending - try to finish work
+ * atc_issue_pending - takes the first transaction descriptor in the pending
+ * queue and starts the transfer.
  * @chan: target DMA channel
  */
 static void atc_issue_pending(struct dma_chan *chan)
 {
-	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
+	struct at_dma_chan *atchan = to_at_dma_chan(chan);
+	struct at_desc *desc;
+	unsigned long flags;
 
 	dev_vdbg(chan2dev(chan), "issue_pending\n");
 
-	atc_advance_work(atchan);
+	spin_lock_irqsave(&atchan->lock, flags);
+	if (atc_chan_is_enabled(atchan) || list_empty(&atchan->queue))
+		return spin_unlock_irqrestore(&atchan->lock, flags);
+
+	desc = atc_first_queued(atchan);
+	list_move_tail(&desc->desc_node, &atchan->active_list);
+	atc_dostart(atchan, desc);
+	spin_unlock_irqrestore(&atchan->lock, flags);
 }
 
 /**
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 05/32] dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (3 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 04/32] dmaengine: at_hdmac: Fix premature completion of desc " Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 06/32] dmaengine: at_hdmac: Protect atchan->status with the channel lock Tudor Ambarus
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

The method was wrong because it violated the dmaengine API. For aborted
transfers the complete callback should not be called. Fix the behavior and
do not call the complete callback on device_terminate_all.

Fixes: 808347f6a317 ("dmaengine: at_hdmac: add DMA slave transfers")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index cb5522417db6..11816484843e 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1437,11 +1437,8 @@ static int atc_terminate_all(struct dma_chan *chan)
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
 	int			chan_id = atchan->chan_common.chan_id;
-	struct at_desc		*desc, *_desc;
 	unsigned long		flags;
 
-	LIST_HEAD(list);
-
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
 
 	/*
@@ -1460,15 +1457,11 @@ static int atc_terminate_all(struct dma_chan *chan)
 		cpu_relax();
 
 	/* active_list entries will end up before queued entries */
-	list_splice_init(&atchan->queue, &list);
-	list_splice_init(&atchan->active_list, &list);
+	list_splice_tail_init(&atchan->queue, &atchan->free_list);
+	list_splice_tail_init(&atchan->active_list, &atchan->free_list);
 
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
-	/* Flush all pending and queued descriptors */
-	list_for_each_entry_safe(desc, _desc, &list, desc_node)
-		atc_chain_complete(atchan, desc);
-
 	clear_bit(ATC_IS_PAUSED, &atchan->status);
 	/* if channel dedicated to cyclic operations, free it */
 	clear_bit(ATC_IS_CYCLIC, &atchan->status);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 06/32] dmaengine: at_hdmac: Protect atchan->status with the channel lock
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (4 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 05/32] dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 07/32] dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all() Tudor Ambarus
                   ` (28 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

Now that the complete callback call was removed from
device_terminate_all(), we can protect the atchan->status with the channel
lock. The atomic bitops on atchan->status do not substitute proper locking
on the status, as one could still modify the status after the lock was
dropped in atc_terminate_all() but before the atomic bitops were executed.

Fixes: 078a6506141a ("dmaengine: at_hdmac: Fix deadlocks")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 11816484843e..deb4c6027436 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1460,12 +1460,12 @@ static int atc_terminate_all(struct dma_chan *chan)
 	list_splice_tail_init(&atchan->queue, &atchan->free_list);
 	list_splice_tail_init(&atchan->active_list, &atchan->free_list);
 
-	spin_unlock_irqrestore(&atchan->lock, flags);
-
 	clear_bit(ATC_IS_PAUSED, &atchan->status);
 	/* if channel dedicated to cyclic operations, free it */
 	clear_bit(ATC_IS_CYCLIC, &atchan->status);
 
+	spin_unlock_irqrestore(&atchan->lock, flags);
+
 	return 0;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 07/32] dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (5 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 06/32] dmaengine: at_hdmac: Protect atchan->status with the channel lock Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 08/32] dmaengine: at_hdmac: Fix concurrency over descriptor Tudor Ambarus
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

atc_complete_all() had concurrency bugs, thus remove it:
1/ atc_complete_all() in its entirety was buggy, as when the atchan->queue
list (the one that contains descriptors that are not yet issued to the
hardware) contained descriptors, it fired just the first from the
atchan->queue, but moved all the desc from atchan->queue to
atchan->active_list and considered them all as fired. This could result in
calling the completion of a descriptor that was not yet issued to the
hardware.
2/ when in tasklet at atc_advance_work() time, atchan->active_list was
queried without holding the lock of the chan. This can result in
atchan->active_list concurrency problems between the tasklet and
issue_pending().

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 49 ++++--------------------------------------
 1 file changed, 4 insertions(+), 45 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index deb4c6027436..f1e6fa6af6c2 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -485,42 +485,6 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 	dma_run_dependencies(txd);
 }
 
-/**
- * atc_complete_all - finish work for all transactions
- * @atchan: channel to complete transactions for
- *
- * Eventually submit queued descriptors if any
- *
- * Assume channel is idle while calling this function
- * Called with atchan->lock held and bh disabled
- */
-static void atc_complete_all(struct at_dma_chan *atchan)
-{
-	struct at_desc *desc, *_desc;
-	LIST_HEAD(list);
-	unsigned long flags;
-
-	dev_vdbg(chan2dev(&atchan->chan_common), "complete all\n");
-
-	spin_lock_irqsave(&atchan->lock, flags);
-
-	/*
-	 * Submit queued descriptors ASAP, i.e. before we go through
-	 * the completed ones.
-	 */
-	if (!list_empty(&atchan->queue))
-		atc_dostart(atchan, atc_first_queued(atchan));
-	/* empty active_list now it is completed */
-	list_splice_init(&atchan->active_list, &list);
-	/* empty queue list by moving descriptors (if any) to active_list */
-	list_splice_init(&atchan->queue, &atchan->active_list);
-
-	spin_unlock_irqrestore(&atchan->lock, flags);
-
-	list_for_each_entry_safe(desc, _desc, &list, desc_node)
-		atc_chain_complete(atchan, desc);
-}
-
 /**
  * atc_advance_work - at the end of a transaction, move forward
  * @atchan: channel where the transaction ended
@@ -528,25 +492,20 @@ static void atc_complete_all(struct at_dma_chan *atchan)
 static void atc_advance_work(struct at_dma_chan *atchan)
 {
 	unsigned long flags;
-	int ret;
 
 	dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n");
 
 	spin_lock_irqsave(&atchan->lock, flags);
-	ret = atc_chan_is_enabled(atchan);
+	if (atc_chan_is_enabled(atchan) || list_empty(&atchan->active_list))
+		return spin_unlock_irqrestore(&atchan->lock, flags);
 	spin_unlock_irqrestore(&atchan->lock, flags);
-	if (ret)
-		return;
-
-	if (list_empty(&atchan->active_list) ||
-	    list_is_singular(&atchan->active_list))
-		return atc_complete_all(atchan);
 
 	atc_chain_complete(atchan, atc_first_active(atchan));
 
 	/* advance work */
 	spin_lock_irqsave(&atchan->lock, flags);
-	atc_dostart(atchan, atc_first_active(atchan));
+	if (!list_empty(&atchan->active_list))
+		atc_dostart(atchan, atc_first_active(atchan));
 	spin_unlock_irqrestore(&atchan->lock, flags);
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 08/32] dmaengine: at_hdmac: Fix concurrency over descriptor
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (6 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 07/32] dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all() Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 09/32] dmaengine: at_hdmac: Free the memset buf without holding the chan lock Tudor Ambarus
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

The descriptor was added to the free_list before calling the callback,
which could result in reissuing of the same descriptor and calling of a
single callback for both. Move the decriptor to the free list after the
callback is invoked.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index f1e6fa6af6c2..2012ecc57826 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -469,11 +469,8 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 		desc->memset_buffer = false;
 	}
 
-	/* move children to free_list */
-	list_splice_init(&desc->tx_list, &atchan->free_list);
-	/* move myself to free_list */
-	list_move(&desc->desc_node, &atchan->free_list);
-
+	/* Remove transfer node from the active list. */
+	list_del_init(&desc->desc_node);
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
 	dma_descriptor_unmap(txd);
@@ -483,6 +480,13 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 		dmaengine_desc_get_callback_invoke(txd, NULL);
 
 	dma_run_dependencies(txd);
+
+	spin_lock_irqsave(&atchan->lock, flags);
+	/* move children to free_list */
+	list_splice_init(&desc->tx_list, &atchan->free_list);
+	/* add myself to free_list */
+	list_add(&desc->desc_node, &atchan->free_list);
+	spin_unlock_irqrestore(&atchan->lock, flags);
 }
 
 /**
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 09/32] dmaengine: at_hdmac: Free the memset buf without holding the chan lock
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (7 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 08/32] dmaengine: at_hdmac: Fix concurrency over descriptor Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 10/32] dmaengine: at_hdmac: Fix concurrency over the active list Tudor Ambarus
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

There's no need to hold the channel lock when freeing the memset buf, as
the operation has already completed. Free the memset buf without holding
the channel lock.

Fixes: 4d112426c344 ("dmaengine: hdmac: Add memset capabilities")
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
---
 drivers/dma/at_hdmac.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 2012ecc57826..0fb44f622d35 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -462,13 +462,6 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 	if (!atc_chan_is_cyclic(atchan))
 		dma_cookie_complete(txd);
 
-	/* If the transfer was a memset, free our temporary buffer */
-	if (desc->memset_buffer) {
-		dma_pool_free(atdma->memset_pool, desc->memset_vaddr,
-			      desc->memset_paddr);
-		desc->memset_buffer = false;
-	}
-
 	/* Remove transfer node from the active list. */
 	list_del_init(&desc->desc_node);
 	spin_unlock_irqrestore(&atchan->lock, flags);
@@ -487,6 +480,13 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 	/* add myself to free_list */
 	list_add(&desc->desc_node, &atchan->free_list);
 	spin_unlock_irqrestore(&atchan->lock, flags);
+
+	/* If the transfer was a memset, free our temporary buffer */
+	if (desc->memset_buffer) {
+		dma_pool_free(atdma->memset_pool, desc->memset_vaddr,
+			      desc->memset_paddr);
+		desc->memset_buffer = false;
+	}
 }
 
 /**
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 10/32] dmaengine: at_hdmac: Fix concurrency over the active list
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (8 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 09/32] dmaengine: at_hdmac: Free the memset buf without holding the chan lock Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 11/32] dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware Tudor Ambarus
                   ` (24 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

The tasklet (atc_advance_work()) did not held the channel lock when
retrieving the first active descriptor, causing concurrency problems if
issue_pending() was called in between. If issue_pending() was called
exactly after the lock was released in the tasklet (atc_advance_work()),
atc_chain_complete() could complete a descriptor for which the controller
has not yet raised an interrupt.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 0fb44f622d35..b53a9fc15dd9 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -462,8 +462,6 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 	if (!atc_chan_is_cyclic(atchan))
 		dma_cookie_complete(txd);
 
-	/* Remove transfer node from the active list. */
-	list_del_init(&desc->desc_node);
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
 	dma_descriptor_unmap(txd);
@@ -495,6 +493,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
  */
 static void atc_advance_work(struct at_dma_chan *atchan)
 {
+	struct at_desc *desc;
 	unsigned long flags;
 
 	dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n");
@@ -502,9 +501,12 @@ static void atc_advance_work(struct at_dma_chan *atchan)
 	spin_lock_irqsave(&atchan->lock, flags);
 	if (atc_chan_is_enabled(atchan) || list_empty(&atchan->active_list))
 		return spin_unlock_irqrestore(&atchan->lock, flags);
-	spin_unlock_irqrestore(&atchan->lock, flags);
 
-	atc_chain_complete(atchan, atc_first_active(atchan));
+	desc = atc_first_active(atchan);
+	/* Remove the transfer node from the active list. */
+	list_del_init(&desc->desc_node);
+	spin_unlock_irqrestore(&atchan->lock, flags);
+	atc_chain_complete(atchan, desc);
 
 	/* advance work */
 	spin_lock_irqsave(&atchan->lock, flags);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 11/32] dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (9 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 10/32] dmaengine: at_hdmac: Fix concurrency over the active list Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 12/32] dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors Tudor Ambarus
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

As it was before, the descriptor was issued to the hardware without adding
it to the active (issued) list. This could result in a completion of other
descriptor, or/and in the descriptor never being completed.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index b53a9fc15dd9..9e5a30396c1c 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -510,8 +510,11 @@ static void atc_advance_work(struct at_dma_chan *atchan)
 
 	/* advance work */
 	spin_lock_irqsave(&atchan->lock, flags);
-	if (!list_empty(&atchan->active_list))
-		atc_dostart(atchan, atc_first_active(atchan));
+	if (!list_empty(&atchan->active_list)) {
+		desc = atc_first_queued(atchan);
+		list_move_tail(&desc->desc_node, &atchan->active_list);
+		atc_dostart(atchan, desc);
+	}
 	spin_unlock_irqrestore(&atchan->lock, flags);
 }
 
@@ -523,6 +526,7 @@ static void atc_advance_work(struct at_dma_chan *atchan)
 static void atc_handle_error(struct at_dma_chan *atchan)
 {
 	struct at_desc *bad_desc;
+	struct at_desc *desc;
 	struct at_desc *child;
 	unsigned long flags;
 
@@ -540,8 +544,11 @@ static void atc_handle_error(struct at_dma_chan *atchan)
 	list_splice_init(&atchan->queue, atchan->active_list.prev);
 
 	/* Try to restart the controller */
-	if (!list_empty(&atchan->active_list))
-		atc_dostart(atchan, atc_first_active(atchan));
+	if (!list_empty(&atchan->active_list)) {
+		desc = atc_first_queued(atchan);
+		list_move_tail(&desc->desc_node, &atchan->active_list);
+		atc_dostart(atchan, desc);
+	}
 
 	/*
 	 * KERN_CRITICAL may seem harsh, but since this only happens
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 12/32] dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (10 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 11/32] dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 13/32] dmaengine: at_hdmac: Don't allow CPU to reorder channel enable Tudor Ambarus
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

In case the controller detected an error, the code took the chance to move
all the queued (submitted) descriptors to the active (issued) list. This
was wrong as if there were any descriptors in the submitted list they were
moved to the issued list without actually issuing them to the controller,
thus a completion could be raised without even fireing the descriptor.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 9e5a30396c1c..80eeb4fb88ef 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -539,10 +539,6 @@ static void atc_handle_error(struct at_dma_chan *atchan)
 	bad_desc = atc_first_active(atchan);
 	list_del_init(&bad_desc->desc_node);
 
-	/* As we are stopped, take advantage to push queued descriptors
-	 * in active_list */
-	list_splice_init(&atchan->queue, atchan->active_list.prev);
-
 	/* Try to restart the controller */
 	if (!list_empty(&atchan->active_list)) {
 		desc = atc_first_queued(atchan);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 13/32] dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (11 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 12/32] dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 14/32] dmaengine: at_hdmac: Fix impossible condition Tudor Ambarus
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

at_hdmac uses __raw_writel for register writes. In the absence of a
barrier, the CPU may reorder the register operations.
Introduce a write memory barrier so that the CPU does not reorder the
channel enable, thus the start of the transfer, without making sure that
all the pre-required register fields are already written.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Reported-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
---
 drivers/dma/at_hdmac.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 80eeb4fb88ef..968a5aba47cd 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -256,6 +256,8 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 		       ATC_SPIP_BOUNDARY(first->boundary));
 	channel_writel(atchan, DPIP, ATC_DPIP_HOLE(first->dst_hole) |
 		       ATC_DPIP_BOUNDARY(first->boundary));
+	/* Don't allow CPU to reorder channel enable. */
+	wmb();
 	dma_writel(atdma, CHER, atchan->mask);
 
 	vdbg_dump_regs(atchan);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 14/32] dmaengine: at_hdmac: Fix impossible condition
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (12 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 13/32] dmaengine: at_hdmac: Don't allow CPU to reorder channel enable Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 15/32] dmaengine: at_hdmac: Check return code of dma_async_device_register Tudor Ambarus
                   ` (20 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

The iterator can not be greater than ATC_MAX_DSCR_TRIALS, as the for loop
will stop when i == ATC_MAX_DSCR_TRIALS. While here, use the common "i"
name for the iterator.

Fixes: 93dce3a6434f ("dmaengine: at_hdmac: fix residue computation")
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
---
 drivers/dma/at_hdmac.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 968a5aba47cd..afcbad3e1718 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -318,7 +318,8 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 	struct at_desc *desc_first = atc_first_active(atchan);
 	struct at_desc *desc;
 	int ret;
-	u32 ctrla, dscr, trials;
+	u32 ctrla, dscr;
+	unsigned int i;
 
 	/*
 	 * If the cookie doesn't match to the currently running transfer then
@@ -388,7 +389,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 		dscr = channel_readl(atchan, DSCR);
 		rmb(); /* ensure DSCR is read before CTRLA */
 		ctrla = channel_readl(atchan, CTRLA);
-		for (trials = 0; trials < ATC_MAX_DSCR_TRIALS; ++trials) {
+		for (i = 0; i < ATC_MAX_DSCR_TRIALS; ++i) {
 			u32 new_dscr;
 
 			rmb(); /* ensure DSCR is read after CTRLA */
@@ -414,7 +415,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 			rmb(); /* ensure DSCR is read before CTRLA */
 			ctrla = channel_readl(atchan, CTRLA);
 		}
-		if (unlikely(trials >= ATC_MAX_DSCR_TRIALS))
+		if (unlikely(i == ATC_MAX_DSCR_TRIALS))
 			return -ETIMEDOUT;
 
 		/* for the first descriptor we can be more accurate */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 15/32] dmaengine: at_hdmac: Check return code of dma_async_device_register
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (13 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 14/32] dmaengine: at_hdmac: Fix impossible condition Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 16/32] dmaengine: at_hdmac: Do not print messages on console while holding the lock Tudor Ambarus
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus, stable

dma_async_device_register() can fail, check the return code and display an
error.

Fixes: dc78baa2b90b ("dmaengine: at_hdmac: new driver for the Atmel AHB DMA Controller")
Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
Cc: stable@vger.kernel.org
---
 drivers/dma/at_hdmac.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index afcbad3e1718..858bd64f1313 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1928,7 +1928,11 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	  dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)  ? "slave " : "",
 	  plat_dat->nr_channels);
 
-	dma_async_device_register(&atdma->dma_common);
+	err = dma_async_device_register(&atdma->dma_common);
+	if (err) {
+		dev_err(&pdev->dev, "Unable to register: %d.\n", err);
+		goto err_dma_async_device_register;
+	}
 
 	/*
 	 * Do not return an error if the dmac node is not present in order to
@@ -1948,6 +1952,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
 
 err_of_dma_controller_register:
 	dma_async_device_unregister(&atdma->dma_common);
+err_dma_async_device_register:
 	dma_pool_destroy(atdma->memset_pool);
 err_memset_pool_create:
 	dma_pool_destroy(atdma->dma_desc_pool);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 16/32] dmaengine: at_hdmac: Do not print messages on console while holding the lock
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (14 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 15/32] dmaengine: at_hdmac: Check return code of dma_async_device_register Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 17/32] dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL Tudor Ambarus
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

The descriptor was already removed from the transfer list, there's no
reason to keep the channel lock while printing desc info, thus do the
prints without holding the lock.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 858bd64f1313..f365ac4d87ff 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -549,6 +549,8 @@ static void atc_handle_error(struct at_dma_chan *atchan)
 		atc_dostart(atchan, desc);
 	}
 
+	spin_unlock_irqrestore(&atchan->lock, flags);
+
 	/*
 	 * KERN_CRITICAL may seem harsh, but since this only happens
 	 * when someone submits a bad physical address in a
@@ -564,8 +566,6 @@ static void atc_handle_error(struct at_dma_chan *atchan)
 	list_for_each_entry(child, &bad_desc->tx_list, desc_node)
 		atc_dump_lli(atchan, &child->lli);
 
-	spin_unlock_irqrestore(&atchan->lock, flags);
-
 	/* Pretend the descriptor completed successfully */
 	atc_chain_complete(atchan, bad_desc);
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 17/32] dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (15 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 16/32] dmaengine: at_hdmac: Do not print messages on console while holding the lock Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 18/32] dmaengine: at_hdmac: Remove superfluous cast Tudor Ambarus
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

txstate is an optional parameter used to get a struct with auxilary
transfer status information. When not provided the call to
device_tx_status() should return the status of the dma cookie. Return the
status of dma cookie when the txstate optional parameter is not provided.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index f365ac4d87ff..10b6b0435d52 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1461,14 +1461,8 @@ atc_tx_status(struct dma_chan *chan,
 	int bytes = 0;
 
 	ret = dma_cookie_status(chan, cookie, txstate);
-	if (ret == DMA_COMPLETE)
+	if (ret == DMA_COMPLETE || !txstate)
 		return ret;
-	/*
-	 * There's no point calculating the residue if there's
-	 * no txstate to store the value.
-	 */
-	if (!txstate)
-		return DMA_ERROR;
 
 	spin_lock_irqsave(&atchan->lock, flags);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 18/32] dmaengine: at_hdmac: Remove superfluous cast
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (16 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 17/32] dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 19/32] dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts Tudor Ambarus
                   ` (16 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Conversions of void * are applied automatically when other pointer types
are assigned to and from void *. Remove the superfluous cast.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 10b6b0435d52..fbfb207104e9 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -603,7 +603,7 @@ static void atc_tasklet(struct tasklet_struct *t)
 
 static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
 {
-	struct at_dma		*atdma = (struct at_dma *)dev_id;
+	struct at_dma		*atdma = dev_id;
 	struct at_dma_chan	*atchan;
 	int			i;
 	u32			status, pending, imr;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 19/32] dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (17 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 18/32] dmaengine: at_hdmac: Remove superfluous cast Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 20/32] dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue Tudor Ambarus
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

struct dma_tx_state defines residue as u32. atc_get_bytes_left() returned
an int which could be either an error or the value of the residue. This
could cause problems if the controller supported a u32 buffer transfer size
and the u32 value was past the max int can hold. Our controller does not
support u32 buffer transfer size, but even so, improve the code and pass
the residue by address to avoid unnecessary implicit casts and make
atc_get_bytes_left() return 0 on success or -errno on errors.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 54 +++++++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 24 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index fbfb207104e9..e2c46f32b284 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -293,7 +293,7 @@ static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
  * @current_len: the number of bytes left before reading CTRLA
  * @ctrla: the value of CTRLA
  */
-static inline int atc_calc_bytes_left(int current_len, u32 ctrla)
+static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla)
 {
 	u32 btsize = (ctrla & ATC_BTSIZE_MAX);
 	u32 src_width = ATC_REG_TO_SRC_WIDTH(ctrla);
@@ -308,17 +308,20 @@ static inline int atc_calc_bytes_left(int current_len, u32 ctrla)
 }
 
 /**
- * atc_get_bytes_left - get the number of bytes residue for a cookie
+ * atc_get_bytes_left - get the number of bytes residue for a cookie.
+ * The residue is passed by address and updated on success.
  * @chan: DMA channel
  * @cookie: transaction identifier to check status of
+ * @residue: residue to be updated.
+ * Return 0 on success, -errono otherwise.
  */
-static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
+static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie,
+			      u32 *residue)
 {
 	struct at_dma_chan      *atchan = to_at_dma_chan(chan);
 	struct at_desc *desc_first = atc_first_active(atchan);
 	struct at_desc *desc;
-	int ret;
-	u32 ctrla, dscr;
+	u32 len, ctrla, dscr;
 	unsigned int i;
 
 	/*
@@ -333,7 +336,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 		return desc->total_len;
 
 	/* cookie matches to the currently running transfer */
-	ret = desc_first->total_len;
+	len = desc_first->total_len;
 
 	if (desc_first->lli.dscr) {
 		/* hardware linked list transfer */
@@ -419,29 +422,31 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie)
 			return -ETIMEDOUT;
 
 		/* for the first descriptor we can be more accurate */
-		if (desc_first->lli.dscr == dscr)
-			return atc_calc_bytes_left(ret, ctrla);
+		if (desc_first->lli.dscr == dscr) {
+			*residue = atc_calc_bytes_left(len, ctrla);
+			return 0;
+		}
 
-		ret -= desc_first->len;
+		len -= desc_first->len;
 		list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
 			if (desc->lli.dscr == dscr)
 				break;
 
-			ret -= desc->len;
+			len -= desc->len;
 		}
 
 		/*
 		 * For the current descriptor in the chain we can calculate
 		 * the remaining bytes using the channel's register.
 		 */
-		ret = atc_calc_bytes_left(ret, ctrla);
+		*residue = atc_calc_bytes_left(len, ctrla);
 	} else {
 		/* single transfer */
 		ctrla = channel_readl(atchan, CTRLA);
-		ret = atc_calc_bytes_left(ret, ctrla);
+		*residue = atc_calc_bytes_left(len, ctrla);
 	}
 
-	return ret;
+	return 0;
 }
 
 /**
@@ -1457,31 +1462,32 @@ atc_tx_status(struct dma_chan *chan,
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	unsigned long		flags;
-	enum dma_status		ret;
-	int bytes = 0;
+	enum dma_status		dma_status;
+	u32 residue;
+	int ret;
 
-	ret = dma_cookie_status(chan, cookie, txstate);
-	if (ret == DMA_COMPLETE || !txstate)
-		return ret;
+	dma_status = dma_cookie_status(chan, cookie, txstate);
+	if (dma_status == DMA_COMPLETE || !txstate)
+		return dma_status;
 
 	spin_lock_irqsave(&atchan->lock, flags);
 
 	/*  Get number of bytes left in the active transactions */
-	bytes = atc_get_bytes_left(chan, cookie);
+	ret = atc_get_bytes_left(chan, cookie, &residue);
 
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
-	if (unlikely(bytes < 0)) {
+	if (unlikely(ret < 0)) {
 		dev_vdbg(chan2dev(chan), "get residual bytes error\n");
 		return DMA_ERROR;
 	} else {
-		dma_set_residue(txstate, bytes);
+		dma_set_residue(txstate, residue);
 	}
 
-	dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d residue = %d\n",
-		 ret, cookie, bytes);
+	dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d residue = %u\n",
+		 dma_status, cookie, residue);
 
-	return ret;
+	return dma_status;
 }
 
 /**
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 20/32] dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (18 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 19/32] dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 21/32] dmaengine: at_hdmac: Introduce atc_get_llis_residue() Tudor Ambarus
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Use dmaengine terminology and rename the method to better indicate what it
does: it gets the residue value which will be later on set with
dma_set_residue().

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index e2c46f32b284..6c328cd16983 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -308,15 +308,15 @@ static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla)
 }
 
 /**
- * atc_get_bytes_left - get the number of bytes residue for a cookie.
+ * atc_get_residue - get the number of bytes residue for a cookie.
  * The residue is passed by address and updated on success.
  * @chan: DMA channel
  * @cookie: transaction identifier to check status of
  * @residue: residue to be updated.
  * Return 0 on success, -errono otherwise.
  */
-static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie,
-			      u32 *residue)
+static int atc_get_residue(struct dma_chan *chan, dma_cookie_t cookie,
+			   u32 *residue)
 {
 	struct at_dma_chan      *atchan = to_at_dma_chan(chan);
 	struct at_desc *desc_first = atc_first_active(atchan);
@@ -1471,10 +1471,7 @@ atc_tx_status(struct dma_chan *chan,
 		return dma_status;
 
 	spin_lock_irqsave(&atchan->lock, flags);
-
-	/*  Get number of bytes left in the active transactions */
-	ret = atc_get_bytes_left(chan, cookie, &residue);
-
+	ret = atc_get_residue(chan, cookie, &residue);
 	spin_unlock_irqrestore(&atchan->lock, flags);
 
 	if (unlikely(ret < 0)) {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 21/32] dmaengine: at_hdmac: Introduce atc_get_llis_residue()
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (19 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 20/32] dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 22/32] dmaengine: at_hdmac: Use devm_kzalloc() and struct_size() Tudor Ambarus
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Introduce a method to get the residue for a hardware linked list transfer.
It makes the code easier to read.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 221 ++++++++++++++++++++---------------------
 1 file changed, 110 insertions(+), 111 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 6c328cd16983..6bd9e35db8f9 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -307,6 +307,109 @@ static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla)
 	return current_len - (btsize << src_width);
 }
 
+/**
+ * atc_get_llis_residue - Get residue for a hardware linked list transfer
+ *
+ * Calculate the residue by removing the length of the child descriptors already
+ * transferred from the total length. To get the current child descriptor we can
+ * use the value of the channel's DSCR register and compare it against the value
+ * of the hardware linked list structure of each child descriptor.
+ *
+ * The CTRLA register provides us with the amount of data already read from the
+ * source for the current child descriptor. So we can compute a more accurate
+ * residue by also removing the number of bytes corresponding to this amount of
+ * data.
+ *
+ * However, the DSCR and CTRLA registers cannot be read both atomically. Hence a
+ * race condition may occur: the first read register may refer to one child
+ * descriptor whereas the second read may refer to a later child descriptor in
+ * the list because of the DMA transfer progression inbetween the two reads.
+ *
+ * One solution could have been to pause the DMA transfer, read the DSCR and
+ * CTRLA then resume the DMA transfer. Nonetheless, this approach presents some
+ * drawbacks:
+ * - If the DMA transfer is paused, RX overruns or TX underruns are more likey
+ *   to occur depending on the system latency. Taking the USART driver as an
+ *   example, it uses a cyclic DMA transfer to read data from the Receive
+ *   Holding Register (RHR) to avoid RX overruns since the RHR is not protected
+ *   by any FIFO on most Atmel SoCs. So pausing the DMA transfer to compute the
+ *   residue would break the USART driver design.
+ * - The atc_pause() function masks interrupts but we'd rather avoid to do so
+ * for system latency purpose.
+ *
+ * Then we'd rather use another solution: the DSCR is read a first time, the
+ * CTRLA is read in turn, next the DSCR is read a second time. If the two
+ * consecutive read values of the DSCR are the same then we assume both refers
+ * to the very same child descriptor as well as the CTRLA value read inbetween
+ * does. For cyclic tranfers, the assumption is that a full loop is "not so
+ * fast". If the two DSCR values are different, we read again the CTRLA then the
+ * DSCR till two consecutive read values from DSCR are equal or till the
+ * maximum trials is reach. This algorithm is very unlikely not to find a stable
+ * value for DSCR.
+ * @atchan: pointer to an atmel hdmac channel.
+ * @desc: pointer to the descriptor for which the residue is calculated.
+ * @residue: residue to be set to dma_tx_state.
+ * Returns 0 on success, -errno otherwise.
+ */
+static int atc_get_llis_residue(struct at_dma_chan *atchan,
+				struct at_desc *desc, u32 *residue)
+{
+	struct at_desc *child;
+	u32 len, ctrla, dscr;
+	unsigned int i;
+
+	len = desc->total_len;
+	dscr = channel_readl(atchan, DSCR);
+	rmb(); /* ensure DSCR is read before CTRLA */
+	ctrla = channel_readl(atchan, CTRLA);
+	for (i = 0; i < ATC_MAX_DSCR_TRIALS; ++i) {
+		u32 new_dscr;
+
+		rmb(); /* ensure DSCR is read after CTRLA */
+		new_dscr = channel_readl(atchan, DSCR);
+
+		/*
+		 * If the DSCR register value has not changed inside the DMA
+		 * controller since the previous read, we assume that both the
+		 * dscr and ctrla values refers to the very same descriptor.
+		 */
+		if (likely(new_dscr == dscr))
+			break;
+
+		/*
+		 * DSCR has changed inside the DMA controller, so the previouly
+		 * read value of CTRLA may refer to an already processed
+		 * descriptor hence could be outdated. We need to update ctrla
+		 * to match the current descriptor.
+		 */
+		dscr = new_dscr;
+		rmb(); /* ensure DSCR is read before CTRLA */
+		ctrla = channel_readl(atchan, CTRLA);
+	}
+	if (unlikely(i == ATC_MAX_DSCR_TRIALS))
+		return -ETIMEDOUT;
+
+	/* For the first descriptor we can be more accurate. */
+	if (desc->lli.dscr == dscr) {
+		*residue = atc_calc_bytes_left(len, ctrla);
+		return 0;
+	}
+
+	len -= desc->len;
+	list_for_each_entry(child, &desc->tx_list, desc_node) {
+		if (child->lli.dscr == dscr)
+			break;
+		len -= child->len;
+	}
+
+	/*
+	 * For the current descriptor in the chain we can calculate the
+	 * remaining bytes using the channel's register.
+	 */
+	*residue = atc_calc_bytes_left(len, ctrla);
+	return 0;
+}
+
 /**
  * atc_get_residue - get the number of bytes residue for a cookie.
  * The residue is passed by address and updated on success.
@@ -321,8 +424,7 @@ static int atc_get_residue(struct dma_chan *chan, dma_cookie_t cookie,
 	struct at_dma_chan      *atchan = to_at_dma_chan(chan);
 	struct at_desc *desc_first = atc_first_active(atchan);
 	struct at_desc *desc;
-	u32 len, ctrla, dscr;
-	unsigned int i;
+	u32 len, ctrla;
 
 	/*
 	 * If the cookie doesn't match to the currently running transfer then
@@ -335,117 +437,14 @@ static int atc_get_residue(struct dma_chan *chan, dma_cookie_t cookie,
 	else if (desc != desc_first)
 		return desc->total_len;
 
-	/* cookie matches to the currently running transfer */
-	len = desc_first->total_len;
-
-	if (desc_first->lli.dscr) {
+	if (desc_first->lli.dscr)
 		/* hardware linked list transfer */
+		return atc_get_llis_residue(atchan, desc_first, residue);
 
-		/*
-		 * Calculate the residue by removing the length of the child
-		 * descriptors already transferred from the total length.
-		 * To get the current child descriptor we can use the value of
-		 * the channel's DSCR register and compare it against the value
-		 * of the hardware linked list structure of each child
-		 * descriptor.
-		 *
-		 * The CTRLA register provides us with the amount of data
-		 * already read from the source for the current child
-		 * descriptor. So we can compute a more accurate residue by also
-		 * removing the number of bytes corresponding to this amount of
-		 * data.
-		 *
-		 * However, the DSCR and CTRLA registers cannot be read both
-		 * atomically. Hence a race condition may occur: the first read
-		 * register may refer to one child descriptor whereas the second
-		 * read may refer to a later child descriptor in the list
-		 * because of the DMA transfer progression inbetween the two
-		 * reads.
-		 *
-		 * One solution could have been to pause the DMA transfer, read
-		 * the DSCR and CTRLA then resume the DMA transfer. Nonetheless,
-		 * this approach presents some drawbacks:
-		 * - If the DMA transfer is paused, RX overruns or TX underruns
-		 *   are more likey to occur depending on the system latency.
-		 *   Taking the USART driver as an example, it uses a cyclic DMA
-		 *   transfer to read data from the Receive Holding Register
-		 *   (RHR) to avoid RX overruns since the RHR is not protected
-		 *   by any FIFO on most Atmel SoCs. So pausing the DMA transfer
-		 *   to compute the residue would break the USART driver design.
-		 * - The atc_pause() function masks interrupts but we'd rather
-		 *   avoid to do so for system latency purpose.
-		 *
-		 * Then we'd rather use another solution: the DSCR is read a
-		 * first time, the CTRLA is read in turn, next the DSCR is read
-		 * a second time. If the two consecutive read values of the DSCR
-		 * are the same then we assume both refers to the very same
-		 * child descriptor as well as the CTRLA value read inbetween
-		 * does. For cyclic tranfers, the assumption is that a full loop
-		 * is "not so fast".
-		 * If the two DSCR values are different, we read again the CTRLA
-		 * then the DSCR till two consecutive read values from DSCR are
-		 * equal or till the maxium trials is reach.
-		 * This algorithm is very unlikely not to find a stable value for
-		 * DSCR.
-		 */
-
-		dscr = channel_readl(atchan, DSCR);
-		rmb(); /* ensure DSCR is read before CTRLA */
-		ctrla = channel_readl(atchan, CTRLA);
-		for (i = 0; i < ATC_MAX_DSCR_TRIALS; ++i) {
-			u32 new_dscr;
-
-			rmb(); /* ensure DSCR is read after CTRLA */
-			new_dscr = channel_readl(atchan, DSCR);
-
-			/*
-			 * If the DSCR register value has not changed inside the
-			 * DMA controller since the previous read, we assume
-			 * that both the dscr and ctrla values refers to the
-			 * very same descriptor.
-			 */
-			if (likely(new_dscr == dscr))
-				break;
-
-			/*
-			 * DSCR has changed inside the DMA controller, so the
-			 * previouly read value of CTRLA may refer to an already
-			 * processed descriptor hence could be outdated.
-			 * We need to update ctrla to match the current
-			 * descriptor.
-			 */
-			dscr = new_dscr;
-			rmb(); /* ensure DSCR is read before CTRLA */
-			ctrla = channel_readl(atchan, CTRLA);
-		}
-		if (unlikely(i == ATC_MAX_DSCR_TRIALS))
-			return -ETIMEDOUT;
-
-		/* for the first descriptor we can be more accurate */
-		if (desc_first->lli.dscr == dscr) {
-			*residue = atc_calc_bytes_left(len, ctrla);
-			return 0;
-		}
-
-		len -= desc_first->len;
-		list_for_each_entry(desc, &desc_first->tx_list, desc_node) {
-			if (desc->lli.dscr == dscr)
-				break;
-
-			len -= desc->len;
-		}
-
-		/*
-		 * For the current descriptor in the chain we can calculate
-		 * the remaining bytes using the channel's register.
-		 */
-		*residue = atc_calc_bytes_left(len, ctrla);
-	} else {
-		/* single transfer */
-		ctrla = channel_readl(atchan, CTRLA);
-		*residue = atc_calc_bytes_left(len, ctrla);
-	}
-
+	/* single transfer */
+	len = desc_first->total_len;
+	ctrla = channel_readl(atchan, CTRLA);
+	*residue = atc_calc_bytes_left(len, ctrla);
 	return 0;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 22/32] dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (20 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 21/32] dmaengine: at_hdmac: Introduce atc_get_llis_residue() Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 23/32] dmaengine: at_hdmac: Use devm_platform_ioremap_resource Tudor Ambarus
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Use the resource-managed kzalloc to simplify error logic. Memory allocated
with this function is automatically freed on driver detach. Use
struct_size() helper to calculate the size of the atdma structure with its
trailing flexible array. While here, move the mem allocation higher in the
probe method, as failing to allocate memory indicates a serious system
issue, and everything else does not matter anyway. All these help the code
look a bit cleaner.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 23 +++++++++--------------
 1 file changed, 9 insertions(+), 14 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 6bd9e35db8f9..f3fbb0aa8b24 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/overflow.h>
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
 
@@ -1786,6 +1787,12 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	if (!plat_dat)
 		return -ENODEV;
 
+	atdma = devm_kzalloc(&pdev->dev,
+			     struct_size(atdma, chan, plat_dat->nr_channels),
+			     GFP_KERNEL);
+	if (!atdma)
+		return -ENOMEM;
+
 	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!io)
 		return -EINVAL;
@@ -1794,21 +1801,13 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
-	size = sizeof(struct at_dma);
-	size += plat_dat->nr_channels * sizeof(struct at_dma_chan);
-	atdma = kzalloc(size, GFP_KERNEL);
-	if (!atdma)
-		return -ENOMEM;
-
 	/* discover transaction capabilities */
 	atdma->dma_common.cap_mask = plat_dat->cap_mask;
 	atdma->all_chan_mask = (1 << plat_dat->nr_channels) - 1;
 
 	size = resource_size(io);
-	if (!request_mem_region(io->start, size, pdev->dev.driver->name)) {
-		err = -EBUSY;
-		goto err_kfree;
-	}
+	if (!request_mem_region(io->start, size, pdev->dev.driver->name))
+		return -EBUSY;
 
 	atdma->regs = ioremap(io->start, size);
 	if (!atdma->regs) {
@@ -1963,8 +1962,6 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	atdma->regs = NULL;
 err_release_r:
 	release_mem_region(io->start, size);
-err_kfree:
-	kfree(atdma);
 	return err;
 }
 
@@ -2003,8 +2000,6 @@ static int at_dma_remove(struct platform_device *pdev)
 	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(io->start, resource_size(io));
 
-	kfree(atdma);
-
 	return 0;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 23/32] dmaengine: at_hdmac: Use devm_platform_ioremap_resource
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (21 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 22/32] dmaengine: at_hdmac: Use devm_kzalloc() and struct_size() Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 24/32] dmaengine: at_hdmac: Use devm_clk_get() Tudor Ambarus
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Use devm_platform_ioremap_resource() helper for cleanner code and easier
resource management.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 37 ++++++-------------------------------
 1 file changed, 6 insertions(+), 31 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index f3fbb0aa8b24..10c250618a33 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1765,9 +1765,7 @@ static void at_dma_off(struct at_dma *atdma)
 
 static int __init at_dma_probe(struct platform_device *pdev)
 {
-	struct resource		*io;
 	struct at_dma		*atdma;
-	size_t			size;
 	int			irq;
 	int			err;
 	int			i;
@@ -1793,9 +1791,9 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	if (!atdma)
 		return -ENOMEM;
 
-	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!io)
-		return -EINVAL;
+	atdma->regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(atdma->regs))
+		return PTR_ERR(atdma->regs);
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -1805,21 +1803,10 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	atdma->dma_common.cap_mask = plat_dat->cap_mask;
 	atdma->all_chan_mask = (1 << plat_dat->nr_channels) - 1;
 
-	size = resource_size(io);
-	if (!request_mem_region(io->start, size, pdev->dev.driver->name))
-		return -EBUSY;
-
-	atdma->regs = ioremap(io->start, size);
-	if (!atdma->regs) {
-		err = -ENOMEM;
-		goto err_release_r;
-	}
-
 	atdma->clk = clk_get(&pdev->dev, "dma_clk");
-	if (IS_ERR(atdma->clk)) {
-		err = PTR_ERR(atdma->clk);
-		goto err_clk;
-	}
+	if (IS_ERR(atdma->clk))
+		return PTR_ERR(atdma->clk);
+
 	err = clk_prepare_enable(atdma->clk);
 	if (err)
 		goto err_clk_prepare;
@@ -1957,11 +1944,6 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	clk_disable_unprepare(atdma->clk);
 err_clk_prepare:
 	clk_put(atdma->clk);
-err_clk:
-	iounmap(atdma->regs);
-	atdma->regs = NULL;
-err_release_r:
-	release_mem_region(io->start, size);
 	return err;
 }
 
@@ -1969,7 +1951,6 @@ static int at_dma_remove(struct platform_device *pdev)
 {
 	struct at_dma		*atdma = platform_get_drvdata(pdev);
 	struct dma_chan		*chan, *_chan;
-	struct resource		*io;
 
 	at_dma_off(atdma);
 	if (pdev->dev.of_node)
@@ -1994,12 +1975,6 @@ static int at_dma_remove(struct platform_device *pdev)
 	clk_disable_unprepare(atdma->clk);
 	clk_put(atdma->clk);
 
-	iounmap(atdma->regs);
-	atdma->regs = NULL;
-
-	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(io->start, resource_size(io));
-
 	return 0;
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 24/32] dmaengine: at_hdmac: Use devm_clk_get()
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (22 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 23/32] dmaengine: at_hdmac: Use devm_platform_ioremap_resource Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:02 ` [PATCH v2 25/32] dmaengine: at_hdmac: Use pm_ptr() Tudor Ambarus
                   ` (10 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Clocks that are get with this method will be automatically put on driver
detach. Use devm_clk_get() and simplify the error handling.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 10c250618a33..444aa7d75ff5 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1803,13 +1803,13 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	atdma->dma_common.cap_mask = plat_dat->cap_mask;
 	atdma->all_chan_mask = (1 << plat_dat->nr_channels) - 1;
 
-	atdma->clk = clk_get(&pdev->dev, "dma_clk");
+	atdma->clk = devm_clk_get(&pdev->dev, "dma_clk");
 	if (IS_ERR(atdma->clk))
 		return PTR_ERR(atdma->clk);
 
 	err = clk_prepare_enable(atdma->clk);
 	if (err)
-		goto err_clk_prepare;
+		return err;
 
 	/* force dma off, just in case */
 	at_dma_off(atdma);
@@ -1942,8 +1942,6 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	free_irq(platform_get_irq(pdev, 0), atdma);
 err_irq:
 	clk_disable_unprepare(atdma->clk);
-err_clk_prepare:
-	clk_put(atdma->clk);
 	return err;
 }
 
@@ -1973,7 +1971,6 @@ static int at_dma_remove(struct platform_device *pdev)
 	}
 
 	clk_disable_unprepare(atdma->clk);
-	clk_put(atdma->clk);
 
 	return 0;
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 25/32] dmaengine: at_hdmac: Use pm_ptr()
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (23 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 24/32] dmaengine: at_hdmac: Use devm_clk_get() Tudor Ambarus
@ 2022-10-25  9:02 ` Tudor Ambarus
  2022-10-25  9:03 ` [PATCH v2 26/32] dmaengine: at_hdmac: Set include entries in alphabetic order Tudor Ambarus
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:02 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Use pm_ptr() macro to fill at_dma_driver.driver.pm. In case CONFIG_PM is
not enabled, the macro will return NULL. When NULL, at_dma_dev_pm_ops will
end up being unused, so prepend it with the __maybe_unused attribute.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 444aa7d75ff5..4e3c519e6079 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -2084,7 +2084,7 @@ static int at_dma_resume_noirq(struct device *dev)
 	return 0;
 }
 
-static const struct dev_pm_ops at_dma_dev_pm_ops = {
+static const struct dev_pm_ops __maybe_unused at_dma_dev_pm_ops = {
 	.prepare = at_dma_prepare,
 	.suspend_noirq = at_dma_suspend_noirq,
 	.resume_noirq = at_dma_resume_noirq,
@@ -2096,7 +2096,7 @@ static struct platform_driver at_dma_driver = {
 	.id_table	= atdma_devtypes,
 	.driver = {
 		.name	= "at_hdmac",
-		.pm	= &at_dma_dev_pm_ops,
+		.pm	= pm_ptr(&at_dma_dev_pm_ops),
 		.of_match_table	= of_match_ptr(atmel_dma_dt_ids),
 	},
 };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 26/32] dmaengine: at_hdmac: Set include entries in alphabetic order
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (24 preceding siblings ...)
  2022-10-25  9:02 ` [PATCH v2 25/32] dmaengine: at_hdmac: Use pm_ptr() Tudor Ambarus
@ 2022-10-25  9:03 ` Tudor Ambarus
  2022-10-25  9:03 ` [PATCH v2 27/32] dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c Tudor Ambarus
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:03 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

It's a good practice to set the include entries in alphabetic order. It
helps humans to read the code easier. Alphabetic order should also prove
that each header is self-contained, i.e. can be included without
prerequisites.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 4e3c519e6079..a3fa8bffdb74 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -12,16 +12,16 @@
 #include <dt-bindings/dma/at91.h>
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/overflow.h>
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
 
 #include "at_hdmac_regs.h"
 #include "dmaengine.h"
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 27/32] dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (25 preceding siblings ...)
  2022-10-25  9:03 ` [PATCH v2 26/32] dmaengine: at_hdmac: Set include entries in alphabetic order Tudor Ambarus
@ 2022-10-25  9:03 ` Tudor Ambarus
  2022-10-25  9:03 ` [PATCH v2 28/32] dmaengine: at_hdmac: Use bitfield access macros Tudor Ambarus
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:03 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Do not expose register definitions, structures and helpers via a .h file
because there are used only by at_hdmac.c. Since there are no other users,
remove the ambiguity and move all the .h contents to the .c file.

One may notice some checkpatch warnings and errors with this move. The move
was done "as it was", checkpatch complaints can be fixed in a further
patch.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 MAINTAINERS                 |   1 -
 drivers/dma/at_hdmac.c      | 469 ++++++++++++++++++++++++++++++++++-
 drivers/dma/at_hdmac_regs.h | 478 ------------------------------------
 3 files changed, 468 insertions(+), 480 deletions(-)
 delete mode 100644 drivers/dma/at_hdmac_regs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index cf0f18502372..0fd65ca63218 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13420,7 +13420,6 @@ L:	dmaengine@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/dma/atmel-dma.txt
 F:	drivers/dma/at_hdmac.c
-F:	drivers/dma/at_hdmac_regs.h
 F:	drivers/dma/at_xdmac.c
 F:	include/dt-bindings/dma/at91.h
 
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index a3fa8bffdb74..a07e3355f09a 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -23,7 +23,6 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-#include "at_hdmac_regs.h"
 #include "dmaengine.h"
 
 /*
@@ -35,6 +34,474 @@
  * atc_	/ atchan	: ATmel DMA Channel entity related
  */
 
+#define	AT_DMA_MAX_NR_CHANNELS	8
+
+
+#define	AT_DMA_GCFG	0x00	/* Global Configuration Register */
+#define		AT_DMA_IF_BIGEND(i)	(0x1 << (i))	/* AHB-Lite Interface i in Big-endian mode */
+#define		AT_DMA_ARB_CFG	(0x1 << 4)	/* Arbiter mode. */
+#define			AT_DMA_ARB_CFG_FIXED		(0x0 << 4)
+#define			AT_DMA_ARB_CFG_ROUND_ROBIN	(0x1 << 4)
+
+#define	AT_DMA_EN	0x04	/* Controller Enable Register */
+#define		AT_DMA_ENABLE	(0x1 << 0)
+
+#define	AT_DMA_SREQ	0x08	/* Software Single Request Register */
+#define		AT_DMA_SSREQ(x)	(0x1 << ((x) << 1))		/* Request a source single transfer on channel x */
+#define		AT_DMA_DSREQ(x)	(0x1 << (1 + ((x) << 1)))	/* Request a destination single transfer on channel x */
+
+#define	AT_DMA_CREQ	0x0C	/* Software Chunk Transfer Request Register */
+#define		AT_DMA_SCREQ(x)	(0x1 << ((x) << 1))		/* Request a source chunk transfer on channel x */
+#define		AT_DMA_DCREQ(x)	(0x1 << (1 + ((x) << 1)))	/* Request a destination chunk transfer on channel x */
+
+#define	AT_DMA_LAST	0x10	/* Software Last Transfer Flag Register */
+#define		AT_DMA_SLAST(x)	(0x1 << ((x) << 1))		/* This src rq is last tx of buffer on channel x */
+#define		AT_DMA_DLAST(x)	(0x1 << (1 + ((x) << 1)))	/* This dst rq is last tx of buffer on channel x */
+
+#define	AT_DMA_SYNC	0x14	/* Request Synchronization Register */
+#define		AT_DMA_SYR(h)	(0x1 << (h))			/* Synchronize handshake line h */
+
+/* Error, Chained Buffer transfer completed and Buffer transfer completed Interrupt registers */
+#define	AT_DMA_EBCIER	0x18	/* Enable register */
+#define	AT_DMA_EBCIDR	0x1C	/* Disable register */
+#define	AT_DMA_EBCIMR	0x20	/* Mask Register */
+#define	AT_DMA_EBCISR	0x24	/* Status Register */
+#define		AT_DMA_CBTC_OFFSET	8
+#define		AT_DMA_ERR_OFFSET	16
+#define		AT_DMA_BTC(x)	(0x1 << (x))
+#define		AT_DMA_CBTC(x)	(0x1 << (AT_DMA_CBTC_OFFSET + (x)))
+#define		AT_DMA_ERR(x)	(0x1 << (AT_DMA_ERR_OFFSET + (x)))
+
+#define	AT_DMA_CHER	0x28	/* Channel Handler Enable Register */
+#define		AT_DMA_ENA(x)	(0x1 << (x))
+#define		AT_DMA_SUSP(x)	(0x1 << ( 8 + (x)))
+#define		AT_DMA_KEEP(x)	(0x1 << (24 + (x)))
+
+#define	AT_DMA_CHDR	0x2C	/* Channel Handler Disable Register */
+#define		AT_DMA_DIS(x)	(0x1 << (x))
+#define		AT_DMA_RES(x)	(0x1 << ( 8 + (x)))
+
+#define	AT_DMA_CHSR	0x30	/* Channel Handler Status Register */
+#define		AT_DMA_EMPT(x)	(0x1 << (16 + (x)))
+#define		AT_DMA_STAL(x)	(0x1 << (24 + (x)))
+
+
+#define	AT_DMA_CH_REGS_BASE	0x3C	/* Channel registers base address */
+#define	ch_regs(x)	(AT_DMA_CH_REGS_BASE + (x) * 0x28) /* Channel x base addr */
+
+/* Hardware register offset for each channel */
+#define	ATC_SADDR_OFFSET	0x00	/* Source Address Register */
+#define	ATC_DADDR_OFFSET	0x04	/* Destination Address Register */
+#define	ATC_DSCR_OFFSET		0x08	/* Descriptor Address Register */
+#define	ATC_CTRLA_OFFSET	0x0C	/* Control A Register */
+#define	ATC_CTRLB_OFFSET	0x10	/* Control B Register */
+#define	ATC_CFG_OFFSET		0x14	/* Configuration Register */
+#define	ATC_SPIP_OFFSET		0x18	/* Src PIP Configuration Register */
+#define	ATC_DPIP_OFFSET		0x1C	/* Dst PIP Configuration Register */
+
+
+/* Bitfield definitions */
+
+/* Bitfields in DSCR */
+#define	ATC_DSCR_IF(i)		(0x3 & (i))	/* Dsc feched via AHB-Lite Interface i */
+
+/* Bitfields in CTRLA */
+#define	ATC_BTSIZE_MAX		0xFFFFUL	/* Maximum Buffer Transfer Size */
+#define	ATC_BTSIZE(x)		(ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
+#define	ATC_SCSIZE_MASK		(0x7 << 16)	/* Source Chunk Transfer Size */
+#define		ATC_SCSIZE(x)		(ATC_SCSIZE_MASK & ((x) << 16))
+#define		ATC_SCSIZE_1		(0x0 << 16)
+#define		ATC_SCSIZE_4		(0x1 << 16)
+#define		ATC_SCSIZE_8		(0x2 << 16)
+#define		ATC_SCSIZE_16		(0x3 << 16)
+#define		ATC_SCSIZE_32		(0x4 << 16)
+#define		ATC_SCSIZE_64		(0x5 << 16)
+#define		ATC_SCSIZE_128		(0x6 << 16)
+#define		ATC_SCSIZE_256		(0x7 << 16)
+#define	ATC_DCSIZE_MASK		(0x7 << 20)	/* Destination Chunk Transfer Size */
+#define		ATC_DCSIZE(x)		(ATC_DCSIZE_MASK & ((x) << 20))
+#define		ATC_DCSIZE_1		(0x0 << 20)
+#define		ATC_DCSIZE_4		(0x1 << 20)
+#define		ATC_DCSIZE_8		(0x2 << 20)
+#define		ATC_DCSIZE_16		(0x3 << 20)
+#define		ATC_DCSIZE_32		(0x4 << 20)
+#define		ATC_DCSIZE_64		(0x5 << 20)
+#define		ATC_DCSIZE_128		(0x6 << 20)
+#define		ATC_DCSIZE_256		(0x7 << 20)
+#define	ATC_SRC_WIDTH_MASK	(0x3 << 24)	/* Source Single Transfer Size */
+#define		ATC_SRC_WIDTH(x)	((x) << 24)
+#define		ATC_SRC_WIDTH_BYTE	(0x0 << 24)
+#define		ATC_SRC_WIDTH_HALFWORD	(0x1 << 24)
+#define		ATC_SRC_WIDTH_WORD	(0x2 << 24)
+#define		ATC_REG_TO_SRC_WIDTH(r)	(((r) >> 24) & 0x3)
+#define	ATC_DST_WIDTH_MASK	(0x3 << 28)	/* Destination Single Transfer Size */
+#define		ATC_DST_WIDTH(x)	((x) << 28)
+#define		ATC_DST_WIDTH_BYTE	(0x0 << 28)
+#define		ATC_DST_WIDTH_HALFWORD	(0x1 << 28)
+#define		ATC_DST_WIDTH_WORD	(0x2 << 28)
+#define	ATC_DONE		(0x1 << 31)	/* Tx Done (only written back in descriptor) */
+
+/* Bitfields in CTRLB */
+#define	ATC_SIF(i)		(0x3 & (i))	/* Src tx done via AHB-Lite Interface i */
+#define	ATC_DIF(i)		((0x3 & (i)) <<  4)	/* Dst tx done via AHB-Lite Interface i */
+				  /* Specify AHB interfaces */
+#define AT_DMA_MEM_IF		0 /* interface 0 as memory interface */
+#define AT_DMA_PER_IF		1 /* interface 1 as peripheral interface */
+
+#define	ATC_SRC_PIP		(0x1 <<  8)	/* Source Picture-in-Picture enabled */
+#define	ATC_DST_PIP		(0x1 << 12)	/* Destination Picture-in-Picture enabled */
+#define	ATC_SRC_DSCR_DIS	(0x1 << 16)	/* Src Descriptor fetch disable */
+#define	ATC_DST_DSCR_DIS	(0x1 << 20)	/* Dst Descriptor fetch disable */
+#define	ATC_FC_MASK		(0x7 << 21)	/* Choose Flow Controller */
+#define		ATC_FC_MEM2MEM		(0x0 << 21)	/* Mem-to-Mem (DMA) */
+#define		ATC_FC_MEM2PER		(0x1 << 21)	/* Mem-to-Periph (DMA) */
+#define		ATC_FC_PER2MEM		(0x2 << 21)	/* Periph-to-Mem (DMA) */
+#define		ATC_FC_PER2PER		(0x3 << 21)	/* Periph-to-Periph (DMA) */
+#define		ATC_FC_PER2MEM_PER	(0x4 << 21)	/* Periph-to-Mem (Peripheral) */
+#define		ATC_FC_MEM2PER_PER	(0x5 << 21)	/* Mem-to-Periph (Peripheral) */
+#define		ATC_FC_PER2PER_SRCPER	(0x6 << 21)	/* Periph-to-Periph (Src Peripheral) */
+#define		ATC_FC_PER2PER_DSTPER	(0x7 << 21)	/* Periph-to-Periph (Dst Peripheral) */
+#define	ATC_SRC_ADDR_MODE_MASK	(0x3 << 24)
+#define		ATC_SRC_ADDR_MODE_INCR	(0x0 << 24)	/* Incrementing Mode */
+#define		ATC_SRC_ADDR_MODE_DECR	(0x1 << 24)	/* Decrementing Mode */
+#define		ATC_SRC_ADDR_MODE_FIXED	(0x2 << 24)	/* Fixed Mode */
+#define	ATC_DST_ADDR_MODE_MASK	(0x3 << 28)
+#define		ATC_DST_ADDR_MODE_INCR	(0x0 << 28)	/* Incrementing Mode */
+#define		ATC_DST_ADDR_MODE_DECR	(0x1 << 28)	/* Decrementing Mode */
+#define		ATC_DST_ADDR_MODE_FIXED	(0x2 << 28)	/* Fixed Mode */
+#define	ATC_IEN			(0x1 << 30)	/* BTC interrupt enable (active low) */
+#define	ATC_AUTO		(0x1 << 31)	/* Auto multiple buffer tx enable */
+
+/* Bitfields in CFG */
+#define ATC_PER_MSB(h)	((0x30U & (h)) >> 4)	/* Extract most significant bits of a handshaking identifier */
+
+#define	ATC_SRC_PER(h)		(0xFU & (h))	/* Channel src rq associated with periph handshaking ifc h */
+#define	ATC_DST_PER(h)		((0xFU & (h)) <<  4)	/* Channel dst rq associated with periph handshaking ifc h */
+#define	ATC_SRC_REP		(0x1 <<  8)	/* Source Replay Mod */
+#define	ATC_SRC_H2SEL		(0x1 <<  9)	/* Source Handshaking Mod */
+#define		ATC_SRC_H2SEL_SW	(0x0 <<  9)
+#define		ATC_SRC_H2SEL_HW	(0x1 <<  9)
+#define	ATC_SRC_PER_MSB(h)	(ATC_PER_MSB(h) << 10)	/* Channel src rq (most significant bits) */
+#define	ATC_DST_REP		(0x1 << 12)	/* Destination Replay Mod */
+#define	ATC_DST_H2SEL		(0x1 << 13)	/* Destination Handshaking Mod */
+#define		ATC_DST_H2SEL_SW	(0x0 << 13)
+#define		ATC_DST_H2SEL_HW	(0x1 << 13)
+#define	ATC_DST_PER_MSB(h)	(ATC_PER_MSB(h) << 14)	/* Channel dst rq (most significant bits) */
+#define	ATC_SOD			(0x1 << 16)	/* Stop On Done */
+#define	ATC_LOCK_IF		(0x1 << 20)	/* Interface Lock */
+#define	ATC_LOCK_B		(0x1 << 21)	/* AHB Bus Lock */
+#define	ATC_LOCK_IF_L		(0x1 << 22)	/* Master Interface Arbiter Lock */
+#define		ATC_LOCK_IF_L_CHUNK	(0x0 << 22)
+#define		ATC_LOCK_IF_L_BUFFER	(0x1 << 22)
+#define	ATC_AHB_PROT_MASK	(0x7 << 24)	/* AHB Protection */
+#define	ATC_FIFOCFG_MASK	(0x3 << 28)	/* FIFO Request Configuration */
+#define		ATC_FIFOCFG_LARGESTBURST	(0x0 << 28)
+#define		ATC_FIFOCFG_HALFFIFO		(0x1 << 28)
+#define		ATC_FIFOCFG_ENOUGHSPACE		(0x2 << 28)
+
+/* Bitfields in SPIP */
+#define	ATC_SPIP_HOLE(x)	(0xFFFFU & (x))
+#define	ATC_SPIP_BOUNDARY(x)	((0x3FF & (x)) << 16)
+
+/* Bitfields in DPIP */
+#define	ATC_DPIP_HOLE(x)	(0xFFFFU & (x))
+#define	ATC_DPIP_BOUNDARY(x)	((0x3FF & (x)) << 16)
+
+
+/*--  descriptors  -----------------------------------------------------*/
+
+/* LLI == Linked List Item; aka DMA buffer descriptor */
+struct at_lli {
+	/* values that are not changed by hardware */
+	u32 saddr;
+	u32 daddr;
+	/* value that may get written back: */
+	u32 ctrla;
+	/* more values that are not changed by hardware */
+	u32 ctrlb;
+	u32 dscr;	/* chain to next lli */
+};
+
+/**
+ * struct at_desc - software descriptor
+ * @at_lli: hardware lli structure
+ * @txd: support for the async_tx api
+ * @desc_node: node on the channed descriptors list
+ * @len: descriptor byte count
+ * @total_len: total transaction byte count
+ */
+struct at_desc {
+	/* FIRST values the hardware uses */
+	struct at_lli			lli;
+
+	/* THEN values for driver housekeeping */
+	struct list_head		tx_list;
+	struct dma_async_tx_descriptor	txd;
+	struct list_head		desc_node;
+	size_t				len;
+	size_t				total_len;
+
+	/* Interleaved data */
+	size_t				boundary;
+	size_t				dst_hole;
+	size_t				src_hole;
+
+	/* Memset temporary buffer */
+	bool				memset_buffer;
+	dma_addr_t			memset_paddr;
+	int				*memset_vaddr;
+};
+
+static inline struct at_desc *
+txd_to_at_desc(struct dma_async_tx_descriptor *txd)
+{
+	return container_of(txd, struct at_desc, txd);
+}
+
+
+/*--  Channels  --------------------------------------------------------*/
+
+/**
+ * atc_status - information bits stored in channel status flag
+ *
+ * Manipulated with atomic operations.
+ */
+enum atc_status {
+	ATC_IS_ERROR = 0,
+	ATC_IS_PAUSED = 1,
+	ATC_IS_CYCLIC = 24,
+};
+
+/**
+ * struct at_dma_chan - internal representation of an Atmel HDMAC channel
+ * @chan_common: common dmaengine channel object members
+ * @device: parent device
+ * @ch_regs: memory mapped register base
+ * @mask: channel index in a mask
+ * @per_if: peripheral interface
+ * @mem_if: memory interface
+ * @status: transmit status information from irq/prep* functions
+ *                to tasklet (use atomic operations)
+ * @tasklet: bottom half to finish transaction work
+ * @save_cfg: configuration register that is saved on suspend/resume cycle
+ * @save_dscr: for cyclic operations, preserve next descriptor address in
+ *             the cyclic list on suspend/resume cycle
+ * @dma_sconfig: configuration for slave transfers, passed via
+ * .device_config
+ * @lock: serializes enqueue/dequeue operations to descriptors lists
+ * @active_list: list of descriptors dmaengine is being running on
+ * @queue: list of descriptors ready to be submitted to engine
+ * @free_list: list of descriptors usable by the channel
+ */
+struct at_dma_chan {
+	struct dma_chan		chan_common;
+	struct at_dma		*device;
+	void __iomem		*ch_regs;
+	u8			mask;
+	u8			per_if;
+	u8			mem_if;
+	unsigned long		status;
+	struct tasklet_struct	tasklet;
+	u32			save_cfg;
+	u32			save_dscr;
+	struct dma_slave_config dma_sconfig;
+
+	spinlock_t		lock;
+
+	/* these other elements are all protected by lock */
+	struct list_head	active_list;
+	struct list_head	queue;
+	struct list_head	free_list;
+};
+
+#define	channel_readl(atchan, name) \
+	__raw_readl((atchan)->ch_regs + ATC_##name##_OFFSET)
+
+#define	channel_writel(atchan, name, val) \
+	__raw_writel((val), (atchan)->ch_regs + ATC_##name##_OFFSET)
+
+static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
+{
+	return container_of(dchan, struct at_dma_chan, chan_common);
+}
+
+/*
+ * Fix sconfig's burst size according to at_hdmac. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3, 32 -> 4, 64 -> 5, 128 -> 6, 256 -> 7.
+ *
+ * This can be done by finding most significant bit set.
+ */
+static inline void convert_burst(u32 *maxburst)
+{
+	if (*maxburst > 1)
+		*maxburst = fls(*maxburst) - 2;
+	else
+		*maxburst = 0;
+}
+
+/*
+ * Fix sconfig's bus width according to at_hdmac.
+ * 1 byte -> 0, 2 bytes -> 1, 4 bytes -> 2.
+ */
+static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
+{
+	switch (addr_width) {
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		return 1;
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		return 2;
+	default:
+		/* For 1 byte width or fallback */
+		return 0;
+	}
+}
+
+/*--  Controller  ------------------------------------------------------*/
+
+/**
+ * struct at_dma - internal representation of an Atmel HDMA Controller
+ * @chan_common: common dmaengine dma_device object members
+ * @atdma_devtype: identifier of DMA controller compatibility
+ * @ch_regs: memory mapped register base
+ * @clk: dma controller clock
+ * @save_imr: interrupt mask register that is saved on suspend/resume cycle
+ * @all_chan_mask: all channels availlable in a mask
+ * @dma_desc_pool: base of DMA descriptor region (DMA address)
+ * @chan: channels table to store at_dma_chan structures
+ */
+struct at_dma {
+	struct dma_device	dma_common;
+	void __iomem		*regs;
+	struct clk		*clk;
+	u32			save_imr;
+
+	u8			all_chan_mask;
+
+	struct dma_pool		*dma_desc_pool;
+	struct dma_pool		*memset_pool;
+	/* AT THE END channels table */
+	struct at_dma_chan	chan[];
+};
+
+#define	dma_readl(atdma, name) \
+	__raw_readl((atdma)->regs + AT_DMA_##name)
+#define	dma_writel(atdma, name, val) \
+	__raw_writel((val), (atdma)->regs + AT_DMA_##name)
+
+static inline struct at_dma *to_at_dma(struct dma_device *ddev)
+{
+	return container_of(ddev, struct at_dma, dma_common);
+}
+
+
+/*--  Helper functions  ------------------------------------------------*/
+
+static struct device *chan2dev(struct dma_chan *chan)
+{
+	return &chan->dev->device;
+}
+
+#if defined(VERBOSE_DEBUG)
+static void vdbg_dump_regs(struct at_dma_chan *atchan)
+{
+	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
+
+	dev_err(chan2dev(&atchan->chan_common),
+		"  channel %d : imr = 0x%x, chsr = 0x%x\n",
+		atchan->chan_common.chan_id,
+		dma_readl(atdma, EBCIMR),
+		dma_readl(atdma, CHSR));
+
+	dev_err(chan2dev(&atchan->chan_common),
+		"  channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n",
+		channel_readl(atchan, SADDR),
+		channel_readl(atchan, DADDR),
+		channel_readl(atchan, CTRLA),
+		channel_readl(atchan, CTRLB),
+		channel_readl(atchan, CFG),
+		channel_readl(atchan, DSCR));
+}
+#else
+static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
+#endif
+
+static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
+{
+	dev_crit(chan2dev(&atchan->chan_common),
+		 "desc: s%pad d%pad ctrl0x%x:0x%x l%pad\n",
+		 &lli->saddr, &lli->daddr,
+		 lli->ctrla, lli->ctrlb, &lli->dscr);
+}
+
+
+static void atc_setup_irq(struct at_dma *atdma, int chan_id, int on)
+{
+	u32 ebci;
+
+	/* enable interrupts on buffer transfer completion & error */
+	ebci =    AT_DMA_BTC(chan_id)
+		| AT_DMA_ERR(chan_id);
+	if (on)
+		dma_writel(atdma, EBCIER, ebci);
+	else
+		dma_writel(atdma, EBCIDR, ebci);
+}
+
+static void atc_enable_chan_irq(struct at_dma *atdma, int chan_id)
+{
+	atc_setup_irq(atdma, chan_id, 1);
+}
+
+static void atc_disable_chan_irq(struct at_dma *atdma, int chan_id)
+{
+	atc_setup_irq(atdma, chan_id, 0);
+}
+
+
+/**
+ * atc_chan_is_enabled - test if given channel is enabled
+ * @atchan: channel we want to test status
+ */
+static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
+{
+	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
+
+	return !!(dma_readl(atdma, CHSR) & atchan->mask);
+}
+
+/**
+ * atc_chan_is_paused - test channel pause/resume status
+ * @atchan: channel we want to test status
+ */
+static inline int atc_chan_is_paused(struct at_dma_chan *atchan)
+{
+	return test_bit(ATC_IS_PAUSED, &atchan->status);
+}
+
+/**
+ * atc_chan_is_cyclic - test if given channel has cyclic property set
+ * @atchan: channel we want to test status
+ */
+static inline int atc_chan_is_cyclic(struct at_dma_chan *atchan)
+{
+	return test_bit(ATC_IS_CYCLIC, &atchan->status);
+}
+
+/**
+ * set_desc_eol - set end-of-link to descriptor so it will end transfer
+ * @desc: descriptor, signle or at the end of a chain, to end chain on
+ */
+static void set_desc_eol(struct at_desc *desc)
+{
+	u32 ctrlb = desc->lli.ctrlb;
+
+	ctrlb &= ~ATC_IEN;
+	ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
+
+	desc->lli.ctrlb = ctrlb;
+	desc->lli.dscr = 0;
+}
+
 #define	ATC_DEFAULT_CFG		(ATC_FIFOCFG_HALFFIFO)
 #define	ATC_DEFAULT_CTRLB	(ATC_SIF(AT_DMA_MEM_IF) \
 				|ATC_DIF(AT_DMA_MEM_IF))
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
deleted file mode 100644
index d4d382d74607..000000000000
--- a/drivers/dma/at_hdmac_regs.h
+++ /dev/null
@@ -1,478 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Header file for the Atmel AHB DMA Controller driver
- *
- * Copyright (C) 2008 Atmel Corporation
- */
-#ifndef AT_HDMAC_REGS_H
-#define	AT_HDMAC_REGS_H
-
-#define	AT_DMA_MAX_NR_CHANNELS	8
-
-
-#define	AT_DMA_GCFG	0x00	/* Global Configuration Register */
-#define		AT_DMA_IF_BIGEND(i)	(0x1 << (i))	/* AHB-Lite Interface i in Big-endian mode */
-#define		AT_DMA_ARB_CFG	(0x1 << 4)	/* Arbiter mode. */
-#define			AT_DMA_ARB_CFG_FIXED		(0x0 << 4)
-#define			AT_DMA_ARB_CFG_ROUND_ROBIN	(0x1 << 4)
-
-#define	AT_DMA_EN	0x04	/* Controller Enable Register */
-#define		AT_DMA_ENABLE	(0x1 << 0)
-
-#define	AT_DMA_SREQ	0x08	/* Software Single Request Register */
-#define		AT_DMA_SSREQ(x)	(0x1 << ((x) << 1))		/* Request a source single transfer on channel x */
-#define		AT_DMA_DSREQ(x)	(0x1 << (1 + ((x) << 1)))	/* Request a destination single transfer on channel x */
-
-#define	AT_DMA_CREQ	0x0C	/* Software Chunk Transfer Request Register */
-#define		AT_DMA_SCREQ(x)	(0x1 << ((x) << 1))		/* Request a source chunk transfer on channel x */
-#define		AT_DMA_DCREQ(x)	(0x1 << (1 + ((x) << 1)))	/* Request a destination chunk transfer on channel x */
-
-#define	AT_DMA_LAST	0x10	/* Software Last Transfer Flag Register */
-#define		AT_DMA_SLAST(x)	(0x1 << ((x) << 1))		/* This src rq is last tx of buffer on channel x */
-#define		AT_DMA_DLAST(x)	(0x1 << (1 + ((x) << 1)))	/* This dst rq is last tx of buffer on channel x */
-
-#define	AT_DMA_SYNC	0x14	/* Request Synchronization Register */
-#define		AT_DMA_SYR(h)	(0x1 << (h))			/* Synchronize handshake line h */
-
-/* Error, Chained Buffer transfer completed and Buffer transfer completed Interrupt registers */
-#define	AT_DMA_EBCIER	0x18	/* Enable register */
-#define	AT_DMA_EBCIDR	0x1C	/* Disable register */
-#define	AT_DMA_EBCIMR	0x20	/* Mask Register */
-#define	AT_DMA_EBCISR	0x24	/* Status Register */
-#define		AT_DMA_CBTC_OFFSET	8
-#define		AT_DMA_ERR_OFFSET	16
-#define		AT_DMA_BTC(x)	(0x1 << (x))
-#define		AT_DMA_CBTC(x)	(0x1 << (AT_DMA_CBTC_OFFSET + (x)))
-#define		AT_DMA_ERR(x)	(0x1 << (AT_DMA_ERR_OFFSET + (x)))
-
-#define	AT_DMA_CHER	0x28	/* Channel Handler Enable Register */
-#define		AT_DMA_ENA(x)	(0x1 << (x))
-#define		AT_DMA_SUSP(x)	(0x1 << ( 8 + (x)))
-#define		AT_DMA_KEEP(x)	(0x1 << (24 + (x)))
-
-#define	AT_DMA_CHDR	0x2C	/* Channel Handler Disable Register */
-#define		AT_DMA_DIS(x)	(0x1 << (x))
-#define		AT_DMA_RES(x)	(0x1 << ( 8 + (x)))
-
-#define	AT_DMA_CHSR	0x30	/* Channel Handler Status Register */
-#define		AT_DMA_EMPT(x)	(0x1 << (16 + (x)))
-#define		AT_DMA_STAL(x)	(0x1 << (24 + (x)))
-
-
-#define	AT_DMA_CH_REGS_BASE	0x3C	/* Channel registers base address */
-#define	ch_regs(x)	(AT_DMA_CH_REGS_BASE + (x) * 0x28) /* Channel x base addr */
-
-/* Hardware register offset for each channel */
-#define	ATC_SADDR_OFFSET	0x00	/* Source Address Register */
-#define	ATC_DADDR_OFFSET	0x04	/* Destination Address Register */
-#define	ATC_DSCR_OFFSET		0x08	/* Descriptor Address Register */
-#define	ATC_CTRLA_OFFSET	0x0C	/* Control A Register */
-#define	ATC_CTRLB_OFFSET	0x10	/* Control B Register */
-#define	ATC_CFG_OFFSET		0x14	/* Configuration Register */
-#define	ATC_SPIP_OFFSET		0x18	/* Src PIP Configuration Register */
-#define	ATC_DPIP_OFFSET		0x1C	/* Dst PIP Configuration Register */
-
-
-/* Bitfield definitions */
-
-/* Bitfields in DSCR */
-#define	ATC_DSCR_IF(i)		(0x3 & (i))	/* Dsc feched via AHB-Lite Interface i */
-
-/* Bitfields in CTRLA */
-#define	ATC_BTSIZE_MAX		0xFFFFUL	/* Maximum Buffer Transfer Size */
-#define	ATC_BTSIZE(x)		(ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
-#define	ATC_SCSIZE_MASK		(0x7 << 16)	/* Source Chunk Transfer Size */
-#define		ATC_SCSIZE(x)		(ATC_SCSIZE_MASK & ((x) << 16))
-#define		ATC_SCSIZE_1		(0x0 << 16)
-#define		ATC_SCSIZE_4		(0x1 << 16)
-#define		ATC_SCSIZE_8		(0x2 << 16)
-#define		ATC_SCSIZE_16		(0x3 << 16)
-#define		ATC_SCSIZE_32		(0x4 << 16)
-#define		ATC_SCSIZE_64		(0x5 << 16)
-#define		ATC_SCSIZE_128		(0x6 << 16)
-#define		ATC_SCSIZE_256		(0x7 << 16)
-#define	ATC_DCSIZE_MASK		(0x7 << 20)	/* Destination Chunk Transfer Size */
-#define		ATC_DCSIZE(x)		(ATC_DCSIZE_MASK & ((x) << 20))
-#define		ATC_DCSIZE_1		(0x0 << 20)
-#define		ATC_DCSIZE_4		(0x1 << 20)
-#define		ATC_DCSIZE_8		(0x2 << 20)
-#define		ATC_DCSIZE_16		(0x3 << 20)
-#define		ATC_DCSIZE_32		(0x4 << 20)
-#define		ATC_DCSIZE_64		(0x5 << 20)
-#define		ATC_DCSIZE_128		(0x6 << 20)
-#define		ATC_DCSIZE_256		(0x7 << 20)
-#define	ATC_SRC_WIDTH_MASK	(0x3 << 24)	/* Source Single Transfer Size */
-#define		ATC_SRC_WIDTH(x)	((x) << 24)
-#define		ATC_SRC_WIDTH_BYTE	(0x0 << 24)
-#define		ATC_SRC_WIDTH_HALFWORD	(0x1 << 24)
-#define		ATC_SRC_WIDTH_WORD	(0x2 << 24)
-#define		ATC_REG_TO_SRC_WIDTH(r)	(((r) >> 24) & 0x3)
-#define	ATC_DST_WIDTH_MASK	(0x3 << 28)	/* Destination Single Transfer Size */
-#define		ATC_DST_WIDTH(x)	((x) << 28)
-#define		ATC_DST_WIDTH_BYTE	(0x0 << 28)
-#define		ATC_DST_WIDTH_HALFWORD	(0x1 << 28)
-#define		ATC_DST_WIDTH_WORD	(0x2 << 28)
-#define	ATC_DONE		(0x1 << 31)	/* Tx Done (only written back in descriptor) */
-
-/* Bitfields in CTRLB */
-#define	ATC_SIF(i)		(0x3 & (i))	/* Src tx done via AHB-Lite Interface i */
-#define	ATC_DIF(i)		((0x3 & (i)) <<  4)	/* Dst tx done via AHB-Lite Interface i */
-				  /* Specify AHB interfaces */
-#define AT_DMA_MEM_IF		0 /* interface 0 as memory interface */
-#define AT_DMA_PER_IF		1 /* interface 1 as peripheral interface */
-
-#define	ATC_SRC_PIP		(0x1 <<  8)	/* Source Picture-in-Picture enabled */
-#define	ATC_DST_PIP		(0x1 << 12)	/* Destination Picture-in-Picture enabled */
-#define	ATC_SRC_DSCR_DIS	(0x1 << 16)	/* Src Descriptor fetch disable */
-#define	ATC_DST_DSCR_DIS	(0x1 << 20)	/* Dst Descriptor fetch disable */
-#define	ATC_FC_MASK		(0x7 << 21)	/* Choose Flow Controller */
-#define		ATC_FC_MEM2MEM		(0x0 << 21)	/* Mem-to-Mem (DMA) */
-#define		ATC_FC_MEM2PER		(0x1 << 21)	/* Mem-to-Periph (DMA) */
-#define		ATC_FC_PER2MEM		(0x2 << 21)	/* Periph-to-Mem (DMA) */
-#define		ATC_FC_PER2PER		(0x3 << 21)	/* Periph-to-Periph (DMA) */
-#define		ATC_FC_PER2MEM_PER	(0x4 << 21)	/* Periph-to-Mem (Peripheral) */
-#define		ATC_FC_MEM2PER_PER	(0x5 << 21)	/* Mem-to-Periph (Peripheral) */
-#define		ATC_FC_PER2PER_SRCPER	(0x6 << 21)	/* Periph-to-Periph (Src Peripheral) */
-#define		ATC_FC_PER2PER_DSTPER	(0x7 << 21)	/* Periph-to-Periph (Dst Peripheral) */
-#define	ATC_SRC_ADDR_MODE_MASK	(0x3 << 24)
-#define		ATC_SRC_ADDR_MODE_INCR	(0x0 << 24)	/* Incrementing Mode */
-#define		ATC_SRC_ADDR_MODE_DECR	(0x1 << 24)	/* Decrementing Mode */
-#define		ATC_SRC_ADDR_MODE_FIXED	(0x2 << 24)	/* Fixed Mode */
-#define	ATC_DST_ADDR_MODE_MASK	(0x3 << 28)
-#define		ATC_DST_ADDR_MODE_INCR	(0x0 << 28)	/* Incrementing Mode */
-#define		ATC_DST_ADDR_MODE_DECR	(0x1 << 28)	/* Decrementing Mode */
-#define		ATC_DST_ADDR_MODE_FIXED	(0x2 << 28)	/* Fixed Mode */
-#define	ATC_IEN			(0x1 << 30)	/* BTC interrupt enable (active low) */
-#define	ATC_AUTO		(0x1 << 31)	/* Auto multiple buffer tx enable */
-
-/* Bitfields in CFG */
-#define ATC_PER_MSB(h)	((0x30U & (h)) >> 4)	/* Extract most significant bits of a handshaking identifier */
-
-#define	ATC_SRC_PER(h)		(0xFU & (h))	/* Channel src rq associated with periph handshaking ifc h */
-#define	ATC_DST_PER(h)		((0xFU & (h)) <<  4)	/* Channel dst rq associated with periph handshaking ifc h */
-#define	ATC_SRC_REP		(0x1 <<  8)	/* Source Replay Mod */
-#define	ATC_SRC_H2SEL		(0x1 <<  9)	/* Source Handshaking Mod */
-#define		ATC_SRC_H2SEL_SW	(0x0 <<  9)
-#define		ATC_SRC_H2SEL_HW	(0x1 <<  9)
-#define	ATC_SRC_PER_MSB(h)	(ATC_PER_MSB(h) << 10)	/* Channel src rq (most significant bits) */
-#define	ATC_DST_REP		(0x1 << 12)	/* Destination Replay Mod */
-#define	ATC_DST_H2SEL		(0x1 << 13)	/* Destination Handshaking Mod */
-#define		ATC_DST_H2SEL_SW	(0x0 << 13)
-#define		ATC_DST_H2SEL_HW	(0x1 << 13)
-#define	ATC_DST_PER_MSB(h)	(ATC_PER_MSB(h) << 14)	/* Channel dst rq (most significant bits) */
-#define	ATC_SOD			(0x1 << 16)	/* Stop On Done */
-#define	ATC_LOCK_IF		(0x1 << 20)	/* Interface Lock */
-#define	ATC_LOCK_B		(0x1 << 21)	/* AHB Bus Lock */
-#define	ATC_LOCK_IF_L		(0x1 << 22)	/* Master Interface Arbiter Lock */
-#define		ATC_LOCK_IF_L_CHUNK	(0x0 << 22)
-#define		ATC_LOCK_IF_L_BUFFER	(0x1 << 22)
-#define	ATC_AHB_PROT_MASK	(0x7 << 24)	/* AHB Protection */
-#define	ATC_FIFOCFG_MASK	(0x3 << 28)	/* FIFO Request Configuration */
-#define		ATC_FIFOCFG_LARGESTBURST	(0x0 << 28)
-#define		ATC_FIFOCFG_HALFFIFO		(0x1 << 28)
-#define		ATC_FIFOCFG_ENOUGHSPACE		(0x2 << 28)
-
-/* Bitfields in SPIP */
-#define	ATC_SPIP_HOLE(x)	(0xFFFFU & (x))
-#define	ATC_SPIP_BOUNDARY(x)	((0x3FF & (x)) << 16)
-
-/* Bitfields in DPIP */
-#define	ATC_DPIP_HOLE(x)	(0xFFFFU & (x))
-#define	ATC_DPIP_BOUNDARY(x)	((0x3FF & (x)) << 16)
-
-
-/*--  descriptors  -----------------------------------------------------*/
-
-/* LLI == Linked List Item; aka DMA buffer descriptor */
-struct at_lli {
-	/* values that are not changed by hardware */
-	u32 saddr;
-	u32 daddr;
-	/* value that may get written back: */
-	u32 ctrla;
-	/* more values that are not changed by hardware */
-	u32 ctrlb;
-	u32 dscr;	/* chain to next lli */
-};
-
-/**
- * struct at_desc - software descriptor
- * @at_lli: hardware lli structure
- * @txd: support for the async_tx api
- * @desc_node: node on the channed descriptors list
- * @len: descriptor byte count
- * @total_len: total transaction byte count
- */
-struct at_desc {
-	/* FIRST values the hardware uses */
-	struct at_lli			lli;
-
-	/* THEN values for driver housekeeping */
-	struct list_head		tx_list;
-	struct dma_async_tx_descriptor	txd;
-	struct list_head		desc_node;
-	size_t				len;
-	size_t				total_len;
-
-	/* Interleaved data */
-	size_t				boundary;
-	size_t				dst_hole;
-	size_t				src_hole;
-
-	/* Memset temporary buffer */
-	bool				memset_buffer;
-	dma_addr_t			memset_paddr;
-	int				*memset_vaddr;
-};
-
-static inline struct at_desc *
-txd_to_at_desc(struct dma_async_tx_descriptor *txd)
-{
-	return container_of(txd, struct at_desc, txd);
-}
-
-
-/*--  Channels  --------------------------------------------------------*/
-
-/**
- * atc_status - information bits stored in channel status flag
- *
- * Manipulated with atomic operations.
- */
-enum atc_status {
-	ATC_IS_ERROR = 0,
-	ATC_IS_PAUSED = 1,
-	ATC_IS_CYCLIC = 24,
-};
-
-/**
- * struct at_dma_chan - internal representation of an Atmel HDMAC channel
- * @chan_common: common dmaengine channel object members
- * @device: parent device
- * @ch_regs: memory mapped register base
- * @mask: channel index in a mask
- * @per_if: peripheral interface
- * @mem_if: memory interface
- * @status: transmit status information from irq/prep* functions
- *                to tasklet (use atomic operations)
- * @tasklet: bottom half to finish transaction work
- * @save_cfg: configuration register that is saved on suspend/resume cycle
- * @save_dscr: for cyclic operations, preserve next descriptor address in
- *             the cyclic list on suspend/resume cycle
- * @dma_sconfig: configuration for slave transfers, passed via
- * .device_config
- * @lock: serializes enqueue/dequeue operations to descriptors lists
- * @active_list: list of descriptors dmaengine is being running on
- * @queue: list of descriptors ready to be submitted to engine
- * @free_list: list of descriptors usable by the channel
- */
-struct at_dma_chan {
-	struct dma_chan		chan_common;
-	struct at_dma		*device;
-	void __iomem		*ch_regs;
-	u8			mask;
-	u8			per_if;
-	u8			mem_if;
-	unsigned long		status;
-	struct tasklet_struct	tasklet;
-	u32			save_cfg;
-	u32			save_dscr;
-	struct dma_slave_config dma_sconfig;
-
-	spinlock_t		lock;
-
-	/* these other elements are all protected by lock */
-	struct list_head	active_list;
-	struct list_head	queue;
-	struct list_head	free_list;
-};
-
-#define	channel_readl(atchan, name) \
-	__raw_readl((atchan)->ch_regs + ATC_##name##_OFFSET)
-
-#define	channel_writel(atchan, name, val) \
-	__raw_writel((val), (atchan)->ch_regs + ATC_##name##_OFFSET)
-
-static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
-{
-	return container_of(dchan, struct at_dma_chan, chan_common);
-}
-
-/*
- * Fix sconfig's burst size according to at_hdmac. We need to convert them as:
- * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3, 32 -> 4, 64 -> 5, 128 -> 6, 256 -> 7.
- *
- * This can be done by finding most significant bit set.
- */
-static inline void convert_burst(u32 *maxburst)
-{
-	if (*maxburst > 1)
-		*maxburst = fls(*maxburst) - 2;
-	else
-		*maxburst = 0;
-}
-
-/*
- * Fix sconfig's bus width according to at_hdmac.
- * 1 byte -> 0, 2 bytes -> 1, 4 bytes -> 2.
- */
-static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
-{
-	switch (addr_width) {
-	case DMA_SLAVE_BUSWIDTH_2_BYTES:
-		return 1;
-	case DMA_SLAVE_BUSWIDTH_4_BYTES:
-		return 2;
-	default:
-		/* For 1 byte width or fallback */
-		return 0;
-	}
-}
-
-/*--  Controller  ------------------------------------------------------*/
-
-/**
- * struct at_dma - internal representation of an Atmel HDMA Controller
- * @chan_common: common dmaengine dma_device object members
- * @atdma_devtype: identifier of DMA controller compatibility
- * @ch_regs: memory mapped register base
- * @clk: dma controller clock
- * @save_imr: interrupt mask register that is saved on suspend/resume cycle
- * @all_chan_mask: all channels availlable in a mask
- * @dma_desc_pool: base of DMA descriptor region (DMA address)
- * @chan: channels table to store at_dma_chan structures
- */
-struct at_dma {
-	struct dma_device	dma_common;
-	void __iomem		*regs;
-	struct clk		*clk;
-	u32			save_imr;
-
-	u8			all_chan_mask;
-
-	struct dma_pool		*dma_desc_pool;
-	struct dma_pool		*memset_pool;
-	/* AT THE END channels table */
-	struct at_dma_chan	chan[];
-};
-
-#define	dma_readl(atdma, name) \
-	__raw_readl((atdma)->regs + AT_DMA_##name)
-#define	dma_writel(atdma, name, val) \
-	__raw_writel((val), (atdma)->regs + AT_DMA_##name)
-
-static inline struct at_dma *to_at_dma(struct dma_device *ddev)
-{
-	return container_of(ddev, struct at_dma, dma_common);
-}
-
-
-/*--  Helper functions  ------------------------------------------------*/
-
-static struct device *chan2dev(struct dma_chan *chan)
-{
-	return &chan->dev->device;
-}
-
-#if defined(VERBOSE_DEBUG)
-static void vdbg_dump_regs(struct at_dma_chan *atchan)
-{
-	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
-
-	dev_err(chan2dev(&atchan->chan_common),
-		"  channel %d : imr = 0x%x, chsr = 0x%x\n",
-		atchan->chan_common.chan_id,
-		dma_readl(atdma, EBCIMR),
-		dma_readl(atdma, CHSR));
-
-	dev_err(chan2dev(&atchan->chan_common),
-		"  channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n",
-		channel_readl(atchan, SADDR),
-		channel_readl(atchan, DADDR),
-		channel_readl(atchan, CTRLA),
-		channel_readl(atchan, CTRLB),
-		channel_readl(atchan, CFG),
-		channel_readl(atchan, DSCR));
-}
-#else
-static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
-#endif
-
-static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
-{
-	dev_crit(chan2dev(&atchan->chan_common),
-		 "desc: s%pad d%pad ctrl0x%x:0x%x l%pad\n",
-		 &lli->saddr, &lli->daddr,
-		 lli->ctrla, lli->ctrlb, &lli->dscr);
-}
-
-
-static void atc_setup_irq(struct at_dma *atdma, int chan_id, int on)
-{
-	u32 ebci;
-
-	/* enable interrupts on buffer transfer completion & error */
-	ebci =    AT_DMA_BTC(chan_id)
-		| AT_DMA_ERR(chan_id);
-	if (on)
-		dma_writel(atdma, EBCIER, ebci);
-	else
-		dma_writel(atdma, EBCIDR, ebci);
-}
-
-static void atc_enable_chan_irq(struct at_dma *atdma, int chan_id)
-{
-	atc_setup_irq(atdma, chan_id, 1);
-}
-
-static void atc_disable_chan_irq(struct at_dma *atdma, int chan_id)
-{
-	atc_setup_irq(atdma, chan_id, 0);
-}
-
-
-/**
- * atc_chan_is_enabled - test if given channel is enabled
- * @atchan: channel we want to test status
- */
-static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
-{
-	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
-
-	return !!(dma_readl(atdma, CHSR) & atchan->mask);
-}
-
-/**
- * atc_chan_is_paused - test channel pause/resume status
- * @atchan: channel we want to test status
- */
-static inline int atc_chan_is_paused(struct at_dma_chan *atchan)
-{
-	return test_bit(ATC_IS_PAUSED, &atchan->status);
-}
-
-/**
- * atc_chan_is_cyclic - test if given channel has cyclic property set
- * @atchan: channel we want to test status
- */
-static inline int atc_chan_is_cyclic(struct at_dma_chan *atchan)
-{
-	return test_bit(ATC_IS_CYCLIC, &atchan->status);
-}
-
-/**
- * set_desc_eol - set end-of-link to descriptor so it will end transfer
- * @desc: descriptor, signle or at the end of a chain, to end chain on
- */
-static void set_desc_eol(struct at_desc *desc)
-{
-	u32 ctrlb = desc->lli.ctrlb;
-
-	ctrlb &= ~ATC_IEN;
-	ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
-
-	desc->lli.ctrlb = ctrlb;
-	desc->lli.dscr = 0;
-}
-
-#endif /* AT_HDMAC_REGS_H */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 28/32] dmaengine: at_hdmac: Use bitfield access macros
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (26 preceding siblings ...)
  2022-10-25  9:03 ` [PATCH v2 27/32] dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c Tudor Ambarus
@ 2022-10-25  9:03 ` Tudor Ambarus
  2022-10-25  9:03 ` [PATCH v2 29/32] dmaengine: at_hdmac: Rename "dma_common" to "dma_device" Tudor Ambarus
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:03 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Use the bitfield access macros in order to clean and to make the driver
easier to read. One will see some "line length exceeds 100 columns"
checkpatch warnings. I chose to not introduce new lines for regs
descriptions in order to preserve the style of the comments throughout
the definitions. Style can be fixed in a further patch.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 408 ++++++++++++++++++++---------------------
 1 file changed, 198 insertions(+), 210 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index a07e3355f09a..edec6a8c730c 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -10,6 +10,7 @@
  */
 
 #include <dt-bindings/dma/at91.h>
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/dmaengine.h>
 #include <linux/dmapool.h>
@@ -36,176 +37,153 @@
 
 #define	AT_DMA_MAX_NR_CHANNELS	8
 
+/* Global Configuration Register */
+#define AT_DMA_GCFG		0x00
+#define AT_DMA_IF_BIGEND(i)	BIT((i))	/* AHB-Lite Interface i in Big-endian mode */
+#define AT_DMA_ARB_CFG		BIT(4)		/* Arbiter mode. */
 
-#define	AT_DMA_GCFG	0x00	/* Global Configuration Register */
-#define		AT_DMA_IF_BIGEND(i)	(0x1 << (i))	/* AHB-Lite Interface i in Big-endian mode */
-#define		AT_DMA_ARB_CFG	(0x1 << 4)	/* Arbiter mode. */
-#define			AT_DMA_ARB_CFG_FIXED		(0x0 << 4)
-#define			AT_DMA_ARB_CFG_ROUND_ROBIN	(0x1 << 4)
+/* Controller Enable Register */
+#define AT_DMA_EN		0x04
+#define AT_DMA_ENABLE		BIT(0)
 
-#define	AT_DMA_EN	0x04	/* Controller Enable Register */
-#define		AT_DMA_ENABLE	(0x1 << 0)
+/* Software Single Request Register */
+#define AT_DMA_SREQ		0x08
+#define AT_DMA_SSREQ(x)		BIT((x) << 1)		/* Request a source single transfer on channel x */
+#define AT_DMA_DSREQ(x)		BIT(1 + ((x) << 1))	/* Request a destination single transfer on channel x */
 
-#define	AT_DMA_SREQ	0x08	/* Software Single Request Register */
-#define		AT_DMA_SSREQ(x)	(0x1 << ((x) << 1))		/* Request a source single transfer on channel x */
-#define		AT_DMA_DSREQ(x)	(0x1 << (1 + ((x) << 1)))	/* Request a destination single transfer on channel x */
+/* Software Chunk Transfer Request Register */
+#define AT_DMA_CREQ		0x0c
+#define AT_DMA_SCREQ(x)		BIT((x) << 1)		/* Request a source chunk transfer on channel x */
+#define AT_DMA_DCREQ(x)		BIT(1 + ((x) << 1))	/* Request a destination chunk transfer on channel x */
 
-#define	AT_DMA_CREQ	0x0C	/* Software Chunk Transfer Request Register */
-#define		AT_DMA_SCREQ(x)	(0x1 << ((x) << 1))		/* Request a source chunk transfer on channel x */
-#define		AT_DMA_DCREQ(x)	(0x1 << (1 + ((x) << 1)))	/* Request a destination chunk transfer on channel x */
+/* Software Last Transfer Flag Register */
+#define AT_DMA_LAST		0x10
+#define AT_DMA_SLAST(x)		BIT((x) << 1)		/* This src rq is last tx of buffer on channel x */
+#define AT_DMA_DLAST(x)		BIT(1 + ((x) << 1))	/* This dst rq is last tx of buffer on channel x */
 
-#define	AT_DMA_LAST	0x10	/* Software Last Transfer Flag Register */
-#define		AT_DMA_SLAST(x)	(0x1 << ((x) << 1))		/* This src rq is last tx of buffer on channel x */
-#define		AT_DMA_DLAST(x)	(0x1 << (1 + ((x) << 1)))	/* This dst rq is last tx of buffer on channel x */
-
-#define	AT_DMA_SYNC	0x14	/* Request Synchronization Register */
-#define		AT_DMA_SYR(h)	(0x1 << (h))			/* Synchronize handshake line h */
+/* Request Synchronization Register */
+#define AT_DMA_SYNC		0x14
+#define AT_DMA_SYR(h)		BIT((h))		/* Synchronize handshake line h */
 
 /* Error, Chained Buffer transfer completed and Buffer transfer completed Interrupt registers */
-#define	AT_DMA_EBCIER	0x18	/* Enable register */
-#define	AT_DMA_EBCIDR	0x1C	/* Disable register */
-#define	AT_DMA_EBCIMR	0x20	/* Mask Register */
-#define	AT_DMA_EBCISR	0x24	/* Status Register */
-#define		AT_DMA_CBTC_OFFSET	8
-#define		AT_DMA_ERR_OFFSET	16
-#define		AT_DMA_BTC(x)	(0x1 << (x))
-#define		AT_DMA_CBTC(x)	(0x1 << (AT_DMA_CBTC_OFFSET + (x)))
-#define		AT_DMA_ERR(x)	(0x1 << (AT_DMA_ERR_OFFSET + (x)))
-
-#define	AT_DMA_CHER	0x28	/* Channel Handler Enable Register */
-#define		AT_DMA_ENA(x)	(0x1 << (x))
-#define		AT_DMA_SUSP(x)	(0x1 << ( 8 + (x)))
-#define		AT_DMA_KEEP(x)	(0x1 << (24 + (x)))
-
-#define	AT_DMA_CHDR	0x2C	/* Channel Handler Disable Register */
-#define		AT_DMA_DIS(x)	(0x1 << (x))
-#define		AT_DMA_RES(x)	(0x1 << ( 8 + (x)))
-
-#define	AT_DMA_CHSR	0x30	/* Channel Handler Status Register */
-#define		AT_DMA_EMPT(x)	(0x1 << (16 + (x)))
-#define		AT_DMA_STAL(x)	(0x1 << (24 + (x)))
-
-
-#define	AT_DMA_CH_REGS_BASE	0x3C	/* Channel registers base address */
-#define	ch_regs(x)	(AT_DMA_CH_REGS_BASE + (x) * 0x28) /* Channel x base addr */
+#define AT_DMA_EBCIER		0x18			/* Enable register */
+#define AT_DMA_EBCIDR		0x1c			/* Disable register */
+#define AT_DMA_EBCIMR		0x20			/* Mask Register */
+#define AT_DMA_EBCISR		0x24			/* Status Register */
+#define AT_DMA_CBTC_OFFSET	8
+#define AT_DMA_ERR_OFFSET	16
+#define AT_DMA_BTC(x)		BIT((x))
+#define AT_DMA_CBTC(x)		BIT(AT_DMA_CBTC_OFFSET + (x))
+#define AT_DMA_ERR(x)		BIT(AT_DMA_ERR_OFFSET + (x))
+
+/* Channel Handler Enable Register */
+#define AT_DMA_CHER		0x28
+#define AT_DMA_ENA(x)		BIT((x))
+#define AT_DMA_SUSP(x)		BIT(8 + (x))
+#define AT_DMA_KEEP(x)		BIT(24 + (x))
+
+/* Channel Handler Disable Register */
+#define AT_DMA_CHDR		0x2c
+#define AT_DMA_DIS(x)		BIT(x)
+#define AT_DMA_RES(x)		BIT(8 + (x))
+
+/* Channel Handler Status Register */
+#define AT_DMA_CHSR		0x30
+#define AT_DMA_EMPT(x)		BIT(16 + (x))
+#define AT_DMA_STAL(x)		BIT(24 + (x))
+
+/* Channel registers base address */
+#define AT_DMA_CH_REGS_BASE	0x3c
+#define ch_regs(x)		(AT_DMA_CH_REGS_BASE + (x) * 0x28) /* Channel x base addr */
 
 /* Hardware register offset for each channel */
-#define	ATC_SADDR_OFFSET	0x00	/* Source Address Register */
-#define	ATC_DADDR_OFFSET	0x04	/* Destination Address Register */
-#define	ATC_DSCR_OFFSET		0x08	/* Descriptor Address Register */
-#define	ATC_CTRLA_OFFSET	0x0C	/* Control A Register */
-#define	ATC_CTRLB_OFFSET	0x10	/* Control B Register */
-#define	ATC_CFG_OFFSET		0x14	/* Configuration Register */
-#define	ATC_SPIP_OFFSET		0x18	/* Src PIP Configuration Register */
-#define	ATC_DPIP_OFFSET		0x1C	/* Dst PIP Configuration Register */
+#define ATC_SADDR_OFFSET	0x00	/* Source Address Register */
+#define ATC_DADDR_OFFSET	0x04	/* Destination Address Register */
+#define ATC_DSCR_OFFSET		0x08	/* Descriptor Address Register */
+#define ATC_CTRLA_OFFSET	0x0c	/* Control A Register */
+#define ATC_CTRLB_OFFSET	0x10	/* Control B Register */
+#define ATC_CFG_OFFSET		0x14	/* Configuration Register */
+#define ATC_SPIP_OFFSET		0x18	/* Src PIP Configuration Register */
+#define ATC_DPIP_OFFSET		0x1c	/* Dst PIP Configuration Register */
 
 
 /* Bitfield definitions */
 
 /* Bitfields in DSCR */
-#define	ATC_DSCR_IF(i)		(0x3 & (i))	/* Dsc feched via AHB-Lite Interface i */
+#define ATC_DSCR_IF		GENMASK(1, 0)	/* Dsc feched via AHB-Lite Interface */
 
 /* Bitfields in CTRLA */
-#define	ATC_BTSIZE_MAX		0xFFFFUL	/* Maximum Buffer Transfer Size */
-#define	ATC_BTSIZE(x)		(ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
-#define	ATC_SCSIZE_MASK		(0x7 << 16)	/* Source Chunk Transfer Size */
-#define		ATC_SCSIZE(x)		(ATC_SCSIZE_MASK & ((x) << 16))
-#define		ATC_SCSIZE_1		(0x0 << 16)
-#define		ATC_SCSIZE_4		(0x1 << 16)
-#define		ATC_SCSIZE_8		(0x2 << 16)
-#define		ATC_SCSIZE_16		(0x3 << 16)
-#define		ATC_SCSIZE_32		(0x4 << 16)
-#define		ATC_SCSIZE_64		(0x5 << 16)
-#define		ATC_SCSIZE_128		(0x6 << 16)
-#define		ATC_SCSIZE_256		(0x7 << 16)
-#define	ATC_DCSIZE_MASK		(0x7 << 20)	/* Destination Chunk Transfer Size */
-#define		ATC_DCSIZE(x)		(ATC_DCSIZE_MASK & ((x) << 20))
-#define		ATC_DCSIZE_1		(0x0 << 20)
-#define		ATC_DCSIZE_4		(0x1 << 20)
-#define		ATC_DCSIZE_8		(0x2 << 20)
-#define		ATC_DCSIZE_16		(0x3 << 20)
-#define		ATC_DCSIZE_32		(0x4 << 20)
-#define		ATC_DCSIZE_64		(0x5 << 20)
-#define		ATC_DCSIZE_128		(0x6 << 20)
-#define		ATC_DCSIZE_256		(0x7 << 20)
-#define	ATC_SRC_WIDTH_MASK	(0x3 << 24)	/* Source Single Transfer Size */
-#define		ATC_SRC_WIDTH(x)	((x) << 24)
-#define		ATC_SRC_WIDTH_BYTE	(0x0 << 24)
-#define		ATC_SRC_WIDTH_HALFWORD	(0x1 << 24)
-#define		ATC_SRC_WIDTH_WORD	(0x2 << 24)
-#define		ATC_REG_TO_SRC_WIDTH(r)	(((r) >> 24) & 0x3)
-#define	ATC_DST_WIDTH_MASK	(0x3 << 28)	/* Destination Single Transfer Size */
-#define		ATC_DST_WIDTH(x)	((x) << 28)
-#define		ATC_DST_WIDTH_BYTE	(0x0 << 28)
-#define		ATC_DST_WIDTH_HALFWORD	(0x1 << 28)
-#define		ATC_DST_WIDTH_WORD	(0x2 << 28)
-#define	ATC_DONE		(0x1 << 31)	/* Tx Done (only written back in descriptor) */
+#define ATC_BTSIZE_MAX		GENMASK(15, 0)	/* Maximum Buffer Transfer Size */
+#define ATC_BTSIZE		GENMASK(15, 0)	/* Buffer Transfer Size */
+#define ATC_SCSIZE		GENMASK(18, 16)	/* Source Chunk Transfer Size */
+#define ATC_DCSIZE		GENMASK(22, 20)	/* Destination Chunk Transfer Size */
+#define ATC_SRC_WIDTH		GENMASK(25, 24)	/* Source Single Transfer Size */
+#define ATC_DST_WIDTH		GENMASK(29, 28)	/* Destination Single Transfer Size */
+#define ATC_DONE		BIT(31)	/* Tx Done (only written back in descriptor) */
 
 /* Bitfields in CTRLB */
-#define	ATC_SIF(i)		(0x3 & (i))	/* Src tx done via AHB-Lite Interface i */
-#define	ATC_DIF(i)		((0x3 & (i)) <<  4)	/* Dst tx done via AHB-Lite Interface i */
-				  /* Specify AHB interfaces */
-#define AT_DMA_MEM_IF		0 /* interface 0 as memory interface */
-#define AT_DMA_PER_IF		1 /* interface 1 as peripheral interface */
-
-#define	ATC_SRC_PIP		(0x1 <<  8)	/* Source Picture-in-Picture enabled */
-#define	ATC_DST_PIP		(0x1 << 12)	/* Destination Picture-in-Picture enabled */
-#define	ATC_SRC_DSCR_DIS	(0x1 << 16)	/* Src Descriptor fetch disable */
-#define	ATC_DST_DSCR_DIS	(0x1 << 20)	/* Dst Descriptor fetch disable */
-#define	ATC_FC_MASK		(0x7 << 21)	/* Choose Flow Controller */
-#define		ATC_FC_MEM2MEM		(0x0 << 21)	/* Mem-to-Mem (DMA) */
-#define		ATC_FC_MEM2PER		(0x1 << 21)	/* Mem-to-Periph (DMA) */
-#define		ATC_FC_PER2MEM		(0x2 << 21)	/* Periph-to-Mem (DMA) */
-#define		ATC_FC_PER2PER		(0x3 << 21)	/* Periph-to-Periph (DMA) */
-#define		ATC_FC_PER2MEM_PER	(0x4 << 21)	/* Periph-to-Mem (Peripheral) */
-#define		ATC_FC_MEM2PER_PER	(0x5 << 21)	/* Mem-to-Periph (Peripheral) */
-#define		ATC_FC_PER2PER_SRCPER	(0x6 << 21)	/* Periph-to-Periph (Src Peripheral) */
-#define		ATC_FC_PER2PER_DSTPER	(0x7 << 21)	/* Periph-to-Periph (Dst Peripheral) */
-#define	ATC_SRC_ADDR_MODE_MASK	(0x3 << 24)
-#define		ATC_SRC_ADDR_MODE_INCR	(0x0 << 24)	/* Incrementing Mode */
-#define		ATC_SRC_ADDR_MODE_DECR	(0x1 << 24)	/* Decrementing Mode */
-#define		ATC_SRC_ADDR_MODE_FIXED	(0x2 << 24)	/* Fixed Mode */
-#define	ATC_DST_ADDR_MODE_MASK	(0x3 << 28)
-#define		ATC_DST_ADDR_MODE_INCR	(0x0 << 28)	/* Incrementing Mode */
-#define		ATC_DST_ADDR_MODE_DECR	(0x1 << 28)	/* Decrementing Mode */
-#define		ATC_DST_ADDR_MODE_FIXED	(0x2 << 28)	/* Fixed Mode */
-#define	ATC_IEN			(0x1 << 30)	/* BTC interrupt enable (active low) */
-#define	ATC_AUTO		(0x1 << 31)	/* Auto multiple buffer tx enable */
+#define ATC_SIF			GENMASK(1, 0)	/* Src tx done via AHB-Lite Interface i */
+#define ATC_DIF			GENMASK(5, 4)	/* Dst tx done via AHB-Lite Interface i */
+#define AT_DMA_MEM_IF		0x0		/* interface 0 as memory interface */
+#define AT_DMA_PER_IF		0x1		/* interface 1 as peripheral interface */
+#define ATC_SRC_PIP		BIT(8)		/* Source Picture-in-Picture enabled */
+#define ATC_DST_PIP		BIT(12)		/* Destination Picture-in-Picture enabled */
+#define ATC_SRC_DSCR_DIS	BIT(16)		/* Src Descriptor fetch disable */
+#define ATC_DST_DSCR_DIS	BIT(20)		/* Dst Descriptor fetch disable */
+#define ATC_FC			GENMASK(22, 21)	/* Choose Flow Controller */
+#define ATC_FC_MEM2MEM		0x0		/* Mem-to-Mem (DMA) */
+#define ATC_FC_MEM2PER		0x1		/* Mem-to-Periph (DMA) */
+#define ATC_FC_PER2MEM		0x2		/* Periph-to-Mem (DMA) */
+#define ATC_FC_PER2PER		0x3		/* Periph-to-Periph (DMA) */
+#define ATC_FC_PER2MEM_PER	0x4		/* Periph-to-Mem (Peripheral) */
+#define ATC_FC_MEM2PER_PER	0x5		/* Mem-to-Periph (Peripheral) */
+#define ATC_FC_PER2PER_SRCPER	0x6		/* Periph-to-Periph (Src Peripheral) */
+#define ATC_FC_PER2PER_DSTPER	0x7		/* Periph-to-Periph (Dst Peripheral) */
+#define ATC_SRC_ADDR_MODE	GENMASK(25, 24)
+#define ATC_SRC_ADDR_MODE_INCR	0x0		/* Incrementing Mode */
+#define ATC_SRC_ADDR_MODE_DECR	0x1		/* Decrementing Mode */
+#define ATC_SRC_ADDR_MODE_FIXED	0x2		/* Fixed Mode */
+#define ATC_DST_ADDR_MODE	GENMASK(29, 28)
+#define ATC_DST_ADDR_MODE_INCR	0x0		/* Incrementing Mode */
+#define ATC_DST_ADDR_MODE_DECR	0x1		/* Decrementing Mode */
+#define ATC_DST_ADDR_MODE_FIXED	0x2		/* Fixed Mode */
+#define ATC_IEN			BIT(30)		/* BTC interrupt enable (active low) */
+#define ATC_AUTO		BIT(31)		/* Auto multiple buffer tx enable */
 
 /* Bitfields in CFG */
 #define ATC_PER_MSB(h)	((0x30U & (h)) >> 4)	/* Extract most significant bits of a handshaking identifier */
 
-#define	ATC_SRC_PER(h)		(0xFU & (h))	/* Channel src rq associated with periph handshaking ifc h */
-#define	ATC_DST_PER(h)		((0xFU & (h)) <<  4)	/* Channel dst rq associated with periph handshaking ifc h */
-#define	ATC_SRC_REP		(0x1 <<  8)	/* Source Replay Mod */
-#define	ATC_SRC_H2SEL		(0x1 <<  9)	/* Source Handshaking Mod */
-#define		ATC_SRC_H2SEL_SW	(0x0 <<  9)
-#define		ATC_SRC_H2SEL_HW	(0x1 <<  9)
-#define	ATC_SRC_PER_MSB(h)	(ATC_PER_MSB(h) << 10)	/* Channel src rq (most significant bits) */
-#define	ATC_DST_REP		(0x1 << 12)	/* Destination Replay Mod */
-#define	ATC_DST_H2SEL		(0x1 << 13)	/* Destination Handshaking Mod */
-#define		ATC_DST_H2SEL_SW	(0x0 << 13)
-#define		ATC_DST_H2SEL_HW	(0x1 << 13)
-#define	ATC_DST_PER_MSB(h)	(ATC_PER_MSB(h) << 14)	/* Channel dst rq (most significant bits) */
-#define	ATC_SOD			(0x1 << 16)	/* Stop On Done */
-#define	ATC_LOCK_IF		(0x1 << 20)	/* Interface Lock */
-#define	ATC_LOCK_B		(0x1 << 21)	/* AHB Bus Lock */
-#define	ATC_LOCK_IF_L		(0x1 << 22)	/* Master Interface Arbiter Lock */
-#define		ATC_LOCK_IF_L_CHUNK	(0x0 << 22)
-#define		ATC_LOCK_IF_L_BUFFER	(0x1 << 22)
-#define	ATC_AHB_PROT_MASK	(0x7 << 24)	/* AHB Protection */
-#define	ATC_FIFOCFG_MASK	(0x3 << 28)	/* FIFO Request Configuration */
-#define		ATC_FIFOCFG_LARGESTBURST	(0x0 << 28)
-#define		ATC_FIFOCFG_HALFFIFO		(0x1 << 28)
-#define		ATC_FIFOCFG_ENOUGHSPACE		(0x2 << 28)
+#define ATC_SRC_PER		GENMASK(3, 0)	/* Channel src rq associated with periph handshaking ifc h */
+#define ATC_DST_PER		GENMASK(7, 4)	/* Channel dst rq associated with periph handshaking ifc h */
+#define ATC_SRC_REP		BIT(8)		/* Source Replay Mod */
+#define ATC_SRC_H2SEL		BIT(9)		/* Source Handshaking Mod */
+#define ATC_SRC_PER_MSB		GENMASK(11, 10)	/* Channel src rq (most significant bits) */
+#define ATC_DST_REP		BIT(12)		/* Destination Replay Mod */
+#define ATC_DST_H2SEL		BIT(13)		/* Destination Handshaking Mod */
+#define ATC_DST_PER_MSB		GENMASK(15, 14)	/* Channel dst rq (most significant bits) */
+#define ATC_SOD			BIT(16)		/* Stop On Done */
+#define ATC_LOCK_IF		BIT(20)		/* Interface Lock */
+#define ATC_LOCK_B		BIT(21)		/* AHB Bus Lock */
+#define ATC_LOCK_IF_L		BIT(22)		/* Master Interface Arbiter Lock */
+#define ATC_AHB_PROT		GENMASK(26, 24)	/* AHB Protection */
+#define ATC_FIFOCFG		GENMASK(29, 28)	/* FIFO Request Configuration */
+#define ATC_FIFOCFG_LARGESTBURST	0x0
+#define ATC_FIFOCFG_HALFFIFO		0x1
+#define ATC_FIFOCFG_ENOUGHSPACE		0x2
 
 /* Bitfields in SPIP */
-#define	ATC_SPIP_HOLE(x)	(0xFFFFU & (x))
-#define	ATC_SPIP_BOUNDARY(x)	((0x3FF & (x)) << 16)
+#define ATC_SPIP_HOLE		GENMASK(15, 0)
+#define ATC_SPIP_BOUNDARY	GENMASK(25, 16)
 
 /* Bitfields in DPIP */
-#define	ATC_DPIP_HOLE(x)	(0xFFFFU & (x))
-#define	ATC_DPIP_BOUNDARY(x)	((0x3FF & (x)) << 16)
+#define ATC_DPIP_HOLE		GENMASK(15, 0)
+#define ATC_DPIP_BOUNDARY	GENMASK(25, 16)
+
+#define ATC_SRC_PER_ID(id)	(FIELD_PREP(ATC_SRC_PER_MSB, (id)) |	\
+				 FIELD_PREP(ATC_SRC_PER, (id)))
+#define ATC_DST_PER_ID(id)	(FIELD_PREP(ATC_DST_PER_MSB, (id)) |	\
+				 FIELD_PREP(ATC_DST_PER, (id)))
+
 
 
 /*--  descriptors  -----------------------------------------------------*/
@@ -502,9 +480,9 @@ static void set_desc_eol(struct at_desc *desc)
 	desc->lli.dscr = 0;
 }
 
-#define	ATC_DEFAULT_CFG		(ATC_FIFOCFG_HALFFIFO)
-#define	ATC_DEFAULT_CTRLB	(ATC_SIF(AT_DMA_MEM_IF) \
-				|ATC_DIF(AT_DMA_MEM_IF))
+#define	ATC_DEFAULT_CFG		FIELD_PREP(ATC_FIFOCFG, ATC_FIFOCFG_HALFFIFO)
+#define	ATC_DEFAULT_CTRLB	(FIELD_PREP(ATC_SIF, AT_DMA_MEM_IF) | \
+				 FIELD_PREP(ATC_DIF, AT_DMA_MEM_IF))
 #define ATC_DMA_BUSWIDTHS\
 	(BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
 	BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
@@ -720,10 +698,12 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 	channel_writel(atchan, CTRLA, 0);
 	channel_writel(atchan, CTRLB, 0);
 	channel_writel(atchan, DSCR, first->txd.phys);
-	channel_writel(atchan, SPIP, ATC_SPIP_HOLE(first->src_hole) |
-		       ATC_SPIP_BOUNDARY(first->boundary));
-	channel_writel(atchan, DPIP, ATC_DPIP_HOLE(first->dst_hole) |
-		       ATC_DPIP_BOUNDARY(first->boundary));
+	channel_writel(atchan, SPIP, FIELD_PREP(ATC_SPIP_HOLE,
+						first->src_hole) |
+		       FIELD_PREP(ATC_SPIP_BOUNDARY, first->boundary));
+	channel_writel(atchan, DPIP, FIELD_PREP(ATC_DPIP_HOLE,
+						first->dst_hole) |
+		       FIELD_PREP(ATC_DPIP_BOUNDARY, first->boundary));
 	/* Don't allow CPU to reorder channel enable. */
 	wmb();
 	dma_writel(atdma, CHER, atchan->mask);
@@ -763,8 +743,8 @@ static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
  */
 static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla)
 {
-	u32 btsize = (ctrla & ATC_BTSIZE_MAX);
-	u32 src_width = ATC_REG_TO_SRC_WIDTH(ctrla);
+	u32 btsize = FIELD_GET(ATC_BTSIZE, ctrla);
+	u32 src_width = FIELD_GET(ATC_SRC_WIDTH, ctrla);
 
 	/*
 	 * According to the datasheet, when reading the Control A Register
@@ -1203,15 +1183,14 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
 		return NULL;
 	}
 
-	ctrla = ATC_SRC_WIDTH(dwidth) |
-		ATC_DST_WIDTH(dwidth);
+	ctrla = FIELD_PREP(ATC_SRC_WIDTH, dwidth) |
+		FIELD_PREP(ATC_DST_WIDTH, dwidth);
 
-	ctrlb =   ATC_DEFAULT_CTRLB | ATC_IEN
-		| ATC_SRC_ADDR_MODE_INCR
-		| ATC_DST_ADDR_MODE_INCR
-		| ATC_SRC_PIP
-		| ATC_DST_PIP
-		| ATC_FC_MEM2MEM;
+	ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN |
+		FIELD_PREP(ATC_SRC_ADDR_MODE, ATC_SRC_ADDR_MODE_INCR) |
+		FIELD_PREP(ATC_DST_ADDR_MODE, ATC_DST_ADDR_MODE_INCR) |
+		ATC_SRC_PIP | ATC_DST_PIP |
+		FIELD_PREP(ATC_FC, ATC_FC_MEM2MEM);
 
 	/* create the transfer */
 	desc = atc_desc_get(atchan);
@@ -1272,10 +1251,10 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		return NULL;
 	}
 
-	ctrlb =   ATC_DEFAULT_CTRLB | ATC_IEN
-		| ATC_SRC_ADDR_MODE_INCR
-		| ATC_DST_ADDR_MODE_INCR
-		| ATC_FC_MEM2MEM;
+	ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN |
+		FIELD_PREP(ATC_SRC_ADDR_MODE, ATC_SRC_ADDR_MODE_INCR) |
+		FIELD_PREP(ATC_DST_ADDR_MODE, ATC_DST_ADDR_MODE_INCR) |
+		FIELD_PREP(ATC_FC, ATC_FC_MEM2MEM);
 
 	/*
 	 * We can be a lot more clever here, but this should take care
@@ -1283,8 +1262,8 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	 */
 	src_width = dst_width = atc_get_xfer_width(src, dest, len);
 
-	ctrla = ATC_SRC_WIDTH(src_width) |
-		ATC_DST_WIDTH(dst_width);
+	ctrla = FIELD_PREP(ATC_SRC_WIDTH, src_width) |
+		FIELD_PREP(ATC_DST_WIDTH, dst_width);
 
 	for (offset = 0; offset < len; offset += xfer_count << src_width) {
 		xfer_count = min_t(size_t, (len - offset) >> src_width,
@@ -1330,11 +1309,11 @@ static struct at_desc *atc_create_memset_desc(struct dma_chan *chan,
 	struct at_desc *desc;
 	size_t xfer_count;
 
-	u32 ctrla = ATC_SRC_WIDTH(2) | ATC_DST_WIDTH(2);
+	u32 ctrla = FIELD_PREP(ATC_SRC_WIDTH, 2) | FIELD_PREP(ATC_DST_WIDTH, 2);
 	u32 ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN |
-		ATC_SRC_ADDR_MODE_FIXED |
-		ATC_DST_ADDR_MODE_INCR |
-		ATC_FC_MEM2MEM;
+		    FIELD_PREP(ATC_SRC_ADDR_MODE, ATC_SRC_ADDR_MODE_FIXED) |
+		    FIELD_PREP(ATC_DST_ADDR_MODE, ATC_DST_ADDR_MODE_INCR) |
+		    FIELD_PREP(ATC_FC, ATC_FC_MEM2MEM);
 
 	xfer_count = len >> 2;
 	if (xfer_count > ATC_BTSIZE_MAX) {
@@ -1549,18 +1528,20 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		return NULL;
 	}
 
-	ctrla =   ATC_SCSIZE(sconfig->src_maxburst)
-		| ATC_DCSIZE(sconfig->dst_maxburst);
+	ctrla = FIELD_PREP(ATC_SCSIZE, sconfig->src_maxburst) |
+		FIELD_PREP(ATC_DCSIZE, sconfig->dst_maxburst);
 	ctrlb = ATC_IEN;
 
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
 		reg_width = convert_buswidth(sconfig->dst_addr_width);
-		ctrla |=  ATC_DST_WIDTH(reg_width);
-		ctrlb |=  ATC_DST_ADDR_MODE_FIXED
-			| ATC_SRC_ADDR_MODE_INCR
-			| ATC_FC_MEM2PER
-			| ATC_SIF(atchan->mem_if) | ATC_DIF(atchan->per_if);
+		ctrla |= FIELD_PREP(ATC_DST_WIDTH, reg_width);
+		ctrlb |= FIELD_PREP(ATC_DST_ADDR_MODE,
+				    ATC_DST_ADDR_MODE_FIXED) |
+			 FIELD_PREP(ATC_SRC_ADDR_MODE, ATC_SRC_ADDR_MODE_INCR) |
+			 FIELD_PREP(ATC_FC, ATC_FC_MEM2PER) |
+			 FIELD_PREP(ATC_SIF, atchan->mem_if) |
+			 FIELD_PREP(ATC_DIF, atchan->per_if);
 		reg = sconfig->dst_addr;
 		for_each_sg(sgl, sg, sg_len, i) {
 			struct at_desc	*desc;
@@ -1584,9 +1565,9 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
 			desc->lli.saddr = mem;
 			desc->lli.daddr = reg;
-			desc->lli.ctrla = ctrla
-					| ATC_SRC_WIDTH(mem_width)
-					| len >> mem_width;
+			desc->lli.ctrla = ctrla |
+					  FIELD_PREP(ATC_SRC_WIDTH, mem_width) |
+					  len >> mem_width;
 			desc->lli.ctrlb = ctrlb;
 			desc->len = len;
 
@@ -1596,11 +1577,13 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		break;
 	case DMA_DEV_TO_MEM:
 		reg_width = convert_buswidth(sconfig->src_addr_width);
-		ctrla |=  ATC_SRC_WIDTH(reg_width);
-		ctrlb |=  ATC_DST_ADDR_MODE_INCR
-			| ATC_SRC_ADDR_MODE_FIXED
-			| ATC_FC_PER2MEM
-			| ATC_SIF(atchan->per_if) | ATC_DIF(atchan->mem_if);
+		ctrla |= FIELD_PREP(ATC_SRC_WIDTH, reg_width);
+		ctrlb |= FIELD_PREP(ATC_DST_ADDR_MODE, ATC_DST_ADDR_MODE_INCR) |
+			 FIELD_PREP(ATC_SRC_ADDR_MODE,
+				    ATC_SRC_ADDR_MODE_FIXED) |
+			 FIELD_PREP(ATC_FC, ATC_FC_PER2MEM) |
+			 FIELD_PREP(ATC_SIF, atchan->per_if) |
+			 FIELD_PREP(ATC_DIF, atchan->mem_if);
 
 		reg = sconfig->src_addr;
 		for_each_sg(sgl, sg, sg_len, i) {
@@ -1625,9 +1608,9 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
 			desc->lli.saddr = reg;
 			desc->lli.daddr = mem;
-			desc->lli.ctrla = ctrla
-					| ATC_DST_WIDTH(mem_width)
-					| len >> reg_width;
+			desc->lli.ctrla = ctrla |
+					  FIELD_PREP(ATC_DST_WIDTH, mem_width) |
+					  len >> reg_width;
 			desc->lli.ctrlb = ctrlb;
 			desc->len = len;
 
@@ -1693,22 +1676,24 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
 	u32			ctrla;
 
 	/* prepare common CRTLA value */
-	ctrla =   ATC_SCSIZE(sconfig->src_maxburst)
-		| ATC_DCSIZE(sconfig->dst_maxburst)
-		| ATC_DST_WIDTH(reg_width)
-		| ATC_SRC_WIDTH(reg_width)
-		| period_len >> reg_width;
+	ctrla = FIELD_PREP(ATC_SCSIZE, sconfig->src_maxburst) |
+		FIELD_PREP(ATC_DCSIZE, sconfig->dst_maxburst) |
+		FIELD_PREP(ATC_DST_WIDTH, reg_width) |
+		FIELD_PREP(ATC_SRC_WIDTH, reg_width) |
+		period_len >> reg_width;
 
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
 		desc->lli.saddr = buf_addr + (period_len * period_index);
 		desc->lli.daddr = sconfig->dst_addr;
 		desc->lli.ctrla = ctrla;
-		desc->lli.ctrlb = ATC_DST_ADDR_MODE_FIXED
-				| ATC_SRC_ADDR_MODE_INCR
-				| ATC_FC_MEM2PER
-				| ATC_SIF(atchan->mem_if)
-				| ATC_DIF(atchan->per_if);
+		desc->lli.ctrlb = FIELD_PREP(ATC_DST_ADDR_MODE,
+					     ATC_DST_ADDR_MODE_FIXED) |
+				  FIELD_PREP(ATC_SRC_ADDR_MODE,
+					     ATC_SRC_ADDR_MODE_INCR) |
+				  FIELD_PREP(ATC_FC, ATC_FC_MEM2PER) |
+				  FIELD_PREP(ATC_SIF, atchan->mem_if) |
+				  FIELD_PREP(ATC_DIF, atchan->per_if);
 		desc->len = period_len;
 		break;
 
@@ -1716,11 +1701,13 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
 		desc->lli.saddr = sconfig->src_addr;
 		desc->lli.daddr = buf_addr + (period_len * period_index);
 		desc->lli.ctrla = ctrla;
-		desc->lli.ctrlb = ATC_DST_ADDR_MODE_INCR
-				| ATC_SRC_ADDR_MODE_FIXED
-				| ATC_FC_PER2MEM
-				| ATC_SIF(atchan->per_if)
-				| ATC_DIF(atchan->mem_if);
+		desc->lli.ctrlb = FIELD_PREP(ATC_DST_ADDR_MODE,
+					     ATC_DST_ADDR_MODE_INCR) |
+				  FIELD_PREP(ATC_SRC_ADDR_MODE,
+					     ATC_SRC_ADDR_MODE_FIXED) |
+				  FIELD_PREP(ATC_FC, ATC_FC_PER2MEM) |
+				  FIELD_PREP(ATC_SIF, atchan->per_if) |
+				  FIELD_PREP(ATC_DIF, atchan->mem_if);
 		desc->len = period_len;
 		break;
 
@@ -2115,14 +2102,13 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
 		return NULL;
 	}
 
-	atslave->cfg = ATC_DST_H2SEL_HW | ATC_SRC_H2SEL_HW;
+	atslave->cfg = ATC_DST_H2SEL | ATC_SRC_H2SEL;
 	/*
 	 * We can fill both SRC_PER and DST_PER, one of these fields will be
 	 * ignored depending on DMA transfer direction.
 	 */
 	per_id = dma_spec->args[1] & AT91_DMA_CFG_PER_ID_MASK;
-	atslave->cfg |= ATC_DST_PER_MSB(per_id) | ATC_DST_PER(per_id)
-		     | ATC_SRC_PER_MSB(per_id) | ATC_SRC_PER(per_id);
+	atslave->cfg |= ATC_DST_PER_ID(per_id) |  ATC_SRC_PER_ID(per_id);
 	/*
 	 * We have to translate the value we get from the device tree since
 	 * the half FIFO configuration value had to be 0 to keep backward
@@ -2130,14 +2116,16 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
 	 */
 	switch (dma_spec->args[1] & AT91_DMA_CFG_FIFOCFG_MASK) {
 	case AT91_DMA_CFG_FIFOCFG_ALAP:
-		atslave->cfg |= ATC_FIFOCFG_LARGESTBURST;
+		atslave->cfg |= FIELD_PREP(ATC_FIFOCFG,
+					   ATC_FIFOCFG_LARGESTBURST);
 		break;
 	case AT91_DMA_CFG_FIFOCFG_ASAP:
-		atslave->cfg |= ATC_FIFOCFG_ENOUGHSPACE;
+		atslave->cfg |= FIELD_PREP(ATC_FIFOCFG,
+					   ATC_FIFOCFG_ENOUGHSPACE);
 		break;
 	case AT91_DMA_CFG_FIFOCFG_HALF:
 	default:
-		atslave->cfg |= ATC_FIFOCFG_HALFFIFO;
+		atslave->cfg |= FIELD_PREP(ATC_FIFOCFG, ATC_FIFOCFG_HALFFIFO);
 	}
 	atslave->dma_dev = &dmac_pdev->dev;
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 29/32] dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (27 preceding siblings ...)
  2022-10-25  9:03 ` [PATCH v2 28/32] dmaengine: at_hdmac: Use bitfield access macros Tudor Ambarus
@ 2022-10-25  9:03 ` Tudor Ambarus
  2022-10-25  9:03 ` [PATCH v2 30/32] dmaengine: at_hdmac: Rename "chan_common" to "dma_chan" Tudor Ambarus
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:03 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

"dma_common" name was misleading and did not suggest that's actually
a struct dma_device underneath. Rename it so that readers can follow the
code easier. One may see some checks and a warning when running
checkpatch. Those have nothing to do with the rename and will be addressed
in a further patch.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 92 +++++++++++++++++++++---------------------
 1 file changed, 46 insertions(+), 46 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index edec6a8c730c..b2619600f68a 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -338,7 +338,7 @@ static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
 
 /**
  * struct at_dma - internal representation of an Atmel HDMA Controller
- * @chan_common: common dmaengine dma_device object members
+ * @dma_device: dmaengine dma_device object members
  * @atdma_devtype: identifier of DMA controller compatibility
  * @ch_regs: memory mapped register base
  * @clk: dma controller clock
@@ -348,7 +348,7 @@ static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
  * @chan: channels table to store at_dma_chan structures
  */
 struct at_dma {
-	struct dma_device	dma_common;
+	struct dma_device	dma_device;
 	void __iomem		*regs;
 	struct clk		*clk;
 	u32			save_imr;
@@ -368,7 +368,7 @@ struct at_dma {
 
 static inline struct at_dma *to_at_dma(struct dma_device *ddev)
 {
-	return container_of(ddev, struct at_dma, dma_common);
+	return container_of(ddev, struct at_dma, dma_device);
 }
 
 
@@ -1069,11 +1069,11 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
 		if (!pending)
 			break;
 
-		dev_vdbg(atdma->dma_common.dev,
+		dev_vdbg(atdma->dma_device.dev,
 			"interrupt: status = 0x%08x, 0x%08x, 0x%08x\n",
 			 status, imr, pending);
 
-		for (i = 0; i < atdma->dma_common.chancnt; i++) {
+		for (i = 0; i < atdma->dma_device.chancnt; i++) {
 			atchan = &atdma->chan[i];
 			if (pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))) {
 				if (pending & AT_DMA_ERR(i)) {
@@ -2000,7 +2000,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 		 * We need controller-specific data to set up slave
 		 * transfers.
 		 */
-		BUG_ON(!atslave->dma_dev || atslave->dma_dev != atdma->dma_common.dev);
+		BUG_ON(!atslave->dma_dev || atslave->dma_dev != atdma->dma_device.dev);
 
 		/* if cfg configuration specified take it instead of default */
 		if (atslave->cfg)
@@ -2011,7 +2011,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 	for (i = 0; i < init_nr_desc_per_channel; i++) {
 		desc = atc_alloc_descriptor(chan, GFP_KERNEL);
 		if (!desc) {
-			dev_err(atdma->dma_common.dev,
+			dev_err(atdma->dma_device.dev,
 				"Only %d initial descriptors\n", i);
 			break;
 		}
@@ -2255,7 +2255,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
 		return irq;
 
 	/* discover transaction capabilities */
-	atdma->dma_common.cap_mask = plat_dat->cap_mask;
+	atdma->dma_device.cap_mask = plat_dat->cap_mask;
 	atdma->all_chan_mask = (1 << plat_dat->nr_channels) - 1;
 
 	atdma->clk = devm_clk_get(&pdev->dev, "dma_clk");
@@ -2299,16 +2299,16 @@ static int __init at_dma_probe(struct platform_device *pdev)
 		cpu_relax();
 
 	/* initialize channels related values */
-	INIT_LIST_HEAD(&atdma->dma_common.channels);
+	INIT_LIST_HEAD(&atdma->dma_device.channels);
 	for (i = 0; i < plat_dat->nr_channels; i++) {
 		struct at_dma_chan	*atchan = &atdma->chan[i];
 
 		atchan->mem_if = AT_DMA_MEM_IF;
 		atchan->per_if = AT_DMA_PER_IF;
-		atchan->chan_common.device = &atdma->dma_common;
+		atchan->chan_common.device = &atdma->dma_device;
 		dma_cookie_init(&atchan->chan_common);
 		list_add_tail(&atchan->chan_common.device_node,
-				&atdma->dma_common.channels);
+				&atdma->dma_device.channels);
 
 		atchan->ch_regs = atdma->regs + ch_regs(i);
 		spin_lock_init(&atchan->lock);
@@ -2323,49 +2323,49 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	}
 
 	/* set base routines */
-	atdma->dma_common.device_alloc_chan_resources = atc_alloc_chan_resources;
-	atdma->dma_common.device_free_chan_resources = atc_free_chan_resources;
-	atdma->dma_common.device_tx_status = atc_tx_status;
-	atdma->dma_common.device_issue_pending = atc_issue_pending;
-	atdma->dma_common.dev = &pdev->dev;
+	atdma->dma_device.device_alloc_chan_resources = atc_alloc_chan_resources;
+	atdma->dma_device.device_free_chan_resources = atc_free_chan_resources;
+	atdma->dma_device.device_tx_status = atc_tx_status;
+	atdma->dma_device.device_issue_pending = atc_issue_pending;
+	atdma->dma_device.dev = &pdev->dev;
 
 	/* set prep routines based on capability */
-	if (dma_has_cap(DMA_INTERLEAVE, atdma->dma_common.cap_mask))
-		atdma->dma_common.device_prep_interleaved_dma = atc_prep_dma_interleaved;
+	if (dma_has_cap(DMA_INTERLEAVE, atdma->dma_device.cap_mask))
+		atdma->dma_device.device_prep_interleaved_dma = atc_prep_dma_interleaved;
 
-	if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask))
-		atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy;
+	if (dma_has_cap(DMA_MEMCPY, atdma->dma_device.cap_mask))
+		atdma->dma_device.device_prep_dma_memcpy = atc_prep_dma_memcpy;
 
-	if (dma_has_cap(DMA_MEMSET, atdma->dma_common.cap_mask)) {
-		atdma->dma_common.device_prep_dma_memset = atc_prep_dma_memset;
-		atdma->dma_common.device_prep_dma_memset_sg = atc_prep_dma_memset_sg;
-		atdma->dma_common.fill_align = DMAENGINE_ALIGN_4_BYTES;
+	if (dma_has_cap(DMA_MEMSET, atdma->dma_device.cap_mask)) {
+		atdma->dma_device.device_prep_dma_memset = atc_prep_dma_memset;
+		atdma->dma_device.device_prep_dma_memset_sg = atc_prep_dma_memset_sg;
+		atdma->dma_device.fill_align = DMAENGINE_ALIGN_4_BYTES;
 	}
 
-	if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) {
-		atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg;
+	if (dma_has_cap(DMA_SLAVE, atdma->dma_device.cap_mask)) {
+		atdma->dma_device.device_prep_slave_sg = atc_prep_slave_sg;
 		/* controller can do slave DMA: can trigger cyclic transfers */
-		dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask);
-		atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic;
-		atdma->dma_common.device_config = atc_config;
-		atdma->dma_common.device_pause = atc_pause;
-		atdma->dma_common.device_resume = atc_resume;
-		atdma->dma_common.device_terminate_all = atc_terminate_all;
-		atdma->dma_common.src_addr_widths = ATC_DMA_BUSWIDTHS;
-		atdma->dma_common.dst_addr_widths = ATC_DMA_BUSWIDTHS;
-		atdma->dma_common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
-		atdma->dma_common.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+		dma_cap_set(DMA_CYCLIC, atdma->dma_device.cap_mask);
+		atdma->dma_device.device_prep_dma_cyclic = atc_prep_dma_cyclic;
+		atdma->dma_device.device_config = atc_config;
+		atdma->dma_device.device_pause = atc_pause;
+		atdma->dma_device.device_resume = atc_resume;
+		atdma->dma_device.device_terminate_all = atc_terminate_all;
+		atdma->dma_device.src_addr_widths = ATC_DMA_BUSWIDTHS;
+		atdma->dma_device.dst_addr_widths = ATC_DMA_BUSWIDTHS;
+		atdma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+		atdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
 	}
 
 	dma_writel(atdma, EN, AT_DMA_ENABLE);
 
 	dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s%s), %d channels\n",
-	  dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "",
-	  dma_has_cap(DMA_MEMSET, atdma->dma_common.cap_mask) ? "set " : "",
-	  dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)  ? "slave " : "",
+	  dma_has_cap(DMA_MEMCPY, atdma->dma_device.cap_mask) ? "cpy " : "",
+	  dma_has_cap(DMA_MEMSET, atdma->dma_device.cap_mask) ? "set " : "",
+	  dma_has_cap(DMA_SLAVE, atdma->dma_device.cap_mask)  ? "slave " : "",
 	  plat_dat->nr_channels);
 
-	err = dma_async_device_register(&atdma->dma_common);
+	err = dma_async_device_register(&atdma->dma_device);
 	if (err) {
 		dev_err(&pdev->dev, "Unable to register: %d.\n", err);
 		goto err_dma_async_device_register;
@@ -2388,7 +2388,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	return 0;
 
 err_of_dma_controller_register:
-	dma_async_device_unregister(&atdma->dma_common);
+	dma_async_device_unregister(&atdma->dma_device);
 err_dma_async_device_register:
 	dma_pool_destroy(atdma->memset_pool);
 err_memset_pool_create:
@@ -2408,13 +2408,13 @@ static int at_dma_remove(struct platform_device *pdev)
 	at_dma_off(atdma);
 	if (pdev->dev.of_node)
 		of_dma_controller_free(pdev->dev.of_node);
-	dma_async_device_unregister(&atdma->dma_common);
+	dma_async_device_unregister(&atdma->dma_device);
 
 	dma_pool_destroy(atdma->memset_pool);
 	dma_pool_destroy(atdma->dma_desc_pool);
 	free_irq(platform_get_irq(pdev, 0), atdma);
 
-	list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
+	list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
 			device_node) {
 		struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 
@@ -2443,7 +2443,7 @@ static int at_dma_prepare(struct device *dev)
 	struct at_dma *atdma = dev_get_drvdata(dev);
 	struct dma_chan *chan, *_chan;
 
-	list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
+	list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
 			device_node) {
 		struct at_dma_chan *atchan = to_at_dma_chan(chan);
 		/* wait for transaction completion (except in cyclic case) */
@@ -2478,7 +2478,7 @@ static int at_dma_suspend_noirq(struct device *dev)
 	struct dma_chan *chan, *_chan;
 
 	/* preserve data */
-	list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
+	list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
 			device_node) {
 		struct at_dma_chan *atchan = to_at_dma_chan(chan);
 
@@ -2528,7 +2528,7 @@ static int at_dma_resume_noirq(struct device *dev)
 
 	/* restore saved data */
 	dma_writel(atdma, EBCIER, atdma->save_imr);
-	list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
+	list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
 			device_node) {
 		struct at_dma_chan *atchan = to_at_dma_chan(chan);
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 30/32] dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (28 preceding siblings ...)
  2022-10-25  9:03 ` [PATCH v2 29/32] dmaengine: at_hdmac: Rename "dma_common" to "dma_device" Tudor Ambarus
@ 2022-10-25  9:03 ` Tudor Ambarus
  2022-10-25  9:03 ` [PATCH v2 31/32] dmaengine: at_hdmac: Remove unused member of at_dma_chan Tudor Ambarus
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:03 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

"chan_common" was misleading and did not suggest that's actually
a struct dma_chan underneath. Rename it so that readers can follow the
code easier. One may see some checks when running checkpatch. Those have
nothing to do with the rename and will be addressed in a further patch.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 62 +++++++++++++++++++++---------------------
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index b2619600f68a..e39b9b47234a 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -252,7 +252,7 @@ enum atc_status {
 
 /**
  * struct at_dma_chan - internal representation of an Atmel HDMAC channel
- * @chan_common: common dmaengine channel object members
+ * @dma_chan: common dmaengine channel object members
  * @device: parent device
  * @ch_regs: memory mapped register base
  * @mask: channel index in a mask
@@ -272,7 +272,7 @@ enum atc_status {
  * @free_list: list of descriptors usable by the channel
  */
 struct at_dma_chan {
-	struct dma_chan		chan_common;
+	struct dma_chan		dma_chan;
 	struct at_dma		*device;
 	void __iomem		*ch_regs;
 	u8			mask;
@@ -300,7 +300,7 @@ struct at_dma_chan {
 
 static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
 {
-	return container_of(dchan, struct at_dma_chan, chan_common);
+	return container_of(dchan, struct at_dma_chan, dma_chan);
 }
 
 /*
@@ -382,15 +382,15 @@ static struct device *chan2dev(struct dma_chan *chan)
 #if defined(VERBOSE_DEBUG)
 static void vdbg_dump_regs(struct at_dma_chan *atchan)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
+	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
 
-	dev_err(chan2dev(&atchan->chan_common),
+	dev_err(chan2dev(&atchan->dma_chan),
 		"  channel %d : imr = 0x%x, chsr = 0x%x\n",
-		atchan->chan_common.chan_id,
+		atchan->dma_chan.chan_id,
 		dma_readl(atdma, EBCIMR),
 		dma_readl(atdma, CHSR));
 
-	dev_err(chan2dev(&atchan->chan_common),
+	dev_err(chan2dev(&atchan->dma_chan),
 		"  channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n",
 		channel_readl(atchan, SADDR),
 		channel_readl(atchan, DADDR),
@@ -405,7 +405,7 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
 
 static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
 {
-	dev_crit(chan2dev(&atchan->chan_common),
+	dev_crit(chan2dev(&atchan->dma_chan),
 		 "desc: s%pad d%pad ctrl0x%x:0x%x l%pad\n",
 		 &lli->saddr, &lli->daddr,
 		 lli->ctrla, lli->ctrlb, &lli->dscr);
@@ -442,7 +442,7 @@ static void atc_disable_chan_irq(struct at_dma *atdma, int chan_id)
  */
 static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
+	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
 
 	return !!(dma_readl(atdma, CHSR) & atchan->mask);
 }
@@ -603,16 +603,16 @@ static struct at_desc *atc_desc_get(struct at_dma_chan *atchan)
 			ret = desc;
 			break;
 		}
-		dev_dbg(chan2dev(&atchan->chan_common),
+		dev_dbg(chan2dev(&atchan->dma_chan),
 				"desc %p not ACKed\n", desc);
 	}
 	spin_unlock_irqrestore(&atchan->lock, flags);
-	dev_vdbg(chan2dev(&atchan->chan_common),
+	dev_vdbg(chan2dev(&atchan->dma_chan),
 		"scanned %u descriptors on freelist\n", i);
 
 	/* no more descriptor available in initial pool: create one more */
 	if (!ret)
-		ret = atc_alloc_descriptor(&atchan->chan_common, GFP_NOWAIT);
+		ret = atc_alloc_descriptor(&atchan->dma_chan, GFP_NOWAIT);
 
 	return ret;
 }
@@ -630,11 +630,11 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc)
 
 		spin_lock_irqsave(&atchan->lock, flags);
 		list_for_each_entry(child, &desc->tx_list, desc_node)
-			dev_vdbg(chan2dev(&atchan->chan_common),
+			dev_vdbg(chan2dev(&atchan->dma_chan),
 					"moving child desc %p to freelist\n",
 					child);
 		list_splice_init(&desc->tx_list, &atchan->free_list);
-		dev_vdbg(chan2dev(&atchan->chan_common),
+		dev_vdbg(chan2dev(&atchan->dma_chan),
 			 "moving desc %p to freelist\n", desc);
 		list_add(&desc->desc_node, &atchan->free_list);
 		spin_unlock_irqrestore(&atchan->lock, flags);
@@ -673,13 +673,13 @@ static void atc_desc_chain(struct at_desc **first, struct at_desc **prev,
  */
 static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
+	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
 
 	/* ASSERT:  channel is idle */
 	if (atc_chan_is_enabled(atchan)) {
-		dev_err(chan2dev(&atchan->chan_common),
+		dev_err(chan2dev(&atchan->dma_chan),
 			"BUG: Attempted to start non-idle channel\n");
-		dev_err(chan2dev(&atchan->chan_common),
+		dev_err(chan2dev(&atchan->dma_chan),
 			"  channel: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n",
 			channel_readl(atchan, SADDR),
 			channel_readl(atchan, DADDR),
@@ -905,10 +905,10 @@ static void
 atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
 {
 	struct dma_async_tx_descriptor	*txd = &desc->txd;
-	struct at_dma			*atdma = to_at_dma(atchan->chan_common.device);
+	struct at_dma			*atdma = to_at_dma(atchan->dma_chan.device);
 	unsigned long flags;
 
-	dev_vdbg(chan2dev(&atchan->chan_common),
+	dev_vdbg(chan2dev(&atchan->dma_chan),
 		"descriptor %u complete\n", txd->cookie);
 
 	spin_lock_irqsave(&atchan->lock, flags);
@@ -951,7 +951,7 @@ static void atc_advance_work(struct at_dma_chan *atchan)
 	struct at_desc *desc;
 	unsigned long flags;
 
-	dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n");
+	dev_vdbg(chan2dev(&atchan->dma_chan), "advance_work\n");
 
 	spin_lock_irqsave(&atchan->lock, flags);
 	if (atc_chan_is_enabled(atchan) || list_empty(&atchan->active_list))
@@ -1010,9 +1010,9 @@ static void atc_handle_error(struct at_dma_chan *atchan)
 	 * controller flagged an error instead of scribbling over
 	 * random memory locations.
 	 */
-	dev_crit(chan2dev(&atchan->chan_common),
+	dev_crit(chan2dev(&atchan->dma_chan),
 			"Bad descriptor submitted for DMA!\n");
-	dev_crit(chan2dev(&atchan->chan_common),
+	dev_crit(chan2dev(&atchan->dma_chan),
 			"  cookie: %d\n", bad_desc->txd.cookie);
 	atc_dump_lli(atchan, &bad_desc->lli);
 	list_for_each_entry(child, &bad_desc->tx_list, desc_node)
@@ -1031,7 +1031,7 @@ static void atc_handle_cyclic(struct at_dma_chan *atchan)
 	struct at_desc			*first = atc_first_active(atchan);
 	struct dma_async_tx_descriptor	*txd = &first->txd;
 
-	dev_vdbg(chan2dev(&atchan->chan_common),
+	dev_vdbg(chan2dev(&atchan->dma_chan),
 			"new cyclic period llp 0x%08x\n",
 			channel_readl(atchan, DSCR));
 
@@ -1825,7 +1825,7 @@ static int atc_pause(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	int			chan_id = atchan->chan_common.chan_id;
+	int			chan_id = atchan->dma_chan.chan_id;
 	unsigned long		flags;
 
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
@@ -1844,7 +1844,7 @@ static int atc_resume(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	int			chan_id = atchan->chan_common.chan_id;
+	int			chan_id = atchan->dma_chan.chan_id;
 	unsigned long		flags;
 
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
@@ -1866,7 +1866,7 @@ static int atc_terminate_all(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	int			chan_id = atchan->chan_common.chan_id;
+	int			chan_id = atchan->dma_chan.chan_id;
 	unsigned long		flags;
 
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
@@ -2305,9 +2305,9 @@ static int __init at_dma_probe(struct platform_device *pdev)
 
 		atchan->mem_if = AT_DMA_MEM_IF;
 		atchan->per_if = AT_DMA_PER_IF;
-		atchan->chan_common.device = &atdma->dma_device;
-		dma_cookie_init(&atchan->chan_common);
-		list_add_tail(&atchan->chan_common.device_node,
+		atchan->dma_chan.device = &atdma->dma_device;
+		dma_cookie_init(&atchan->dma_chan);
+		list_add_tail(&atchan->dma_chan.device_node,
 				&atdma->dma_device.channels);
 
 		atchan->ch_regs = atdma->regs + ch_regs(i);
@@ -2455,7 +2455,7 @@ static int at_dma_prepare(struct device *dev)
 
 static void atc_suspend_cyclic(struct at_dma_chan *atchan)
 {
-	struct dma_chan	*chan = &atchan->chan_common;
+	struct dma_chan	*chan = &atchan->dma_chan;
 
 	/* Channel should be paused by user
 	 * do it anyway even if it is not done already */
@@ -2496,7 +2496,7 @@ static int at_dma_suspend_noirq(struct device *dev)
 
 static void atc_resume_cyclic(struct at_dma_chan *atchan)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->chan_common.device);
+	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
 
 	/* restore channel status for cyclic descriptors list:
 	 * next descriptor in the cyclic list at the time of suspend */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 31/32] dmaengine: at_hdmac: Remove unused member of at_dma_chan
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (29 preceding siblings ...)
  2022-10-25  9:03 ` [PATCH v2 30/32] dmaengine: at_hdmac: Rename "chan_common" to "dma_chan" Tudor Ambarus
@ 2022-10-25  9:03 ` Tudor Ambarus
  2022-10-25  9:03 ` [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma Tudor Ambarus
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:03 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

The pointer to at_dma engine was never used, remove it.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/at_hdmac.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index e39b9b47234a..143d75c18d1e 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -253,7 +253,6 @@ enum atc_status {
 /**
  * struct at_dma_chan - internal representation of an Atmel HDMAC channel
  * @dma_chan: common dmaengine channel object members
- * @device: parent device
  * @ch_regs: memory mapped register base
  * @mask: channel index in a mask
  * @per_if: peripheral interface
@@ -273,7 +272,6 @@ enum atc_status {
  */
 struct at_dma_chan {
 	struct dma_chan		dma_chan;
-	struct at_dma		*device;
 	void __iomem		*ch_regs;
 	u8			mask;
 	u8			per_if;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (30 preceding siblings ...)
  2022-10-25  9:03 ` [PATCH v2 31/32] dmaengine: at_hdmac: Remove unused member of at_dma_chan Tudor Ambarus
@ 2022-10-25  9:03 ` Tudor Ambarus
  2022-10-28 12:55   ` Nicolas Ferre
  2022-10-25  9:06 ` [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor.Ambarus
                   ` (2 subsequent siblings)
  34 siblings, 1 reply; 42+ messages in thread
From: Tudor Ambarus @ 2022-10-25  9:03 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel, Tudor Ambarus

Convert the driver to use the core virt-dma. The driver will be easier to
maintain as it uses the list handling and the tasklet from virt-dma.

With the conversion replace the election of a new transfer in the tasklet
with the election of the new transfer in the interrupt handler. With this
we have a shorter idle window as we remove the scheduling latency of the
tasklet. I chose to do this while doing the conversion to virt-dma,
because if I made a prerequisite patch with the new transfer election in
the irq handler, I would have to duplicate some virt-dma code in the
at_hdmac driver that would end up being removed at the virt-dma conversion
anyway. So do this in a single step.

Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>
---
 drivers/dma/Kconfig    |    1 +
 drivers/dma/at_hdmac.c | 1108 +++++++++++++++-------------------------
 2 files changed, 403 insertions(+), 706 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index b73fc89ba877..80848c6b5cd5 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -97,6 +97,7 @@ config AT_HDMAC
 	tristate "Atmel AHB DMA support"
 	depends on ARCH_AT91
 	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
 	help
 	  Support the Atmel AHB DMA controller.
 
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 143d75c18d1e..8858470246e1 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -3,6 +3,7 @@
  * Driver for the Atmel AHB DMA Controller (aka HDMA or DMAC on AT91 systems)
  *
  * Copyright (C) 2008 Atmel Corporation
+ * Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
  *
  * This supports the Atmel AHB DMA Controller found in several Atmel SoCs.
  * The only Atmel DMA Controller that is not covered by this driver is the one
@@ -25,6 +26,7 @@
 #include <linux/slab.h>
 
 #include "dmaengine.h"
+#include "virt-dma.h"
 
 /*
  * Glossary
@@ -200,25 +202,31 @@ struct at_lli {
 	u32 dscr;	/* chain to next lli */
 };
 
+/**
+ * struct atdma_sg - atdma scatter gather entry
+ * @len: length of the current Linked List Item.
+ * @lli: linked list item that is passed to the DMA controller
+ * @lli_phys: physical address of the LLI.
+ */
+struct atdma_sg {
+	unsigned int len;
+	struct at_lli *lli;
+	dma_addr_t lli_phys;
+};
+
 /**
  * struct at_desc - software descriptor
- * @at_lli: hardware lli structure
- * @txd: support for the async_tx api
- * @desc_node: node on the channed descriptors list
- * @len: descriptor byte count
+ * @vd: pointer to the virtual dma descriptor.
+ * @atchan: pointer to the atmel dma channel.
  * @total_len: total transaction byte count
+ * @sg_len: number of sg entries.
+ * @sg: array of sgs.
  */
 struct at_desc {
-	/* FIRST values the hardware uses */
-	struct at_lli			lli;
-
-	/* THEN values for driver housekeeping */
-	struct list_head		tx_list;
-	struct dma_async_tx_descriptor	txd;
-	struct list_head		desc_node;
-	size_t				len;
+	struct				virt_dma_desc vd;
+	struct				at_dma_chan *atchan;
 	size_t				total_len;
-
+	unsigned int			sglen;
 	/* Interleaved data */
 	size_t				boundary;
 	size_t				dst_hole;
@@ -228,15 +236,9 @@ struct at_desc {
 	bool				memset_buffer;
 	dma_addr_t			memset_paddr;
 	int				*memset_vaddr;
+	struct atdma_sg			sg[];
 };
 
-static inline struct at_desc *
-txd_to_at_desc(struct dma_async_tx_descriptor *txd)
-{
-	return container_of(txd, struct at_desc, txd);
-}
-
-
 /*--  Channels  --------------------------------------------------------*/
 
 /**
@@ -245,49 +247,40 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
  * Manipulated with atomic operations.
  */
 enum atc_status {
-	ATC_IS_ERROR = 0,
 	ATC_IS_PAUSED = 1,
 	ATC_IS_CYCLIC = 24,
 };
 
 /**
  * struct at_dma_chan - internal representation of an Atmel HDMAC channel
- * @dma_chan: common dmaengine channel object members
+ * @vc: virtual dma channel entry.
+ * @atdma: pointer to the driver data.
  * @ch_regs: memory mapped register base
  * @mask: channel index in a mask
  * @per_if: peripheral interface
  * @mem_if: memory interface
  * @status: transmit status information from irq/prep* functions
  *                to tasklet (use atomic operations)
- * @tasklet: bottom half to finish transaction work
  * @save_cfg: configuration register that is saved on suspend/resume cycle
  * @save_dscr: for cyclic operations, preserve next descriptor address in
  *             the cyclic list on suspend/resume cycle
  * @dma_sconfig: configuration for slave transfers, passed via
  * .device_config
- * @lock: serializes enqueue/dequeue operations to descriptors lists
- * @active_list: list of descriptors dmaengine is being running on
- * @queue: list of descriptors ready to be submitted to engine
- * @free_list: list of descriptors usable by the channel
+ * @desc: pointer to the atmel dma descriptor.
  */
 struct at_dma_chan {
-	struct dma_chan		dma_chan;
+	struct virt_dma_chan	vc;
+	struct at_dma		*atdma;
 	void __iomem		*ch_regs;
 	u8			mask;
 	u8			per_if;
 	u8			mem_if;
 	unsigned long		status;
-	struct tasklet_struct	tasklet;
 	u32			save_cfg;
 	u32			save_dscr;
-	struct dma_slave_config dma_sconfig;
-
-	spinlock_t		lock;
-
-	/* these other elements are all protected by lock */
-	struct list_head	active_list;
-	struct list_head	queue;
-	struct list_head	free_list;
+	struct dma_slave_config	dma_sconfig;
+	bool			cyclic;
+	struct at_desc		*desc;
 };
 
 #define	channel_readl(atchan, name) \
@@ -296,11 +289,6 @@ struct at_dma_chan {
 #define	channel_writel(atchan, name, val) \
 	__raw_writel((val), (atchan)->ch_regs + ATC_##name##_OFFSET)
 
-static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *dchan)
-{
-	return container_of(dchan, struct at_dma_chan, dma_chan);
-}
-
 /*
  * Fix sconfig's burst size according to at_hdmac. We need to convert them as:
  * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3, 32 -> 4, 64 -> 5, 128 -> 6, 256 -> 7.
@@ -342,7 +330,7 @@ static inline u8 convert_buswidth(enum dma_slave_buswidth addr_width)
  * @clk: dma controller clock
  * @save_imr: interrupt mask register that is saved on suspend/resume cycle
  * @all_chan_mask: all channels availlable in a mask
- * @dma_desc_pool: base of DMA descriptor region (DMA address)
+ * @lli_pool: hw lli table
  * @chan: channels table to store at_dma_chan structures
  */
 struct at_dma {
@@ -353,7 +341,7 @@ struct at_dma {
 
 	u8			all_chan_mask;
 
-	struct dma_pool		*dma_desc_pool;
+	struct dma_pool		*lli_pool;
 	struct dma_pool		*memset_pool;
 	/* AT THE END channels table */
 	struct at_dma_chan	chan[];
@@ -364,6 +352,16 @@ struct at_dma {
 #define	dma_writel(atdma, name, val) \
 	__raw_writel((val), (atdma)->regs + AT_DMA_##name)
 
+static inline struct at_desc *to_atdma_desc(struct dma_async_tx_descriptor *t)
+{
+	return container_of(t, struct at_desc, vd.tx);
+}
+
+static inline struct at_dma_chan *to_at_dma_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct at_dma_chan, vc.chan);
+}
+
 static inline struct at_dma *to_at_dma(struct dma_device *ddev)
 {
 	return container_of(ddev, struct at_dma, dma_device);
@@ -380,15 +378,15 @@ static struct device *chan2dev(struct dma_chan *chan)
 #if defined(VERBOSE_DEBUG)
 static void vdbg_dump_regs(struct at_dma_chan *atchan)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
+	struct at_dma	*atdma = to_at_dma(atchan->vc.chan.device);
 
-	dev_err(chan2dev(&atchan->dma_chan),
+	dev_err(chan2dev(&atchan->vc.chan),
 		"  channel %d : imr = 0x%x, chsr = 0x%x\n",
-		atchan->dma_chan.chan_id,
+		atchan->vc.chan.chan_id,
 		dma_readl(atdma, EBCIMR),
 		dma_readl(atdma, CHSR));
 
-	dev_err(chan2dev(&atchan->dma_chan),
+	dev_err(chan2dev(&atchan->vc.chan),
 		"  channel: s0x%x d0x%x ctrl0x%x:0x%x cfg0x%x l0x%x\n",
 		channel_readl(atchan, SADDR),
 		channel_readl(atchan, DADDR),
@@ -403,7 +401,7 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
 
 static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
 {
-	dev_crit(chan2dev(&atchan->dma_chan),
+	dev_crit(chan2dev(&atchan->vc.chan),
 		 "desc: s%pad d%pad ctrl0x%x:0x%x l%pad\n",
 		 &lli->saddr, &lli->daddr,
 		 lli->ctrla, lli->ctrlb, &lli->dscr);
@@ -440,7 +438,7 @@ static void atc_disable_chan_irq(struct at_dma *atdma, int chan_id)
  */
 static inline int atc_chan_is_enabled(struct at_dma_chan *atchan)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
+	struct at_dma *atdma = to_at_dma(atchan->vc.chan.device);
 
 	return !!(dma_readl(atdma, CHSR) & atchan->mask);
 }
@@ -464,18 +462,19 @@ static inline int atc_chan_is_cyclic(struct at_dma_chan *atchan)
 }
 
 /**
- * set_desc_eol - set end-of-link to descriptor so it will end transfer
+ * set_lli_eol - set end-of-link to descriptor so it will end transfer
  * @desc: descriptor, signle or at the end of a chain, to end chain on
+ * @i: index of the atmel scatter gather entry that is at the end of the chain.
  */
-static void set_desc_eol(struct at_desc *desc)
+static void set_lli_eol(struct at_desc *desc, unsigned int i)
 {
-	u32 ctrlb = desc->lli.ctrlb;
+	u32 ctrlb = desc->sg[i].lli->ctrlb;
 
 	ctrlb &= ~ATC_IEN;
 	ctrlb |= ATC_SRC_DSCR_DIS | ATC_DST_DSCR_DIS;
 
-	desc->lli.ctrlb = ctrlb;
-	desc->lli.dscr = 0;
+	desc->sg[i].lli->ctrlb = ctrlb;
+	desc->sg[i].lli->dscr = 0;
 }
 
 #define	ATC_DEFAULT_CFG		FIELD_PREP(ATC_FIFOCFG, ATC_FIFOCFG_HALFFIFO)
@@ -518,13 +517,6 @@ struct at_dma_slave {
 	u32			cfg;
 };
 
-/* prototypes */
-static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx);
-static void atc_issue_pending(struct dma_chan *chan);
-
-
-/*----------------------------------------------------------------------*/
-
 static inline unsigned int atc_get_xfer_width(dma_addr_t src, dma_addr_t dst,
 						size_t len)
 {
@@ -540,196 +532,72 @@ static inline unsigned int atc_get_xfer_width(dma_addr_t src, dma_addr_t dst,
 	return width;
 }
 
-static struct at_desc *atc_first_active(struct at_dma_chan *atchan)
+static void atdma_lli_chain(struct at_desc *desc, unsigned int i)
 {
-	return list_first_entry(&atchan->active_list,
-				struct at_desc, desc_node);
-}
+	struct atdma_sg *atdma_sg = &desc->sg[i];
 
-static struct at_desc *atc_first_queued(struct at_dma_chan *atchan)
-{
-	return list_first_entry(&atchan->queue,
-				struct at_desc, desc_node);
-}
-
-/**
- * atc_alloc_descriptor - allocate and return an initialized descriptor
- * @chan: the channel to allocate descriptors for
- * @gfp_flags: GFP allocation flags
- *
- * Note: The ack-bit is positioned in the descriptor flag at creation time
- *       to make initial allocation more convenient. This bit will be cleared
- *       and control will be given to client at usage time (during
- *       preparation functions).
- */
-static struct at_desc *atc_alloc_descriptor(struct dma_chan *chan,
-					    gfp_t gfp_flags)
-{
-	struct at_desc	*desc = NULL;
-	struct at_dma	*atdma = to_at_dma(chan->device);
-	dma_addr_t phys;
-
-	desc = dma_pool_zalloc(atdma->dma_desc_pool, gfp_flags, &phys);
-	if (desc) {
-		INIT_LIST_HEAD(&desc->tx_list);
-		dma_async_tx_descriptor_init(&desc->txd, chan);
-		/* txd.flags will be overwritten in prep functions */
-		desc->txd.flags = DMA_CTRL_ACK;
-		desc->txd.tx_submit = atc_tx_submit;
-		desc->txd.phys = phys;
-	}
-
-	return desc;
-}
-
-/**
- * atc_desc_get - get an unused descriptor from free_list
- * @atchan: channel we want a new descriptor for
- */
-static struct at_desc *atc_desc_get(struct at_dma_chan *atchan)
-{
-	struct at_desc *desc, *_desc;
-	struct at_desc *ret = NULL;
-	unsigned long flags;
-	unsigned int i = 0;
-
-	spin_lock_irqsave(&atchan->lock, flags);
-	list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) {
-		i++;
-		if (async_tx_test_ack(&desc->txd)) {
-			list_del(&desc->desc_node);
-			ret = desc;
-			break;
-		}
-		dev_dbg(chan2dev(&atchan->dma_chan),
-				"desc %p not ACKed\n", desc);
-	}
-	spin_unlock_irqrestore(&atchan->lock, flags);
-	dev_vdbg(chan2dev(&atchan->dma_chan),
-		"scanned %u descriptors on freelist\n", i);
-
-	/* no more descriptor available in initial pool: create one more */
-	if (!ret)
-		ret = atc_alloc_descriptor(&atchan->dma_chan, GFP_NOWAIT);
-
-	return ret;
-}
-
-/**
- * atc_desc_put - move a descriptor, including any children, to the free list
- * @atchan: channel we work on
- * @desc: descriptor, at the head of a chain, to move to free list
- */
-static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc)
-{
-	if (desc) {
-		struct at_desc *child;
-		unsigned long flags;
-
-		spin_lock_irqsave(&atchan->lock, flags);
-		list_for_each_entry(child, &desc->tx_list, desc_node)
-			dev_vdbg(chan2dev(&atchan->dma_chan),
-					"moving child desc %p to freelist\n",
-					child);
-		list_splice_init(&desc->tx_list, &atchan->free_list);
-		dev_vdbg(chan2dev(&atchan->dma_chan),
-			 "moving desc %p to freelist\n", desc);
-		list_add(&desc->desc_node, &atchan->free_list);
-		spin_unlock_irqrestore(&atchan->lock, flags);
-	}
-}
-
-/**
- * atc_desc_chain - build chain adding a descriptor
- * @first: address of first descriptor of the chain
- * @prev: address of previous descriptor of the chain
- * @desc: descriptor to queue
- *
- * Called from prep_* functions
- */
-static void atc_desc_chain(struct at_desc **first, struct at_desc **prev,
-			   struct at_desc *desc)
-{
-	if (!(*first)) {
-		*first = desc;
-	} else {
-		/* inform the HW lli about chaining */
-		(*prev)->lli.dscr = desc->txd.phys;
-		/* insert the link descriptor to the LD ring */
-		list_add_tail(&desc->desc_node,
-				&(*first)->tx_list);
-	}
-	*prev = desc;
+	if (i)
+		desc->sg[i - 1].lli->dscr = atdma_sg->lli_phys;
 }
 
 /**
  * atc_dostart - starts the DMA engine for real
  * @atchan: the channel we want to start
- * @first: first descriptor in the list we want to begin with
- *
- * Called with atchan->lock held and bh disabled
  */
-static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
+static void atc_dostart(struct at_dma_chan *atchan)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
+	struct virt_dma_desc *vd = vchan_next_desc(&atchan->vc);
+	struct at_desc *desc;
 
-	/* ASSERT:  channel is idle */
-	if (atc_chan_is_enabled(atchan)) {
-		dev_err(chan2dev(&atchan->dma_chan),
-			"BUG: Attempted to start non-idle channel\n");
-		dev_err(chan2dev(&atchan->dma_chan),
-			"  channel: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n",
-			channel_readl(atchan, SADDR),
-			channel_readl(atchan, DADDR),
-			channel_readl(atchan, CTRLA),
-			channel_readl(atchan, CTRLB),
-			channel_readl(atchan, DSCR));
-
-		/* The tasklet will hopefully advance the queue... */
+	if (!vd) {
+		atchan->desc = NULL;
 		return;
 	}
 
 	vdbg_dump_regs(atchan);
 
+	list_del(&vd->node);
+	atchan->desc = desc = to_atdma_desc(&vd->tx);
+
 	channel_writel(atchan, SADDR, 0);
 	channel_writel(atchan, DADDR, 0);
 	channel_writel(atchan, CTRLA, 0);
 	channel_writel(atchan, CTRLB, 0);
-	channel_writel(atchan, DSCR, first->txd.phys);
-	channel_writel(atchan, SPIP, FIELD_PREP(ATC_SPIP_HOLE,
-						first->src_hole) |
-		       FIELD_PREP(ATC_SPIP_BOUNDARY, first->boundary));
-	channel_writel(atchan, DPIP, FIELD_PREP(ATC_DPIP_HOLE,
-						first->dst_hole) |
-		       FIELD_PREP(ATC_DPIP_BOUNDARY, first->boundary));
+	channel_writel(atchan, DSCR, desc->sg[0].lli_phys);
+	channel_writel(atchan, SPIP,
+		       FIELD_PREP(ATC_SPIP_HOLE, desc->src_hole) |
+		       FIELD_PREP(ATC_SPIP_BOUNDARY, desc->boundary));
+	channel_writel(atchan, DPIP,
+		       FIELD_PREP(ATC_DPIP_HOLE, desc->dst_hole) |
+		       FIELD_PREP(ATC_DPIP_BOUNDARY, desc->boundary));
+
 	/* Don't allow CPU to reorder channel enable. */
 	wmb();
-	dma_writel(atdma, CHER, atchan->mask);
+	dma_writel(atchan->atdma, CHER, atchan->mask);
 
 	vdbg_dump_regs(atchan);
 }
 
-/*
- * atc_get_desc_by_cookie - get the descriptor of a cookie
- * @atchan: the DMA channel
- * @cookie: the cookie to get the descriptor for
- */
-static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan,
-						dma_cookie_t cookie)
+static void atdma_desc_free(struct virt_dma_desc *vd)
 {
-	struct at_desc *desc, *_desc;
+	struct at_dma *atdma = to_at_dma(vd->tx.chan->device);
+	struct at_desc *desc = to_atdma_desc(&vd->tx);
+	unsigned int i;
 
-	list_for_each_entry_safe(desc, _desc, &atchan->queue, desc_node) {
-		if (desc->txd.cookie == cookie)
-			return desc;
+	for (i = 0; i < desc->sglen; i++) {
+		if (desc->sg[i].lli)
+			dma_pool_free(atdma->lli_pool, desc->sg[i].lli,
+				      desc->sg[i].lli_phys);
 	}
 
-	list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
-		if (desc->txd.cookie == cookie)
-			return desc;
+	/* If the transfer was a memset, free our temporary buffer */
+	if (desc->memset_buffer) {
+		dma_pool_free(atdma->memset_pool, desc->memset_vaddr,
+			      desc->memset_paddr);
+		desc->memset_buffer = false;
 	}
 
-	return NULL;
+	kfree(desc);
 }
 
 /**
@@ -756,20 +624,19 @@ static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla)
 /**
  * atc_get_llis_residue - Get residue for a hardware linked list transfer
  *
- * Calculate the residue by removing the length of the child descriptors already
- * transferred from the total length. To get the current child descriptor we can
- * use the value of the channel's DSCR register and compare it against the value
- * of the hardware linked list structure of each child descriptor.
+ * Calculate the residue by removing the length of the Linked List Item (LLI)
+ * already transferred from the total length. To get the current LLI we can use
+ * the value of the channel's DSCR register and compare it against the DSCR
+ * value of each LLI.
  *
  * The CTRLA register provides us with the amount of data already read from the
- * source for the current child descriptor. So we can compute a more accurate
- * residue by also removing the number of bytes corresponding to this amount of
- * data.
+ * source for the LLI. So we can compute a more accurate residue by also
+ * removing the number of bytes corresponding to this amount of data.
  *
  * However, the DSCR and CTRLA registers cannot be read both atomically. Hence a
- * race condition may occur: the first read register may refer to one child
- * descriptor whereas the second read may refer to a later child descriptor in
- * the list because of the DMA transfer progression inbetween the two reads.
+ * race condition may occur: the first read register may refer to one LLI
+ * whereas the second read may refer to a later LLI in the list because of the
+ * DMA transfer progression inbetween the two reads.
  *
  * One solution could have been to pause the DMA transfer, read the DSCR and
  * CTRLA then resume the DMA transfer. Nonetheless, this approach presents some
@@ -786,12 +653,11 @@ static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla)
  * Then we'd rather use another solution: the DSCR is read a first time, the
  * CTRLA is read in turn, next the DSCR is read a second time. If the two
  * consecutive read values of the DSCR are the same then we assume both refers
- * to the very same child descriptor as well as the CTRLA value read inbetween
- * does. For cyclic tranfers, the assumption is that a full loop is "not so
- * fast". If the two DSCR values are different, we read again the CTRLA then the
- * DSCR till two consecutive read values from DSCR are equal or till the
- * maximum trials is reach. This algorithm is very unlikely not to find a stable
- * value for DSCR.
+ * to the very same LLI as well as the CTRLA value read inbetween does. For
+ * cyclic tranfers, the assumption is that a full loop is "not so fast". If the
+ * two DSCR values are different, we read again the CTRLA then the DSCR till two
+ * consecutive read values from DSCR are equal or till the maximum trials is
+ * reach. This algorithm is very unlikely not to find a stable value for DSCR.
  * @atchan: pointer to an atmel hdmac channel.
  * @desc: pointer to the descriptor for which the residue is calculated.
  * @residue: residue to be set to dma_tx_state.
@@ -800,7 +666,6 @@ static inline u32 atc_calc_bytes_left(u32 current_len, u32 ctrla)
 static int atc_get_llis_residue(struct at_dma_chan *atchan,
 				struct at_desc *desc, u32 *residue)
 {
-	struct at_desc *child;
 	u32 len, ctrla, dscr;
 	unsigned int i;
 
@@ -836,24 +701,25 @@ static int atc_get_llis_residue(struct at_dma_chan *atchan,
 		return -ETIMEDOUT;
 
 	/* For the first descriptor we can be more accurate. */
-	if (desc->lli.dscr == dscr) {
+	if (desc->sg[0].lli->dscr == dscr) {
 		*residue = atc_calc_bytes_left(len, ctrla);
 		return 0;
 	}
+	len -= desc->sg[0].len;
 
-	len -= desc->len;
-	list_for_each_entry(child, &desc->tx_list, desc_node) {
-		if (child->lli.dscr == dscr)
+	for (i = 1; i < desc->sglen; i++) {
+		if (desc->sg[i].lli && desc->sg[i].lli->dscr == dscr)
 			break;
-		len -= child->len;
+		len -= desc->sg[i].len;
 	}
 
 	/*
-	 * For the current descriptor in the chain we can calculate the
-	 * remaining bytes using the channel's register.
+	 * For the current LLI in the chain we can calculate the remaining bytes
+	 * using the channel's CTRLA register.
 	 */
 	*residue = atc_calc_bytes_left(len, ctrla);
 	return 0;
+
 }
 
 /**
@@ -867,139 +733,42 @@ static int atc_get_llis_residue(struct at_dma_chan *atchan,
 static int atc_get_residue(struct dma_chan *chan, dma_cookie_t cookie,
 			   u32 *residue)
 {
-	struct at_dma_chan      *atchan = to_at_dma_chan(chan);
-	struct at_desc *desc_first = atc_first_active(atchan);
-	struct at_desc *desc;
+	struct at_dma_chan *atchan = to_at_dma_chan(chan);
+	struct virt_dma_desc *vd;
+	struct at_desc *desc = NULL;
 	u32 len, ctrla;
 
-	/*
-	 * If the cookie doesn't match to the currently running transfer then
-	 * we can return the total length of the associated DMA transfer,
-	 * because it is still queued.
-	 */
-	desc = atc_get_desc_by_cookie(atchan, cookie);
-	if (desc == NULL)
+	vd = vchan_find_desc(&atchan->vc, cookie);
+	if (vd)
+		desc = to_atdma_desc(&vd->tx);
+	else if (atchan->desc && atchan->desc->vd.tx.cookie == cookie)
+		desc = atchan->desc;
+
+	if (!desc)
 		return -EINVAL;
-	else if (desc != desc_first)
-		return desc->total_len;
 
-	if (desc_first->lli.dscr)
+	if (desc->sg[0].lli->dscr)
 		/* hardware linked list transfer */
-		return atc_get_llis_residue(atchan, desc_first, residue);
+		return atc_get_llis_residue(atchan, desc, residue);
 
 	/* single transfer */
-	len = desc_first->total_len;
+	len = desc->total_len;
 	ctrla = channel_readl(atchan, CTRLA);
 	*residue = atc_calc_bytes_left(len, ctrla);
 	return 0;
 }
 
-/**
- * atc_chain_complete - finish work for one transaction chain
- * @atchan: channel we work on
- * @desc: descriptor at the head of the chain we want do complete
- */
-static void
-atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
-{
-	struct dma_async_tx_descriptor	*txd = &desc->txd;
-	struct at_dma			*atdma = to_at_dma(atchan->dma_chan.device);
-	unsigned long flags;
-
-	dev_vdbg(chan2dev(&atchan->dma_chan),
-		"descriptor %u complete\n", txd->cookie);
-
-	spin_lock_irqsave(&atchan->lock, flags);
-
-	/* mark the descriptor as complete for non cyclic cases only */
-	if (!atc_chan_is_cyclic(atchan))
-		dma_cookie_complete(txd);
-
-	spin_unlock_irqrestore(&atchan->lock, flags);
-
-	dma_descriptor_unmap(txd);
-	/* for cyclic transfers,
-	 * no need to replay callback function while stopping */
-	if (!atc_chan_is_cyclic(atchan))
-		dmaengine_desc_get_callback_invoke(txd, NULL);
-
-	dma_run_dependencies(txd);
-
-	spin_lock_irqsave(&atchan->lock, flags);
-	/* move children to free_list */
-	list_splice_init(&desc->tx_list, &atchan->free_list);
-	/* add myself to free_list */
-	list_add(&desc->desc_node, &atchan->free_list);
-	spin_unlock_irqrestore(&atchan->lock, flags);
-
-	/* If the transfer was a memset, free our temporary buffer */
-	if (desc->memset_buffer) {
-		dma_pool_free(atdma->memset_pool, desc->memset_vaddr,
-			      desc->memset_paddr);
-		desc->memset_buffer = false;
-	}
-}
-
-/**
- * atc_advance_work - at the end of a transaction, move forward
- * @atchan: channel where the transaction ended
- */
-static void atc_advance_work(struct at_dma_chan *atchan)
-{
-	struct at_desc *desc;
-	unsigned long flags;
-
-	dev_vdbg(chan2dev(&atchan->dma_chan), "advance_work\n");
-
-	spin_lock_irqsave(&atchan->lock, flags);
-	if (atc_chan_is_enabled(atchan) || list_empty(&atchan->active_list))
-		return spin_unlock_irqrestore(&atchan->lock, flags);
-
-	desc = atc_first_active(atchan);
-	/* Remove the transfer node from the active list. */
-	list_del_init(&desc->desc_node);
-	spin_unlock_irqrestore(&atchan->lock, flags);
-	atc_chain_complete(atchan, desc);
-
-	/* advance work */
-	spin_lock_irqsave(&atchan->lock, flags);
-	if (!list_empty(&atchan->active_list)) {
-		desc = atc_first_queued(atchan);
-		list_move_tail(&desc->desc_node, &atchan->active_list);
-		atc_dostart(atchan, desc);
-	}
-	spin_unlock_irqrestore(&atchan->lock, flags);
-}
-
-
 /**
  * atc_handle_error - handle errors reported by DMA controller
- * @atchan: channel where error occurs
+ * @atchan: channel where error occurs.
+ * @i: channel index
  */
-static void atc_handle_error(struct at_dma_chan *atchan)
+static void atc_handle_error(struct at_dma_chan *atchan, unsigned int i)
 {
-	struct at_desc *bad_desc;
-	struct at_desc *desc;
-	struct at_desc *child;
-	unsigned long flags;
-
-	spin_lock_irqsave(&atchan->lock, flags);
-	/*
-	 * The descriptor currently at the head of the active list is
-	 * broked. Since we don't have any way to report errors, we'll
-	 * just have to scream loudly and try to carry on.
-	 */
-	bad_desc = atc_first_active(atchan);
-	list_del_init(&bad_desc->desc_node);
-
-	/* Try to restart the controller */
-	if (!list_empty(&atchan->active_list)) {
-		desc = atc_first_queued(atchan);
-		list_move_tail(&desc->desc_node, &atchan->active_list);
-		atc_dostart(atchan, desc);
-	}
+	struct at_desc *desc = atchan->desc;
 
-	spin_unlock_irqrestore(&atchan->lock, flags);
+	/* Disable channel on AHB error */
+	dma_writel(atchan->atdma, CHDR, AT_DMA_RES(i) | atchan->mask);
 
 	/*
 	 * KERN_CRITICAL may seem harsh, but since this only happens
@@ -1008,47 +777,37 @@ static void atc_handle_error(struct at_dma_chan *atchan)
 	 * controller flagged an error instead of scribbling over
 	 * random memory locations.
 	 */
-	dev_crit(chan2dev(&atchan->dma_chan),
-			"Bad descriptor submitted for DMA!\n");
-	dev_crit(chan2dev(&atchan->dma_chan),
-			"  cookie: %d\n", bad_desc->txd.cookie);
-	atc_dump_lli(atchan, &bad_desc->lli);
-	list_for_each_entry(child, &bad_desc->tx_list, desc_node)
-		atc_dump_lli(atchan, &child->lli);
-
-	/* Pretend the descriptor completed successfully */
-	atc_chain_complete(atchan, bad_desc);
-}
-
-/**
- * atc_handle_cyclic - at the end of a period, run callback function
- * @atchan: channel used for cyclic operations
- */
-static void atc_handle_cyclic(struct at_dma_chan *atchan)
-{
-	struct at_desc			*first = atc_first_active(atchan);
-	struct dma_async_tx_descriptor	*txd = &first->txd;
-
-	dev_vdbg(chan2dev(&atchan->dma_chan),
-			"new cyclic period llp 0x%08x\n",
-			channel_readl(atchan, DSCR));
-
-	dmaengine_desc_get_callback_invoke(txd, NULL);
+	dev_crit(chan2dev(&atchan->vc.chan), "Bad descriptor submitted for DMA!\n");
+	dev_crit(chan2dev(&atchan->vc.chan), "cookie: %d\n",
+		 desc->vd.tx.cookie);
+	for (i = 0; i < desc->sglen; i++)
+		atc_dump_lli(atchan, desc->sg[i].lli);
 }
 
-/*--  IRQ & Tasklet  ---------------------------------------------------*/
-
-static void atc_tasklet(struct tasklet_struct *t)
+static void atdma_handle_chan_done(struct at_dma_chan *atchan, u32 pending,
+				   unsigned int i)
 {
-	struct at_dma_chan *atchan = from_tasklet(atchan, t, tasklet);
+	struct at_desc *desc;
 
-	if (test_and_clear_bit(ATC_IS_ERROR, &atchan->status))
-		return atc_handle_error(atchan);
+	spin_lock(&atchan->vc.lock);
+	desc = atchan->desc;
 
-	if (atc_chan_is_cyclic(atchan))
-		return atc_handle_cyclic(atchan);
+	if (desc) {
+		if (pending & AT_DMA_ERR(i)) {
+			atc_handle_error(atchan, i);
+			/* Pretend the descriptor completed successfully */
+		}
 
-	atc_advance_work(atchan);
+		if (atc_chan_is_cyclic(atchan)) {
+			vchan_cyclic_callback(&desc->vd);
+		} else {
+			vchan_cookie_complete(&desc->vd);
+			atchan->desc = NULL;
+			if (!(atc_chan_is_enabled(atchan)))
+				atc_dostart(atchan);
+		}
+	}
+	spin_unlock(&atchan->vc.lock);
 }
 
 static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
@@ -1073,17 +832,10 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
 
 		for (i = 0; i < atdma->dma_device.chancnt; i++) {
 			atchan = &atdma->chan[i];
-			if (pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))) {
-				if (pending & AT_DMA_ERR(i)) {
-					/* Disable channel on AHB error */
-					dma_writel(atdma, CHDR,
-						AT_DMA_RES(i) | atchan->mask);
-					/* Give information to tasklet */
-					set_bit(ATC_IS_ERROR, &atchan->status);
-				}
-				tasklet_schedule(&atchan->tasklet);
-				ret = IRQ_HANDLED;
-			}
+			if (!(pending & (AT_DMA_BTC(i) | AT_DMA_ERR(i))))
+				continue;
+			atdma_handle_chan_done(atchan, pending, i);
+			ret = IRQ_HANDLED;
 		}
 
 	} while (pending);
@@ -1091,35 +843,7 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
 	return ret;
 }
 
-
 /*--  DMA Engine API  --------------------------------------------------*/
-
-/**
- * atc_tx_submit - set the prepared descriptor(s) to be executed by the engine
- * @tx: descriptor at the head of the transaction chain
- *
- * Queue chain if DMA engine is working already
- *
- * Cookie increment and adding to active_list or queue must be atomic
- */
-static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx)
-{
-	struct at_desc		*desc = txd_to_at_desc(tx);
-	struct at_dma_chan	*atchan = to_at_dma_chan(tx->chan);
-	dma_cookie_t		cookie;
-	unsigned long		flags;
-
-	spin_lock_irqsave(&atchan->lock, flags);
-	cookie = dma_cookie_assign(tx);
-
-	list_add_tail(&desc->desc_node, &atchan->queue);
-	spin_unlock_irqrestore(&atchan->lock, flags);
-
-	dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
-		 desc->txd.cookie);
-	return cookie;
-}
-
 /**
  * atc_prep_dma_interleaved - prepare memory to memory interleaved operation
  * @chan: the channel to prepare operation on
@@ -1131,9 +855,12 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
 			 struct dma_interleaved_template *xt,
 			 unsigned long flags)
 {
+	struct at_dma		*atdma = to_at_dma(chan->device);
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct data_chunk	*first;
-	struct at_desc		*desc = NULL;
+	struct atdma_sg		*atdma_sg;
+	struct at_desc		*desc;
+	struct at_lli		*lli;
 	size_t			xfer_count;
 	unsigned int		dwidth;
 	u32			ctrla;
@@ -1172,8 +899,7 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
 		len += chunk->size;
 	}
 
-	dwidth = atc_get_xfer_width(xt->src_start,
-				    xt->dst_start, len);
+	dwidth = atc_get_xfer_width(xt->src_start, xt->dst_start, len);
 
 	xfer_count = len >> dwidth;
 	if (xfer_count > ATC_BTSIZE_MAX) {
@@ -1190,32 +916,34 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
 		ATC_SRC_PIP | ATC_DST_PIP |
 		FIELD_PREP(ATC_FC, ATC_FC_MEM2MEM);
 
-	/* create the transfer */
-	desc = atc_desc_get(atchan);
-	if (!desc) {
-		dev_err(chan2dev(chan),
-			"%s: couldn't allocate our descriptor\n", __func__);
+	desc = kzalloc(struct_size(desc, sg, 1), GFP_ATOMIC);
+	if (!desc)
+		return NULL;
+	desc->sglen = 1;
+
+	atdma_sg = desc->sg;
+	atdma_sg->lli = dma_pool_alloc(atdma->lli_pool, GFP_NOWAIT,
+				       &atdma_sg->lli_phys);
+	if (!atdma_sg->lli) {
+		kfree(desc);
 		return NULL;
 	}
+	lli = atdma_sg->lli;
 
-	desc->lli.saddr = xt->src_start;
-	desc->lli.daddr = xt->dst_start;
-	desc->lli.ctrla = ctrla | xfer_count;
-	desc->lli.ctrlb = ctrlb;
+	lli->saddr = xt->src_start;
+	lli->daddr = xt->dst_start;
+	lli->ctrla = ctrla | xfer_count;
+	lli->ctrlb = ctrlb;
 
 	desc->boundary = first->size >> dwidth;
 	desc->dst_hole = (dmaengine_get_dst_icg(xt, first) >> dwidth) + 1;
 	desc->src_hole = (dmaengine_get_src_icg(xt, first) >> dwidth) + 1;
 
-	desc->txd.cookie = -EBUSY;
-	desc->total_len = desc->len = len;
-
-	/* set end-of-link to the last link descriptor of list*/
-	set_desc_eol(desc);
-
-	desc->txd.flags = flags; /* client is in control of this ack */
+	atdma_sg->len = len;
+	desc->total_len = len;
 
-	return &desc->txd;
+	set_lli_eol(desc, 0);
+	return vchan_tx_prep(&atchan->vc, &desc->vd, flags);
 }
 
 /**
@@ -1230,25 +958,32 @@ static struct dma_async_tx_descriptor *
 atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 		size_t len, unsigned long flags)
 {
+	struct at_dma		*atdma = to_at_dma(chan->device);
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_desc		*desc = NULL;
-	struct at_desc		*first = NULL;
-	struct at_desc		*prev = NULL;
 	size_t			xfer_count;
 	size_t			offset;
+	size_t			sg_len;
 	unsigned int		src_width;
 	unsigned int		dst_width;
+	unsigned int		i;
 	u32			ctrla;
 	u32			ctrlb;
 
-	dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d%pad s%pad l0x%zx f0x%lx\n",
-			&dest, &src, len, flags);
+	dev_dbg(chan2dev(chan), "prep_dma_memcpy: d%pad s%pad l0x%zx f0x%lx\n",
+		&dest, &src, len, flags);
 
 	if (unlikely(!len)) {
-		dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
+		dev_err(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
 		return NULL;
 	}
 
+	sg_len = DIV_ROUND_UP(len, ATC_BTSIZE_MAX);
+	desc = kzalloc(struct_size(desc, sg, sg_len), GFP_ATOMIC);
+	if (!desc)
+		return NULL;
+	desc->sglen = sg_len;
+
 	ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN |
 		FIELD_PREP(ATC_SRC_ADDR_MODE, ATC_SRC_ADDR_MODE_INCR) |
 		FIELD_PREP(ATC_DST_ADDR_MODE, ATC_DST_ADDR_MODE_INCR) |
@@ -1263,50 +998,49 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 	ctrla = FIELD_PREP(ATC_SRC_WIDTH, src_width) |
 		FIELD_PREP(ATC_DST_WIDTH, dst_width);
 
-	for (offset = 0; offset < len; offset += xfer_count << src_width) {
-		xfer_count = min_t(size_t, (len - offset) >> src_width,
-				ATC_BTSIZE_MAX);
+	for (offset = 0, i = 0; offset < len;
+	     offset += xfer_count << src_width, i++) {
+		struct atdma_sg *atdma_sg = &desc->sg[i];
+		struct at_lli *lli;
 
-		desc = atc_desc_get(atchan);
-		if (!desc)
+		atdma_sg->lli = dma_pool_alloc(atdma->lli_pool, GFP_NOWAIT,
+					       &atdma_sg->lli_phys);
+		if (!atdma_sg->lli)
 			goto err_desc_get;
+		lli = atdma_sg->lli;
+
+		xfer_count = min_t(size_t, (len - offset) >> src_width,
+				   ATC_BTSIZE_MAX);
 
-		desc->lli.saddr = src + offset;
-		desc->lli.daddr = dest + offset;
-		desc->lli.ctrla = ctrla | xfer_count;
-		desc->lli.ctrlb = ctrlb;
+		lli->saddr = src + offset;
+		lli->daddr = dest + offset;
+		lli->ctrla = ctrla | xfer_count;
+		lli->ctrlb = ctrlb;
 
-		desc->txd.cookie = 0;
-		desc->len = xfer_count << src_width;
+		desc->sg[i].len = xfer_count << src_width;
 
-		atc_desc_chain(&first, &prev, desc);
+		atdma_lli_chain(desc, i);
 	}
 
-	/* First descriptor of the chain embedds additional information */
-	first->txd.cookie = -EBUSY;
-	first->total_len = len;
+	desc->total_len = len;
 
 	/* set end-of-link to the last link descriptor of list*/
-	set_desc_eol(desc);
-
-	first->txd.flags = flags; /* client is in control of this ack */
+	set_lli_eol(desc, i - 1);
 
-	return &first->txd;
+	return vchan_tx_prep(&atchan->vc, &desc->vd, flags);
 
 err_desc_get:
-	atc_desc_put(atchan, first);
+	atdma_desc_free(&desc->vd);
 	return NULL;
 }
 
-static struct at_desc *atc_create_memset_desc(struct dma_chan *chan,
-					      dma_addr_t psrc,
-					      dma_addr_t pdst,
-					      size_t len)
+static int atdma_create_memset_lli(struct dma_chan *chan,
+				   struct atdma_sg *atdma_sg,
+				   dma_addr_t psrc, dma_addr_t pdst, size_t len)
 {
-	struct at_dma_chan *atchan = to_at_dma_chan(chan);
-	struct at_desc *desc;
+	struct at_dma *atdma = to_at_dma(chan->device);
+	struct at_lli *lli;
 	size_t xfer_count;
-
 	u32 ctrla = FIELD_PREP(ATC_SRC_WIDTH, 2) | FIELD_PREP(ATC_DST_WIDTH, 2);
 	u32 ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN |
 		    FIELD_PREP(ATC_SRC_ADDR_MODE, ATC_SRC_ADDR_MODE_FIXED) |
@@ -1315,27 +1049,24 @@ static struct at_desc *atc_create_memset_desc(struct dma_chan *chan,
 
 	xfer_count = len >> 2;
 	if (xfer_count > ATC_BTSIZE_MAX) {
-		dev_err(chan2dev(chan), "%s: buffer is too big\n",
-			__func__);
-		return NULL;
+		dev_err(chan2dev(chan), "%s: buffer is too big\n", __func__);
+		return -EINVAL;
 	}
 
-	desc = atc_desc_get(atchan);
-	if (!desc) {
-		dev_err(chan2dev(chan), "%s: can't get a descriptor\n",
-			__func__);
-		return NULL;
-	}
+	atdma_sg->lli = dma_pool_alloc(atdma->lli_pool, GFP_NOWAIT,
+				       &atdma_sg->lli_phys);
+	if (!atdma_sg->lli)
+		return -ENOMEM;
+	lli = atdma_sg->lli;
 
-	desc->lli.saddr = psrc;
-	desc->lli.daddr = pdst;
-	desc->lli.ctrla = ctrla | xfer_count;
-	desc->lli.ctrlb = ctrlb;
+	lli->saddr = psrc;
+	lli->daddr = pdst;
+	lli->ctrla = ctrla | xfer_count;
+	lli->ctrlb = ctrlb;
 
-	desc->txd.cookie = 0;
-	desc->len = len;
+	atdma_sg->len = len;
 
-	return desc;
+	return 0;
 }
 
 /**
@@ -1350,11 +1081,13 @@ static struct dma_async_tx_descriptor *
 atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
 		    size_t len, unsigned long flags)
 {
+	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
 	struct at_desc		*desc;
 	void __iomem		*vaddr;
 	dma_addr_t		paddr;
 	char			fill_pattern;
+	int			ret;
 
 	dev_vdbg(chan2dev(chan), "%s: d%pad v0x%x l0x%zx f0x%lx\n", __func__,
 		&dest, value, len, flags);
@@ -1385,27 +1118,28 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
 		       (fill_pattern << 8) |
 		       fill_pattern;
 
-	desc = atc_create_memset_desc(chan, paddr, dest, len);
-	if (!desc) {
-		dev_err(chan2dev(chan), "%s: couldn't get a descriptor\n",
-			__func__);
+	desc = kzalloc(struct_size(desc, sg, 1), GFP_ATOMIC);
+	if (!desc)
 		goto err_free_buffer;
-	}
+	desc->sglen = 1;
+
+	ret = atdma_create_memset_lli(chan, desc->sg, paddr, dest, len);
+	if (ret)
+		goto err_free_desc;
 
 	desc->memset_paddr = paddr;
 	desc->memset_vaddr = vaddr;
 	desc->memset_buffer = true;
 
-	desc->txd.cookie = -EBUSY;
 	desc->total_len = len;
 
 	/* set end-of-link on the descriptor */
-	set_desc_eol(desc);
-
-	desc->txd.flags = flags;
+	set_lli_eol(desc, 0);
 
-	return &desc->txd;
+	return vchan_tx_prep(&atchan->vc, &desc->vd, flags);
 
+err_free_desc:
+	kfree(desc);
 err_free_buffer:
 	dma_pool_free(atdma->memset_pool, vaddr, paddr);
 	return NULL;
@@ -1419,12 +1153,13 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	struct at_desc		*desc = NULL, *first = NULL, *prev = NULL;
+	struct at_desc		*desc;
 	struct scatterlist	*sg;
 	void __iomem		*vaddr;
 	dma_addr_t		paddr;
 	size_t			total_len = 0;
 	int			i;
+	int			ret;
 
 	dev_vdbg(chan2dev(chan), "%s: v0x%x l0x%zx f0x%lx\n", __func__,
 		 value, sg_len, flags);
@@ -1443,6 +1178,11 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
 	}
 	*(u32*)vaddr = value;
 
+	desc = kzalloc(struct_size(desc, sg, sg_len), GFP_ATOMIC);
+	if (!desc)
+		goto err_free_dma_buf;
+	desc->sglen = sg_len;
+
 	for_each_sg(sgl, sg, sg_len, i) {
 		dma_addr_t dest = sg_dma_address(sg);
 		size_t len = sg_dma_len(sg);
@@ -1453,38 +1193,33 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
 		if (!is_dma_fill_aligned(chan->device, dest, 0, len)) {
 			dev_err(chan2dev(chan), "%s: buffer is not aligned\n",
 				__func__);
-			goto err_put_desc;
+			goto err_free_desc;
 		}
 
-		desc = atc_create_memset_desc(chan, paddr, dest, len);
-		if (!desc)
-			goto err_put_desc;
-
-		atc_desc_chain(&first, &prev, desc);
+		ret = atdma_create_memset_lli(chan, &desc->sg[i], paddr, dest,
+					      len);
+		if (ret)
+			goto err_free_desc;
 
+		atdma_lli_chain(desc, i);
 		total_len += len;
 	}
 
-	/*
-	 * Only set the buffer pointers on the last descriptor to
-	 * avoid free'ing while we have our transfer still going
-	 */
 	desc->memset_paddr = paddr;
 	desc->memset_vaddr = vaddr;
 	desc->memset_buffer = true;
 
-	first->txd.cookie = -EBUSY;
-	first->total_len = total_len;
+	desc->total_len = total_len;
 
 	/* set end-of-link on the descriptor */
-	set_desc_eol(desc);
-
-	first->txd.flags = flags;
+	set_lli_eol(desc, i - 1);
 
-	return &first->txd;
+	return vchan_tx_prep(&atchan->vc, &desc->vd, flags);
 
-err_put_desc:
-	atc_desc_put(atchan, first);
+err_free_desc:
+	atdma_desc_free(&desc->vd);
+err_free_dma_buf:
+	dma_pool_free(atdma->memset_pool, vaddr, paddr);
 	return NULL;
 }
 
@@ -1502,11 +1237,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
 		unsigned long flags, void *context)
 {
+	struct at_dma		*atdma = to_at_dma(chan->device);
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma_slave	*atslave = chan->private;
 	struct dma_slave_config	*sconfig = &atchan->dma_sconfig;
-	struct at_desc		*first = NULL;
-	struct at_desc		*prev = NULL;
+	struct at_desc		*desc;
 	u32			ctrla;
 	u32			ctrlb;
 	dma_addr_t		reg;
@@ -1526,6 +1261,11 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		return NULL;
 	}
 
+	desc = kzalloc(struct_size(desc, sg, sg_len), GFP_ATOMIC);
+	if (!desc)
+		return NULL;
+	desc->sglen = sg_len;
+
 	ctrla = FIELD_PREP(ATC_SCSIZE, sconfig->src_maxburst) |
 		FIELD_PREP(ATC_DCSIZE, sconfig->dst_maxburst);
 	ctrlb = ATC_IEN;
@@ -1542,13 +1282,17 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			 FIELD_PREP(ATC_DIF, atchan->per_if);
 		reg = sconfig->dst_addr;
 		for_each_sg(sgl, sg, sg_len, i) {
-			struct at_desc	*desc;
+			struct atdma_sg *atdma_sg = &desc->sg[i];
+			struct at_lli *lli;
 			u32		len;
 			u32		mem;
 
-			desc = atc_desc_get(atchan);
-			if (!desc)
+			atdma_sg->lli = dma_pool_alloc(atdma->lli_pool,
+						       GFP_NOWAIT,
+						       &atdma_sg->lli_phys);
+			if (!atdma_sg->lli)
 				goto err_desc_get;
+			lli = atdma_sg->lli;
 
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
@@ -1561,16 +1305,18 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			if (unlikely(mem & 3 || len & 3))
 				mem_width = 0;
 
-			desc->lli.saddr = mem;
-			desc->lli.daddr = reg;
-			desc->lli.ctrla = ctrla |
-					  FIELD_PREP(ATC_SRC_WIDTH, mem_width) |
-					  len >> mem_width;
-			desc->lli.ctrlb = ctrlb;
-			desc->len = len;
+			lli->saddr = mem;
+			lli->daddr = reg;
+			lli->ctrla = ctrla |
+				     FIELD_PREP(ATC_SRC_WIDTH, mem_width) |
+				     len >> mem_width;
+			lli->ctrlb = ctrlb;
 
-			atc_desc_chain(&first, &prev, desc);
+			atdma_sg->len = len;
 			total_len += len;
+
+			desc->sg[i].len = len;
+			atdma_lli_chain(desc, i);
 		}
 		break;
 	case DMA_DEV_TO_MEM:
@@ -1585,13 +1331,17 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
 		reg = sconfig->src_addr;
 		for_each_sg(sgl, sg, sg_len, i) {
-			struct at_desc	*desc;
+			struct atdma_sg *atdma_sg = &desc->sg[i];
+			struct at_lli *lli;
 			u32		len;
 			u32		mem;
 
-			desc = atc_desc_get(atchan);
-			if (!desc)
+			atdma_sg->lli = dma_pool_alloc(atdma->lli_pool,
+						       GFP_NOWAIT,
+						       &atdma_sg->lli_phys);
+			if (!atdma_sg->lli)
 				goto err_desc_get;
+			lli = atdma_sg->lli;
 
 			mem = sg_dma_address(sg);
 			len = sg_dma_len(sg);
@@ -1604,16 +1354,17 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 			if (unlikely(mem & 3 || len & 3))
 				mem_width = 0;
 
-			desc->lli.saddr = reg;
-			desc->lli.daddr = mem;
-			desc->lli.ctrla = ctrla |
-					  FIELD_PREP(ATC_DST_WIDTH, mem_width) |
-					  len >> reg_width;
-			desc->lli.ctrlb = ctrlb;
-			desc->len = len;
+			lli->saddr = reg;
+			lli->daddr = mem;
+			lli->ctrla = ctrla |
+				     FIELD_PREP(ATC_DST_WIDTH, mem_width) |
+				     len >> reg_width;
+			lli->ctrlb = ctrlb;
 
-			atc_desc_chain(&first, &prev, desc);
+			desc->sg[i].len = len;
 			total_len += len;
+
+			atdma_lli_chain(desc, i);
 		}
 		break;
 	default:
@@ -1621,21 +1372,16 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	}
 
 	/* set end-of-link to the last link descriptor of list*/
-	set_desc_eol(prev);
-
-	/* First descriptor of the chain embedds additional information */
-	first->txd.cookie = -EBUSY;
-	first->total_len = total_len;
+	set_lli_eol(desc, i - 1);
 
-	/* first link descriptor of list is responsible of flags */
-	first->txd.flags = flags; /* client is in control of this ack */
+	desc->total_len = total_len;
 
-	return &first->txd;
+	return vchan_tx_prep(&atchan->vc, &desc->vd, flags);
 
 err_desc_get:
 	dev_err(chan2dev(chan), "not enough descriptors available\n");
 err:
-	atc_desc_put(atchan, first);
+	atdma_desc_free(&desc->vd);
 	return NULL;
 }
 
@@ -1665,54 +1411,59 @@ atc_dma_cyclic_check_values(unsigned int reg_width, dma_addr_t buf_addr,
  */
 static int
 atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
-		unsigned int period_index, dma_addr_t buf_addr,
+		unsigned int i, dma_addr_t buf_addr,
 		unsigned int reg_width, size_t period_len,
 		enum dma_transfer_direction direction)
 {
+	struct at_dma		*atdma = to_at_dma(chan->device);
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct dma_slave_config	*sconfig = &atchan->dma_sconfig;
-	u32			ctrla;
+	struct atdma_sg		*atdma_sg = &desc->sg[i];
+	struct at_lli		*lli;
 
-	/* prepare common CRTLA value */
-	ctrla = FIELD_PREP(ATC_SCSIZE, sconfig->src_maxburst) |
-		FIELD_PREP(ATC_DCSIZE, sconfig->dst_maxburst) |
-		FIELD_PREP(ATC_DST_WIDTH, reg_width) |
-		FIELD_PREP(ATC_SRC_WIDTH, reg_width) |
-		period_len >> reg_width;
+	atdma_sg->lli = dma_pool_alloc(atdma->lli_pool, GFP_ATOMIC,
+				       &atdma_sg->lli_phys);
+	if (!atdma_sg->lli)
+		return -ENOMEM;
+	lli = atdma_sg->lli;
 
 	switch (direction) {
 	case DMA_MEM_TO_DEV:
-		desc->lli.saddr = buf_addr + (period_len * period_index);
-		desc->lli.daddr = sconfig->dst_addr;
-		desc->lli.ctrla = ctrla;
-		desc->lli.ctrlb = FIELD_PREP(ATC_DST_ADDR_MODE,
-					     ATC_DST_ADDR_MODE_FIXED) |
-				  FIELD_PREP(ATC_SRC_ADDR_MODE,
-					     ATC_SRC_ADDR_MODE_INCR) |
-				  FIELD_PREP(ATC_FC, ATC_FC_MEM2PER) |
-				  FIELD_PREP(ATC_SIF, atchan->mem_if) |
-				  FIELD_PREP(ATC_DIF, atchan->per_if);
-		desc->len = period_len;
+		lli->saddr = buf_addr + (period_len * i);
+		lli->daddr = sconfig->dst_addr;
+		lli->ctrlb = FIELD_PREP(ATC_DST_ADDR_MODE,
+					ATC_DST_ADDR_MODE_FIXED) |
+			     FIELD_PREP(ATC_SRC_ADDR_MODE,
+					ATC_SRC_ADDR_MODE_INCR) |
+			     FIELD_PREP(ATC_FC, ATC_FC_MEM2PER) |
+			     FIELD_PREP(ATC_SIF, atchan->mem_if) |
+			     FIELD_PREP(ATC_DIF, atchan->per_if);
+
 		break;
 
 	case DMA_DEV_TO_MEM:
-		desc->lli.saddr = sconfig->src_addr;
-		desc->lli.daddr = buf_addr + (period_len * period_index);
-		desc->lli.ctrla = ctrla;
-		desc->lli.ctrlb = FIELD_PREP(ATC_DST_ADDR_MODE,
-					     ATC_DST_ADDR_MODE_INCR) |
-				  FIELD_PREP(ATC_SRC_ADDR_MODE,
-					     ATC_SRC_ADDR_MODE_FIXED) |
-				  FIELD_PREP(ATC_FC, ATC_FC_PER2MEM) |
-				  FIELD_PREP(ATC_SIF, atchan->per_if) |
-				  FIELD_PREP(ATC_DIF, atchan->mem_if);
-		desc->len = period_len;
+		lli->saddr = sconfig->src_addr;
+		lli->daddr = buf_addr + (period_len * i);
+		lli->ctrlb = FIELD_PREP(ATC_DST_ADDR_MODE,
+					ATC_DST_ADDR_MODE_INCR) |
+			     FIELD_PREP(ATC_SRC_ADDR_MODE,
+					ATC_SRC_ADDR_MODE_FIXED) |
+			     FIELD_PREP(ATC_FC, ATC_FC_PER2MEM) |
+			     FIELD_PREP(ATC_SIF, atchan->per_if) |
+			     FIELD_PREP(ATC_DIF, atchan->mem_if);
 		break;
 
 	default:
 		return -EINVAL;
 	}
 
+	lli->ctrla = FIELD_PREP(ATC_SCSIZE, sconfig->src_maxburst) |
+		     FIELD_PREP(ATC_DCSIZE, sconfig->dst_maxburst) |
+		     FIELD_PREP(ATC_DST_WIDTH, reg_width) |
+		     FIELD_PREP(ATC_SRC_WIDTH, reg_width) |
+		     period_len >> reg_width;
+	desc->sg[i].len = period_len;
+
 	return 0;
 }
 
@@ -1733,8 +1484,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma_slave	*atslave = chan->private;
 	struct dma_slave_config	*sconfig = &atchan->dma_sconfig;
-	struct at_desc		*first = NULL;
-	struct at_desc		*prev = NULL;
+	struct at_desc		*desc;
 	unsigned long		was_cyclic;
 	unsigned int		reg_width;
 	unsigned int		periods = buf_len / period_len;
@@ -1768,33 +1518,26 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 	if (atc_dma_cyclic_check_values(reg_width, buf_addr, period_len))
 		goto err_out;
 
+	desc = kzalloc(struct_size(desc, sg, periods), GFP_ATOMIC);
+	if (!desc)
+		goto err_out;
+	desc->sglen = periods;
+
 	/* build cyclic linked list */
 	for (i = 0; i < periods; i++) {
-		struct at_desc	*desc;
-
-		desc = atc_desc_get(atchan);
-		if (!desc)
-			goto err_desc_get;
-
 		if (atc_dma_cyclic_fill_desc(chan, desc, i, buf_addr,
 					     reg_width, period_len, direction))
-			goto err_desc_get;
-
-		atc_desc_chain(&first, &prev, desc);
+			goto err_fill_desc;
+		atdma_lli_chain(desc, i);
 	}
-
+	desc->total_len = buf_len;
 	/* lets make a cyclic list */
-	prev->lli.dscr = first->txd.phys;
-
-	/* First descriptor of the chain embedds additional information */
-	first->txd.cookie = -EBUSY;
-	first->total_len = buf_len;
+	desc->sg[i - 1].lli->dscr = desc->sg[0].lli_phys;
 
-	return &first->txd;
+	return vchan_tx_prep(&atchan->vc, &desc->vd, flags);
 
-err_desc_get:
-	dev_err(chan2dev(chan), "not enough descriptors available\n");
-	atc_desc_put(atchan, first);
+err_fill_desc:
+	atdma_desc_free(&desc->vd);
 err_out:
 	clear_bit(ATC_IS_CYCLIC, &atchan->status);
 	return NULL;
@@ -1823,17 +1566,17 @@ static int atc_pause(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	int			chan_id = atchan->dma_chan.chan_id;
+	int			chan_id = atchan->vc.chan.chan_id;
 	unsigned long		flags;
 
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
 
-	spin_lock_irqsave(&atchan->lock, flags);
+	spin_lock_irqsave(&atchan->vc.lock, flags);
 
 	dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
 	set_bit(ATC_IS_PAUSED, &atchan->status);
 
-	spin_unlock_irqrestore(&atchan->lock, flags);
+	spin_unlock_irqrestore(&atchan->vc.lock, flags);
 
 	return 0;
 }
@@ -1842,7 +1585,7 @@ static int atc_resume(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	int			chan_id = atchan->dma_chan.chan_id;
+	int			chan_id = atchan->vc.chan.chan_id;
 	unsigned long		flags;
 
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
@@ -1850,12 +1593,12 @@ static int atc_resume(struct dma_chan *chan)
 	if (!atc_chan_is_paused(atchan))
 		return 0;
 
-	spin_lock_irqsave(&atchan->lock, flags);
+	spin_lock_irqsave(&atchan->vc.lock, flags);
 
 	dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
 	clear_bit(ATC_IS_PAUSED, &atchan->status);
 
-	spin_unlock_irqrestore(&atchan->lock, flags);
+	spin_unlock_irqrestore(&atchan->vc.lock, flags);
 
 	return 0;
 }
@@ -1864,9 +1607,11 @@ static int atc_terminate_all(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	int			chan_id = atchan->dma_chan.chan_id;
+	int			chan_id = atchan->vc.chan.chan_id;
 	unsigned long		flags;
 
+	LIST_HEAD(list);
+
 	dev_vdbg(chan2dev(chan), "%s\n", __func__);
 
 	/*
@@ -1875,7 +1620,7 @@ static int atc_terminate_all(struct dma_chan *chan)
 	 * channel. We still have to poll the channel enable bit due
 	 * to AHB/HSB limitations.
 	 */
-	spin_lock_irqsave(&atchan->lock, flags);
+	spin_lock_irqsave(&atchan->vc.lock, flags);
 
 	/* disabling channel: must also remove suspend state */
 	dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
@@ -1884,15 +1629,20 @@ static int atc_terminate_all(struct dma_chan *chan)
 	while (dma_readl(atdma, CHSR) & atchan->mask)
 		cpu_relax();
 
-	/* active_list entries will end up before queued entries */
-	list_splice_tail_init(&atchan->queue, &atchan->free_list);
-	list_splice_tail_init(&atchan->active_list, &atchan->free_list);
+	if (atchan->desc) {
+		vchan_terminate_vdesc(&atchan->desc->vd);
+		atchan->desc = NULL;
+	}
+
+	vchan_get_all_descriptors(&atchan->vc, &list);
 
 	clear_bit(ATC_IS_PAUSED, &atchan->status);
 	/* if channel dedicated to cyclic operations, free it */
 	clear_bit(ATC_IS_CYCLIC, &atchan->status);
 
-	spin_unlock_irqrestore(&atchan->lock, flags);
+	spin_unlock_irqrestore(&atchan->vc.lock, flags);
+
+	vchan_dma_desc_free_list(&atchan->vc, &list);
 
 	return 0;
 }
@@ -1922,9 +1672,10 @@ atc_tx_status(struct dma_chan *chan,
 	if (dma_status == DMA_COMPLETE || !txstate)
 		return dma_status;
 
-	spin_lock_irqsave(&atchan->lock, flags);
+	spin_lock_irqsave(&atchan->vc.lock, flags);
+	/*  Get number of bytes left in the active transactions */
 	ret = atc_get_residue(chan, cookie, &residue);
-	spin_unlock_irqrestore(&atchan->lock, flags);
+	spin_unlock_irqrestore(&atchan->vc.lock, flags);
 
 	if (unlikely(ret < 0)) {
 		dev_vdbg(chan2dev(chan), "get residual bytes error\n");
@@ -1939,27 +1690,17 @@ atc_tx_status(struct dma_chan *chan,
 	return dma_status;
 }
 
-/**
- * atc_issue_pending - takes the first transaction descriptor in the pending
- * queue and starts the transfer.
- * @chan: target DMA channel
- */
 static void atc_issue_pending(struct dma_chan *chan)
 {
 	struct at_dma_chan *atchan = to_at_dma_chan(chan);
-	struct at_desc *desc;
 	unsigned long flags;
 
-	dev_vdbg(chan2dev(chan), "issue_pending\n");
-
-	spin_lock_irqsave(&atchan->lock, flags);
-	if (atc_chan_is_enabled(atchan) || list_empty(&atchan->queue))
-		return spin_unlock_irqrestore(&atchan->lock, flags);
-
-	desc = atc_first_queued(atchan);
-	list_move_tail(&desc->desc_node, &atchan->active_list);
-	atc_dostart(atchan, desc);
-	spin_unlock_irqrestore(&atchan->lock, flags);
+	spin_lock_irqsave(&atchan->vc.lock, flags);
+	if (vchan_issue_pending(&atchan->vc) && !atchan->desc) {
+		if (!(atc_chan_is_enabled(atchan)))
+			atc_dostart(atchan);
+	}
+	spin_unlock_irqrestore(&atchan->vc.lock, flags);
 }
 
 /**
@@ -1972,9 +1713,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
 	struct at_dma		*atdma = to_at_dma(chan->device);
-	struct at_desc		*desc;
 	struct at_dma_slave	*atslave;
-	int			i;
 	u32			cfg;
 
 	dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
@@ -1985,11 +1724,6 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 		return -EIO;
 	}
 
-	if (!list_empty(&atchan->free_list)) {
-		dev_dbg(chan2dev(chan), "can't allocate channel resources (channel not freed from a previous use)\n");
-		return -EIO;
-	}
-
 	cfg = ATC_DEFAULT_CFG;
 
 	atslave = chan->private;
@@ -2005,26 +1739,10 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 			cfg = atslave->cfg;
 	}
 
-	/* Allocate initial pool of descriptors */
-	for (i = 0; i < init_nr_desc_per_channel; i++) {
-		desc = atc_alloc_descriptor(chan, GFP_KERNEL);
-		if (!desc) {
-			dev_err(atdma->dma_device.dev,
-				"Only %d initial descriptors\n", i);
-			break;
-		}
-		list_add_tail(&desc->desc_node, &atchan->free_list);
-	}
-
-	dma_cookie_init(chan);
-
 	/* channel parameters */
 	channel_writel(atchan, CFG, cfg);
 
-	dev_dbg(chan2dev(chan),
-		"alloc_chan_resources: allocated %d descriptors\n", i);
-
-	return i;
+	return 0;
 }
 
 /**
@@ -2034,22 +1752,10 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
 static void atc_free_chan_resources(struct dma_chan *chan)
 {
 	struct at_dma_chan	*atchan = to_at_dma_chan(chan);
-	struct at_dma		*atdma = to_at_dma(chan->device);
-	struct at_desc		*desc, *_desc;
-	LIST_HEAD(list);
 
-	/* ASSERT:  channel is idle */
-	BUG_ON(!list_empty(&atchan->active_list));
-	BUG_ON(!list_empty(&atchan->queue));
 	BUG_ON(atc_chan_is_enabled(atchan));
 
-	list_for_each_entry_safe(desc, _desc, &atchan->free_list, desc_node) {
-		dev_vdbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
-		list_del(&desc->desc_node);
-		/* free link descriptor */
-		dma_pool_free(atdma->dma_desc_pool, desc, desc->txd.phys);
-	}
-	list_splice_init(&atchan->free_list, &list);
+	vchan_free_chan_resources(to_virt_chan(chan));
 	atchan->status = 0;
 
 	/*
@@ -2274,11 +1980,11 @@ static int __init at_dma_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, atdma);
 
 	/* create a pool of consistent memory blocks for hardware descriptors */
-	atdma->dma_desc_pool = dma_pool_create("at_hdmac_desc_pool",
-			&pdev->dev, sizeof(struct at_desc),
-			4 /* word alignment */, 0);
-	if (!atdma->dma_desc_pool) {
-		dev_err(&pdev->dev, "No memory for descriptors dma pool\n");
+	atdma->lli_pool = dma_pool_create("at_hdmac_lli_pool",
+					  &pdev->dev, sizeof(struct at_lli),
+					  4 /* word alignment */, 0);
+	if (!atdma->lli_pool) {
+		dev_err(&pdev->dev, "Unable to allocate DMA LLI descriptor pool\n");
 		err = -ENOMEM;
 		goto err_desc_pool_create;
 	}
@@ -2303,20 +2009,13 @@ static int __init at_dma_probe(struct platform_device *pdev)
 
 		atchan->mem_if = AT_DMA_MEM_IF;
 		atchan->per_if = AT_DMA_PER_IF;
-		atchan->dma_chan.device = &atdma->dma_device;
-		dma_cookie_init(&atchan->dma_chan);
-		list_add_tail(&atchan->dma_chan.device_node,
-				&atdma->dma_device.channels);
 
 		atchan->ch_regs = atdma->regs + ch_regs(i);
-		spin_lock_init(&atchan->lock);
 		atchan->mask = 1 << i;
 
-		INIT_LIST_HEAD(&atchan->active_list);
-		INIT_LIST_HEAD(&atchan->queue);
-		INIT_LIST_HEAD(&atchan->free_list);
-
-		tasklet_setup(&atchan->tasklet, atc_tasklet);
+		atchan->atdma = atdma;
+		atchan->vc.desc_free = atdma_desc_free;
+		vchan_init(&atchan->vc, &atdma->dma_device);
 		atc_enable_chan_irq(atdma, i);
 	}
 
@@ -2390,7 +2089,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
 err_dma_async_device_register:
 	dma_pool_destroy(atdma->memset_pool);
 err_memset_pool_create:
-	dma_pool_destroy(atdma->dma_desc_pool);
+	dma_pool_destroy(atdma->lli_pool);
 err_desc_pool_create:
 	free_irq(platform_get_irq(pdev, 0), atdma);
 err_irq:
@@ -2409,17 +2108,13 @@ static int at_dma_remove(struct platform_device *pdev)
 	dma_async_device_unregister(&atdma->dma_device);
 
 	dma_pool_destroy(atdma->memset_pool);
-	dma_pool_destroy(atdma->dma_desc_pool);
+	dma_pool_destroy(atdma->lli_pool);
 	free_irq(platform_get_irq(pdev, 0), atdma);
 
 	list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
 			device_node) {
-		struct at_dma_chan	*atchan = to_at_dma_chan(chan);
-
 		/* Disable interrupts */
 		atc_disable_chan_irq(atdma, chan->chan_id);
-
-		tasklet_kill(&atchan->tasklet);
 		list_del(&chan->device_node);
 	}
 
@@ -2453,7 +2148,7 @@ static int at_dma_prepare(struct device *dev)
 
 static void atc_suspend_cyclic(struct at_dma_chan *atchan)
 {
-	struct dma_chan	*chan = &atchan->dma_chan;
+	struct dma_chan	*chan = &atchan->vc.chan;
 
 	/* Channel should be paused by user
 	 * do it anyway even if it is not done already */
@@ -2494,7 +2189,7 @@ static int at_dma_suspend_noirq(struct device *dev)
 
 static void atc_resume_cyclic(struct at_dma_chan *atchan)
 {
-	struct at_dma	*atdma = to_at_dma(atchan->dma_chan.device);
+	struct at_dma	*atdma = to_at_dma(atchan->vc.chan.device);
 
 	/* restore channel status for cyclic descriptors list:
 	 * next descriptor in the cyclic list at the time of suspend */
@@ -2568,5 +2263,6 @@ module_exit(at_dma_exit);
 
 MODULE_DESCRIPTION("Atmel AHB DMA Controller driver");
 MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
+MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:at_hdmac");
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (31 preceding siblings ...)
  2022-10-25  9:03 ` [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma Tudor Ambarus
@ 2022-10-25  9:06 ` Tudor.Ambarus
  2022-10-28 13:00 ` Nicolas Ferre
  2022-11-04 13:22 ` Vinod Koul
  34 siblings, 0 replies; 42+ messages in thread
From: Tudor.Ambarus @ 2022-10-25  9:06 UTC (permalink / raw)
  To: vkoul, peda, du
  Cc: Nicolas.Ferre, mripard, torfl6749, linux-kernel, dmaengine,
	linux-arm-kernel

Hi, Peter,

Can I have your tested-by tag on this patch set please?

Thanks,
ta

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma
  2022-10-25  9:03 ` [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma Tudor Ambarus
@ 2022-10-28 12:55   ` Nicolas Ferre
  0 siblings, 0 replies; 42+ messages in thread
From: Nicolas Ferre @ 2022-10-28 12:55 UTC (permalink / raw)
  To: Tudor Ambarus, vkoul, peda, du
  Cc: maciej.sosnowski, mripard, torfl6749, linux-kernel, dmaengine,
	linux-arm-kernel

On 25/10/2022 at 11:03, Tudor Ambarus wrote:
> Convert the driver to use the core virt-dma. The driver will be easier to
> maintain as it uses the list handling and the tasklet from virt-dma.
> 
> With the conversion replace the election of a new transfer in the tasklet
> with the election of the new transfer in the interrupt handler. With this
> we have a shorter idle window as we remove the scheduling latency of the
> tasklet. I chose to do this while doing the conversion to virt-dma,
> because if I made a prerequisite patch with the new transfer election in
> the irq handler, I would have to duplicate some virt-dma code in the
> at_hdmac driver that would end up being removed at the virt-dma conversion
> anyway. So do this in a single step.
> 
> Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com>

Even if it's difficult to review, I support the transition:
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>

Thanks Tudor, regards,
   Nicolas

[..]

-- 
Nicolas Ferre


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (32 preceding siblings ...)
  2022-10-25  9:06 ` [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor.Ambarus
@ 2022-10-28 13:00 ` Nicolas Ferre
  2022-11-04 13:22 ` Vinod Koul
  34 siblings, 0 replies; 42+ messages in thread
From: Nicolas Ferre @ 2022-10-28 13:00 UTC (permalink / raw)
  To: Tudor Ambarus, vkoul, peda, du
  Cc: maciej.sosnowski, mripard, torfl6749, linux-kernel, dmaengine,
	linux-arm-kernel

On 25/10/2022 at 11:02, Tudor Ambarus wrote:
> v2:
> - reorder patches so that fixes come first -> easier to backport to
> stable kernels.
> - drop the devm_request_irq() patch as we had to disable the irq anyway
> in remove() in order to avoid spurios IRQs. Using devm variant brings no
> palpable benefit.
> - reword pm_ptr commit message
> 
> 
> at_hdmac driver had poor list handling and concurrency bugs.
> We experienced calling of the completion call twice for the
> same descriptor. Peter Rosin encountered the same while
> reporting a different bug:
> https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
> 
> Two sets of tests were performed:
> 1/ tested just the fixes, to make sure everything is fine and the
> concurrency bugs are squashed even without the conversion to virt-dma.
> All went fine.
> 2/ tested the entire series including the conversion the virt-dma
> All went fine.
> 
> I tested NAND (prep_dma_memcpy), MMC (prep_dma_slave_sg),
> usart (cyclic mode), dmatest (memcpy, memset).

All these tests are reassuring.

The important piece to preserve is the computation of the residue as it 
went with lots of experiments in both silicon and simulation with the IP 
designer. The errors were very difficult to reproduce.
As this part seems well understood and maintained it its good 
conditions, I can give my Ack to the series.
So, for the whole series, after a quick-but-not-too-quick review:
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>

Thanks for this effort Tudor. Best regards,
   Nicolas

> With the conversion to virt-dma I replaced the election of a new transfer
> in the tasklet with the election of the new transfer in the interrupt
> handler. We should have a shorter idle window as we remove the scheduling
> latency of the tasklet. Using mtd_speedtest showed similar performances
> when using NAND with DMA. That could be because of using a low timming
> mode on NAND.
> 
> 
> Tudor Ambarus (32):
>    dmaengine: at_hdmac: Fix at_lli struct definition
>    dmaengine: at_hdmac: Don't start transactions at tx_submit level
>    dmaengine: at_hdmac: Start transfer for cyclic channels in
>      issue_pending
>    dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
>    dmaengine: at_hdmac: Do not call the complete callback on
>      device_terminate_all
>    dmaengine: at_hdmac: Protect atchan->status with the channel lock
>    dmaengine: at_hdmac: Fix concurrency problems by removing
>      atc_complete_all()
>    dmaengine: at_hdmac: Fix concurrency over descriptor
>    dmaengine: at_hdmac: Free the memset buf without holding the chan lock
>    dmaengine: at_hdmac: Fix concurrency over the active list
>    dmaengine: at_hdmac: Fix descriptor handling when issuing it to
>      hardware
>    dmaengine: at_hdmac: Fix completion of unissued descriptor in case of
>      errors
>    dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
>    dmaengine: at_hdmac: Fix impossible condition
>    dmaengine: at_hdmac: Check return code of dma_async_device_register
>    dmaengine: at_hdmac: Do not print messages on console while holding
>      the lock
>    dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when
>      txstate is NULL
>    dmaengine: at_hdmac: Remove superfluous cast
>    dmaengine: at_hdmac: Pass residue by address to avoid unnecessary
>      implicit casts
>    dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
>    dmaengine: at_hdmac: Introduce atc_get_llis_residue()
>    dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
>    dmaengine: at_hdmac: Use devm_platform_ioremap_resource
>    dmaengine: at_hdmac: Use devm_clk_get()
>    dmaengine: at_hdmac: Use pm_ptr()
>    dmaengine: at_hdmac: Set include entries in alphabetic order
>    dmaengine: at_hdmac: Keep register definitions and structures private
>      to at_hdmac.c
>    dmaengine: at_hdmac: Use bitfield access macros
>    dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
>    dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
>    dmaengine: at_hdmac: Remove unused member of at_dma_chan
>    dmaengine: at_hdmac: Convert driver to use virt-dma
> 
>   MAINTAINERS                 |    1 -
>   drivers/dma/Kconfig         |    1 +
>   drivers/dma/at_hdmac.c      | 1899 ++++++++++++++++++-----------------
>   drivers/dma/at_hdmac_regs.h |  478 ---------
>   4 files changed, 990 insertions(+), 1389 deletions(-)
>   delete mode 100644 drivers/dma/at_hdmac_regs.h
> 

-- 
Nicolas Ferre


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
                   ` (33 preceding siblings ...)
  2022-10-28 13:00 ` Nicolas Ferre
@ 2022-11-04 13:22 ` Vinod Koul
  2022-11-04 15:14   ` Tudor.Ambarus
  34 siblings, 1 reply; 42+ messages in thread
From: Vinod Koul @ 2022-11-04 13:22 UTC (permalink / raw)
  To: Tudor Ambarus
  Cc: peda, du, maciej.sosnowski, nicolas.ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel

On 25-10-22, 12:02, Tudor Ambarus wrote:
> v2:
> - reorder patches so that fixes come first -> easier to backport to
> stable kernels.
> - drop the devm_request_irq() patch as we had to disable the irq anyway
> in remove() in order to avoid spurios IRQs. Using devm variant brings no
> palpable benefit.
> - reword pm_ptr commit message
> 
> 
> at_hdmac driver had poor list handling and concurrency bugs.
> We experienced calling of the completion call twice for the
> same descriptor. Peter Rosin encountered the same while
> reporting a different bug:
> https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
> 
> Two sets of tests were performed:
> 1/ tested just the fixes, to make sure everything is fine and the
> concurrency bugs are squashed even without the conversion to virt-dma.
> All went fine.
> 2/ tested the entire series including the conversion the virt-dma
> All went fine.
> 
> I tested NAND (prep_dma_memcpy), MMC (prep_dma_slave_sg),
> usart (cyclic mode), dmatest (memcpy, memset).
> With the conversion to virt-dma I replaced the election of a new transfer
> in the tasklet with the election of the new transfer in the interrupt
> handler. We should have a shorter idle window as we remove the scheduling
> latency of the tasklet. Using mtd_speedtest showed similar performances
> when using NAND with DMA. That could be because of using a low timming
> mode on NAND.

This does not apply on dmaengine-fixes, can you please rebase and resend

-- 
~Vinod

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-11-04 13:22 ` Vinod Koul
@ 2022-11-04 15:14   ` Tudor.Ambarus
  2022-11-04 15:21     ` Tudor.Ambarus
  0 siblings, 1 reply; 42+ messages in thread
From: Tudor.Ambarus @ 2022-11-04 15:14 UTC (permalink / raw)
  To: vkoul
  Cc: peda, du, maciej.sosnowski, Nicolas.Ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel

On 11/4/22 15:22, Vinod Koul wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 25-10-22, 12:02, Tudor Ambarus wrote:
>> v2:
>> - reorder patches so that fixes come first -> easier to backport to
>> stable kernels.
>> - drop the devm_request_irq() patch as we had to disable the irq anyway
>> in remove() in order to avoid spurios IRQs. Using devm variant brings no
>> palpable benefit.
>> - reword pm_ptr commit message
>>
>>
>> at_hdmac driver had poor list handling and concurrency bugs.
>> We experienced calling of the completion call twice for the
>> same descriptor. Peter Rosin encountered the same while
>> reporting a different bug:
>> https://lore.kernel.org/lkml/13c6c9a2-6db5-c3bf-349b-4c127ad3496a@axentia.se/
>>
>> Two sets of tests were performed:
>> 1/ tested just the fixes, to make sure everything is fine and the
>> concurrency bugs are squashed even without the conversion to virt-dma.
>> All went fine.
>> 2/ tested the entire series including the conversion the virt-dma
>> All went fine.
>>
>> I tested NAND (prep_dma_memcpy), MMC (prep_dma_slave_sg),
>> usart (cyclic mode), dmatest (memcpy, memset).
>> With the conversion to virt-dma I replaced the election of a new transfer
>> in the tasklet with the election of the new transfer in the interrupt
>> handler. We should have a shorter idle window as we remove the scheduling
>> latency of the tasklet. Using mtd_speedtest showed similar performances
>> when using NAND with DMA. That could be because of using a low timming
>> mode on NAND.
> 
> This does not apply on dmaengine-fixes, can you please rebase and resend
> 

Sure, I can, but on my side it applies just fine, both on the fixes and next
branches. I used git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git
Shall I use other tree?

Thanks,
ta

$  git am ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.mbx
Applying: dmaengine: at_hdmac: Fix at_lli struct definition
Applying: dmaengine: at_hdmac: Don't start transactions at tx_submit level
Applying: dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
Applying: dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
Applying: dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
Applying: dmaengine: at_hdmac: Protect atchan->status with the channel lock
Applying: dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
Applying: dmaengine: at_hdmac: Fix concurrency over descriptor
Applying: dmaengine: at_hdmac: Free the memset buf without holding the chan lock
Applying: dmaengine: at_hdmac: Fix concurrency over the active list
Applying: dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
Applying: dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
Applying: dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
Applying: dmaengine: at_hdmac: Fix impossible condition
Applying: dmaengine: at_hdmac: Check return code of dma_async_device_register
Applying: dmaengine: at_hdmac: Do not print messages on console while holding the lock
Applying: dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
Applying: dmaengine: at_hdmac: Remove superfluous cast
Applying: dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
Applying: dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
Applying: dmaengine: at_hdmac: Introduce atc_get_llis_residue()
Applying: dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
Applying: dmaengine: at_hdmac: Use devm_platform_ioremap_resource
Applying: dmaengine: at_hdmac: Use devm_clk_get()
Applying: dmaengine: at_hdmac: Use pm_ptr()
Applying: dmaengine: at_hdmac: Set include entries in alphabetic order
Applying: dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
Applying: dmaengine: at_hdmac: Use bitfield access macros
Applying: dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
Applying: dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
Applying: dmaengine: at_hdmac: Remove unused member of at_dma_chan
Applying: dmaengine: at_hdmac: Convert driver to use virt-dma
b4 am 20221025090306.297886-1-tudor.ambarus@microchip.com
Looking up https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus%40microchip.com
Analyzing 37 messages in the thread
Checking attestation on all messages, may take a moment...
---
  [PATCH v2 1/32] dmaengine: at_hdmac: Fix at_lli struct definition
  [PATCH v2 2/32] dmaengine: at_hdmac: Don't start transactions at tx_submit level
  [PATCH v2 3/32] dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
  [PATCH v2 4/32] dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
  [PATCH v2 5/32] dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
  [PATCH v2 6/32] dmaengine: at_hdmac: Protect atchan->status with the channel lock
  [PATCH v2 7/32] dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
  [PATCH v2 8/32] dmaengine: at_hdmac: Fix concurrency over descriptor
  [PATCH v2 9/32] dmaengine: at_hdmac: Free the memset buf without holding the chan lock
  [PATCH v2 10/32] dmaengine: at_hdmac: Fix concurrency over the active list
  [PATCH v2 11/32] dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
  [PATCH v2 12/32] dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
  [PATCH v2 13/32] dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
  [PATCH v2 14/32] dmaengine: at_hdmac: Fix impossible condition
  [PATCH v2 15/32] dmaengine: at_hdmac: Check return code of dma_async_device_register
  [PATCH v2 16/32] dmaengine: at_hdmac: Do not print messages on console while holding the lock
  [PATCH v2 17/32] dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
  [PATCH v2 18/32] dmaengine: at_hdmac: Remove superfluous cast
  [PATCH v2 19/32] dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
  [PATCH v2 20/32] dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
  [PATCH v2 21/32] dmaengine: at_hdmac: Introduce atc_get_llis_residue()
  [PATCH v2 22/32] dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
  [PATCH v2 23/32] dmaengine: at_hdmac: Use devm_platform_ioremap_resource
  [PATCH v2 24/32] dmaengine: at_hdmac: Use devm_clk_get()
  [PATCH v2 25/32] dmaengine: at_hdmac: Use pm_ptr()
  [PATCH v2 26/32] dmaengine: at_hdmac: Set include entries in alphabetic order
  [PATCH v2 27/32] dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
  [PATCH v2 28/32] dmaengine: at_hdmac: Use bitfield access macros
  [PATCH v2 29/32] dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
  [PATCH v2 30/32] dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
  [PATCH v2 31/32] dmaengine: at_hdmac: Remove unused member of at_dma_chan
  [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma
    + Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
---
Total patches: 32
---
NOTE: Some trailers were sent to the cover letter:
      Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
NOTE: Rerun with -t to apply them to all patches
---
Cover: ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.cover
 Link: https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus@microchip.com
 Base: not specified
       git am ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.mbx

$ git log --oneline
79029dc341c7 (HEAD, vkoul-dma/fixes) dmaengine: stm32-dma: fix potential race between pause and resume



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-11-04 15:14   ` Tudor.Ambarus
@ 2022-11-04 15:21     ` Tudor.Ambarus
  2022-11-04 17:59       ` Vinod Koul
  0 siblings, 1 reply; 42+ messages in thread
From: Tudor.Ambarus @ 2022-11-04 15:21 UTC (permalink / raw)
  To: vkoul
  Cc: peda, du, maciej.sosnowski, Nicolas.Ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel


>>
>> This does not apply on dmaengine-fixes, can you please rebase and resend
>>
> 
> Sure, I can, but on my side it applies just fine, both on the fixes and next
> branches. I used git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git
> Shall I use other tree?

$ git log --oneline
79029dc341c7 (HEAD, vkoul-dma/fixes) dmaengine: stm32-dma: fix potential race between pause and resume

[cut]

$ b4 am 20221025090306.297886-1-tudor.ambarus@microchip.com
Looking up https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus%40microchip.com
Grabbing thread from lore.kernel.org/all/20221025090306.297886-1-tudor.ambarus%40microchip.com/t.mbox.gz
Analyzing 37 messages in the thread
Checking attestation on all messages, may take a moment...
---
  [PATCH v2 1/32] dmaengine: at_hdmac: Fix at_lli struct definition
  [PATCH v2 2/32] dmaengine: at_hdmac: Don't start transactions at tx_submit level
  [PATCH v2 3/32] dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
  [PATCH v2 4/32] dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
  [PATCH v2 5/32] dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
  [PATCH v2 6/32] dmaengine: at_hdmac: Protect atchan->status with the channel lock
  [PATCH v2 7/32] dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
  [PATCH v2 8/32] dmaengine: at_hdmac: Fix concurrency over descriptor
  [PATCH v2 9/32] dmaengine: at_hdmac: Free the memset buf without holding the chan lock
  [PATCH v2 10/32] dmaengine: at_hdmac: Fix concurrency over the active list
  [PATCH v2 11/32] dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
  [PATCH v2 12/32] dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
  [PATCH v2 13/32] dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
  [PATCH v2 14/32] dmaengine: at_hdmac: Fix impossible condition
  [PATCH v2 15/32] dmaengine: at_hdmac: Check return code of dma_async_device_register
  [PATCH v2 16/32] dmaengine: at_hdmac: Do not print messages on console while holding the lock
  [PATCH v2 17/32] dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
  [PATCH v2 18/32] dmaengine: at_hdmac: Remove superfluous cast
  [PATCH v2 19/32] dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
  [PATCH v2 20/32] dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
  [PATCH v2 21/32] dmaengine: at_hdmac: Introduce atc_get_llis_residue()
  [PATCH v2 22/32] dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
  [PATCH v2 23/32] dmaengine: at_hdmac: Use devm_platform_ioremap_resource
  [PATCH v2 24/32] dmaengine: at_hdmac: Use devm_clk_get()
  [PATCH v2 25/32] dmaengine: at_hdmac: Use pm_ptr()
  [PATCH v2 26/32] dmaengine: at_hdmac: Set include entries in alphabetic order
  [PATCH v2 27/32] dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
  [PATCH v2 28/32] dmaengine: at_hdmac: Use bitfield access macros
  [PATCH v2 29/32] dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
  [PATCH v2 30/32] dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
  [PATCH v2 31/32] dmaengine: at_hdmac: Remove unused member of at_dma_chan
  [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma
    + Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
---
Total patches: 32
---
NOTE: Some trailers were sent to the cover letter:
      Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
NOTE: Rerun with -t to apply them to all patches
---
Cover: ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.cover
 Link: https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus@microchip.com
 Base: not specified
       git am ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.mbx

$ git am ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.mbx
Applying: dmaengine: at_hdmac: Fix at_lli struct definition
Applying: dmaengine: at_hdmac: Don't start transactions at tx_submit level
Applying: dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
Applying: dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
Applying: dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
Applying: dmaengine: at_hdmac: Protect atchan->status with the channel lock
Applying: dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
Applying: dmaengine: at_hdmac: Fix concurrency over descriptor
Applying: dmaengine: at_hdmac: Free the memset buf without holding the chan lock
Applying: dmaengine: at_hdmac: Fix concurrency over the active list
Applying: dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
Applying: dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
Applying: dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
Applying: dmaengine: at_hdmac: Fix impossible condition
Applying: dmaengine: at_hdmac: Check return code of dma_async_device_register
Applying: dmaengine: at_hdmac: Do not print messages on console while holding the lock
Applying: dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
Applying: dmaengine: at_hdmac: Remove superfluous cast
Applying: dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
Applying: dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
Applying: dmaengine: at_hdmac: Introduce atc_get_llis_residue()
Applying: dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
Applying: dmaengine: at_hdmac: Use devm_platform_ioremap_resource
Applying: dmaengine: at_hdmac: Use devm_clk_get()
Applying: dmaengine: at_hdmac: Use pm_ptr()
Applying: dmaengine: at_hdmac: Set include entries in alphabetic order
Applying: dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
Applying: dmaengine: at_hdmac: Use bitfield access macros
Applying: dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
Applying: dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
Applying: dmaengine: at_hdmac: Remove unused member of at_dma_chan
Applying: dmaengine: at_hdmac: Convert driver to use virt-dma

$ git log --oneline
0216a9804005 (HEAD) dmaengine: at_hdmac: Convert driver to use virt-dma
3c38e6f0c683 dmaengine: at_hdmac: Remove unused member of at_dma_chan
3f801af0fe24 dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
deee5deb54d7 dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
6561448a5bef dmaengine: at_hdmac: Use bitfield access macros
744ba3189722 dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
c7b1826777a1 dmaengine: at_hdmac: Set include entries in alphabetic order
fb34dfd24504 dmaengine: at_hdmac: Use pm_ptr()
348276780e9c dmaengine: at_hdmac: Use devm_clk_get()
800462a74e78 dmaengine: at_hdmac: Use devm_platform_ioremap_resource
d7236b9dd3b4 dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
e6eaacf98492 dmaengine: at_hdmac: Introduce atc_get_llis_residue()
010cabae81ae dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
9d09a47eb73a dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
2dd9e9cbb086 dmaengine: at_hdmac: Remove superfluous cast
5ef926e13fb8 dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
3b09d91a06ef dmaengine: at_hdmac: Do not print messages on console while holding the lock
e521dfad36a3 dmaengine: at_hdmac: Check return code of dma_async_device_register
5edd5e1c0a8d dmaengine: at_hdmac: Fix impossible condition
5621e6e7be9b dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
263a0ea4bc91 dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
afb3cd55a2c1 dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
cc94d7bdae69 dmaengine: at_hdmac: Fix concurrency over the active list
e654eceb0331 dmaengine: at_hdmac: Free the memset buf without holding the chan lock
2536923b7374 dmaengine: at_hdmac: Fix concurrency over descriptor
c928306dea15 dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
55f6c9b21ad1 dmaengine: at_hdmac: Protect atchan->status with the channel lock
ecb13670616f dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
e0926ead50f9 dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
8354c91e9484 dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
90395825181c dmaengine: at_hdmac: Don't start transactions at tx_submit level
93af084cf60a dmaengine: at_hdmac: Fix at_lli struct definition
79029dc341c7 (vkoul-dma/fixes) dmaengine: stm32-dma: fix potential race between pause and resume

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-11-04 15:21     ` Tudor.Ambarus
@ 2022-11-04 17:59       ` Vinod Koul
  2022-11-07  4:33         ` Vinod Koul
  0 siblings, 1 reply; 42+ messages in thread
From: Vinod Koul @ 2022-11-04 17:59 UTC (permalink / raw)
  To: Tudor.Ambarus
  Cc: peda, du, maciej.sosnowski, Nicolas.Ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel

On 04-11-22, 15:21, Tudor.Ambarus@microchip.com wrote:
> 
> >>
> >> This does not apply on dmaengine-fixes, can you please rebase and resend
> >>
> > 
> > Sure, I can, but on my side it applies just fine, both on the fixes and next
> > branches. I used git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git
> > Shall I use other tree?

this is right tree, I was on fixes branch (for initial fixes) and i
think 7th or 8th one failed to apply for me...

> 
> $ git log --oneline
> 79029dc341c7 (HEAD, vkoul-dma/fixes) dmaengine: stm32-dma: fix potential race between pause and resume
> 
> [cut]
> 
> $ b4 am 20221025090306.297886-1-tudor.ambarus@microchip.com
> Looking up https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus%40microchip.com
> Grabbing thread from lore.kernel.org/all/20221025090306.297886-1-tudor.ambarus%40microchip.com/t.mbox.gz
> Analyzing 37 messages in the thread
> Checking attestation on all messages, may take a moment...
> ---
>   [PATCH v2 1/32] dmaengine: at_hdmac: Fix at_lli struct definition
>   [PATCH v2 2/32] dmaengine: at_hdmac: Don't start transactions at tx_submit level
>   [PATCH v2 3/32] dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
>   [PATCH v2 4/32] dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
>   [PATCH v2 5/32] dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
>   [PATCH v2 6/32] dmaengine: at_hdmac: Protect atchan->status with the channel lock
>   [PATCH v2 7/32] dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
>   [PATCH v2 8/32] dmaengine: at_hdmac: Fix concurrency over descriptor
>   [PATCH v2 9/32] dmaengine: at_hdmac: Free the memset buf without holding the chan lock
>   [PATCH v2 10/32] dmaengine: at_hdmac: Fix concurrency over the active list
>   [PATCH v2 11/32] dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
>   [PATCH v2 12/32] dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
>   [PATCH v2 13/32] dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
>   [PATCH v2 14/32] dmaengine: at_hdmac: Fix impossible condition
>   [PATCH v2 15/32] dmaengine: at_hdmac: Check return code of dma_async_device_register
>   [PATCH v2 16/32] dmaengine: at_hdmac: Do not print messages on console while holding the lock
>   [PATCH v2 17/32] dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
>   [PATCH v2 18/32] dmaengine: at_hdmac: Remove superfluous cast
>   [PATCH v2 19/32] dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
>   [PATCH v2 20/32] dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
>   [PATCH v2 21/32] dmaengine: at_hdmac: Introduce atc_get_llis_residue()
>   [PATCH v2 22/32] dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
>   [PATCH v2 23/32] dmaengine: at_hdmac: Use devm_platform_ioremap_resource
>   [PATCH v2 24/32] dmaengine: at_hdmac: Use devm_clk_get()
>   [PATCH v2 25/32] dmaengine: at_hdmac: Use pm_ptr()
>   [PATCH v2 26/32] dmaengine: at_hdmac: Set include entries in alphabetic order
>   [PATCH v2 27/32] dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
>   [PATCH v2 28/32] dmaengine: at_hdmac: Use bitfield access macros
>   [PATCH v2 29/32] dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
>   [PATCH v2 30/32] dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
>   [PATCH v2 31/32] dmaengine: at_hdmac: Remove unused member of at_dma_chan
>   [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma
>     + Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> ---
> Total patches: 32
> ---
> NOTE: Some trailers were sent to the cover letter:
>       Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> NOTE: Rerun with -t to apply them to all patches
> ---
> Cover: ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.cover
>  Link: https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus@microchip.com
>  Base: not specified
>        git am ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.mbx
> 
> $ git am ./v2_20221025_tudor_ambarus_dmaengine_at_hdmac_fix_concurrency_bugs_and_then_convert_to_virt_dma.mbx
> Applying: dmaengine: at_hdmac: Fix at_lli struct definition
> Applying: dmaengine: at_hdmac: Don't start transactions at tx_submit level
> Applying: dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
> Applying: dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
> Applying: dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
> Applying: dmaengine: at_hdmac: Protect atchan->status with the channel lock
> Applying: dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
> Applying: dmaengine: at_hdmac: Fix concurrency over descriptor
> Applying: dmaengine: at_hdmac: Free the memset buf without holding the chan lock
> Applying: dmaengine: at_hdmac: Fix concurrency over the active list
> Applying: dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
> Applying: dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
> Applying: dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
> Applying: dmaengine: at_hdmac: Fix impossible condition
> Applying: dmaengine: at_hdmac: Check return code of dma_async_device_register
> Applying: dmaengine: at_hdmac: Do not print messages on console while holding the lock
> Applying: dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
> Applying: dmaengine: at_hdmac: Remove superfluous cast
> Applying: dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
> Applying: dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
> Applying: dmaengine: at_hdmac: Introduce atc_get_llis_residue()
> Applying: dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
> Applying: dmaengine: at_hdmac: Use devm_platform_ioremap_resource
> Applying: dmaengine: at_hdmac: Use devm_clk_get()
> Applying: dmaengine: at_hdmac: Use pm_ptr()
> Applying: dmaengine: at_hdmac: Set include entries in alphabetic order
> Applying: dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
> Applying: dmaengine: at_hdmac: Use bitfield access macros
> Applying: dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
> Applying: dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
> Applying: dmaengine: at_hdmac: Remove unused member of at_dma_chan
> Applying: dmaengine: at_hdmac: Convert driver to use virt-dma
> 
> $ git log --oneline
> 0216a9804005 (HEAD) dmaengine: at_hdmac: Convert driver to use virt-dma
> 3c38e6f0c683 dmaengine: at_hdmac: Remove unused member of at_dma_chan
> 3f801af0fe24 dmaengine: at_hdmac: Rename "chan_common" to "dma_chan"
> deee5deb54d7 dmaengine: at_hdmac: Rename "dma_common" to "dma_device"
> 6561448a5bef dmaengine: at_hdmac: Use bitfield access macros
> 744ba3189722 dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c
> c7b1826777a1 dmaengine: at_hdmac: Set include entries in alphabetic order
> fb34dfd24504 dmaengine: at_hdmac: Use pm_ptr()
> 348276780e9c dmaengine: at_hdmac: Use devm_clk_get()
> 800462a74e78 dmaengine: at_hdmac: Use devm_platform_ioremap_resource
> d7236b9dd3b4 dmaengine: at_hdmac: Use devm_kzalloc() and struct_size()
> e6eaacf98492 dmaengine: at_hdmac: Introduce atc_get_llis_residue()
> 010cabae81ae dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue
> 9d09a47eb73a dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts
> 2dd9e9cbb086 dmaengine: at_hdmac: Remove superfluous cast
> 5ef926e13fb8 dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL
> 3b09d91a06ef dmaengine: at_hdmac: Do not print messages on console while holding the lock
> e521dfad36a3 dmaengine: at_hdmac: Check return code of dma_async_device_register
> 5edd5e1c0a8d dmaengine: at_hdmac: Fix impossible condition
> 5621e6e7be9b dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
> 263a0ea4bc91 dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
> afb3cd55a2c1 dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware
> cc94d7bdae69 dmaengine: at_hdmac: Fix concurrency over the active list
> e654eceb0331 dmaengine: at_hdmac: Free the memset buf without holding the chan lock
> 2536923b7374 dmaengine: at_hdmac: Fix concurrency over descriptor
> c928306dea15 dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all()
> 55f6c9b21ad1 dmaengine: at_hdmac: Protect atchan->status with the channel lock
> ecb13670616f dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all
> e0926ead50f9 dmaengine: at_hdmac: Fix premature completion of desc in issue_pending
> 8354c91e9484 dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending
> 90395825181c dmaengine: at_hdmac: Don't start transactions at tx_submit level
> 93af084cf60a dmaengine: at_hdmac: Fix at_lli struct definition
> 79029dc341c7 (vkoul-dma/fixes) dmaengine: stm32-dma: fix potential race between pause and resume

-- 
~Vinod

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-11-04 17:59       ` Vinod Koul
@ 2022-11-07  4:33         ` Vinod Koul
  2022-11-07  9:00           ` Tudor.Ambarus
  0 siblings, 1 reply; 42+ messages in thread
From: Vinod Koul @ 2022-11-07  4:33 UTC (permalink / raw)
  To: Tudor.Ambarus
  Cc: peda, du, maciej.sosnowski, Nicolas.Ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel

On 04-11-22, 23:29, Vinod Koul wrote:
> On 04-11-22, 15:21, Tudor.Ambarus@microchip.com wrote:
> > 
> > >>
> > >> This does not apply on dmaengine-fixes, can you please rebase and resend
> > >>
> > > 
> > > Sure, I can, but on my side it applies just fine, both on the fixes and next
> > > branches. I used git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git
> > > Shall I use other tree?
> 
> this is right tree, I was on fixes branch (for initial fixes) and i
> think 7th or 8th one failed to apply for me...
> 
> > 
> > $ git log --oneline
> > 79029dc341c7 (HEAD, vkoul-dma/fixes) dmaengine: stm32-dma: fix potential race between pause and resume
> > 
> > [cut]
> > 
> > $ b4 am 20221025090306.297886-1-tudor.ambarus@microchip.com
> > Looking up https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus%40microchip.com
> > Grabbing thread from lore.kernel.org/all/20221025090306.297886-1-tudor.ambarus%40microchip.com/t.mbox.gz
> > Analyzing 37 messages in the thread
> > Checking attestation on all messages, may take a moment...

Okay grabbing the b4 version did the trick, no sure why my local one
failed. I have applied these now. Thanks

-- 
~Vinod

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma
  2022-11-07  4:33         ` Vinod Koul
@ 2022-11-07  9:00           ` Tudor.Ambarus
  0 siblings, 0 replies; 42+ messages in thread
From: Tudor.Ambarus @ 2022-11-07  9:00 UTC (permalink / raw)
  To: vkoul
  Cc: peda, du, maciej.sosnowski, Nicolas.Ferre, mripard, torfl6749,
	linux-kernel, dmaengine, linux-arm-kernel

On 11/7/22 06:33, Vinod Koul wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On 04-11-22, 23:29, Vinod Koul wrote:
>> On 04-11-22, 15:21, Tudor.Ambarus@microchip.com wrote:
>>>
>>>>>
>>>>> This does not apply on dmaengine-fixes, can you please rebase and resend
>>>>>
>>>>
>>>> Sure, I can, but on my side it applies just fine, both on the fixes and next
>>>> branches. I used git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine.git
>>>> Shall I use other tree?
>>
>> this is right tree, I was on fixes branch (for initial fixes) and i
>> think 7th or 8th one failed to apply for me...
>>
>>>
>>> $ git log --oneline
>>> 79029dc341c7 (HEAD, vkoul-dma/fixes) dmaengine: stm32-dma: fix potential race between pause and resume
>>>
>>> [cut]
>>>
>>> $ b4 am 20221025090306.297886-1-tudor.ambarus@microchip.com
>>> Looking up https://lore.kernel.org/r/20221025090306.297886-1-tudor.ambarus%40microchip.com
>>> Grabbing thread from lore.kernel.org/all/20221025090306.297886-1-tudor.ambarus%40microchip.com/t.mbox.gz
>>> Analyzing 37 messages in the thread
>>> Checking attestation on all messages, may take a moment...
> 
> Okay grabbing the b4 version did the trick, no sure why my local one
> failed. I have applied these now. Thanks

Cool, thank you!


^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2022-11-07  9:00 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-25  9:02 [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 01/32] dmaengine: at_hdmac: Fix at_lli struct definition Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 02/32] dmaengine: at_hdmac: Don't start transactions at tx_submit level Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 03/32] dmaengine: at_hdmac: Start transfer for cyclic channels in issue_pending Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 04/32] dmaengine: at_hdmac: Fix premature completion of desc " Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 05/32] dmaengine: at_hdmac: Do not call the complete callback on device_terminate_all Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 06/32] dmaengine: at_hdmac: Protect atchan->status with the channel lock Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 07/32] dmaengine: at_hdmac: Fix concurrency problems by removing atc_complete_all() Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 08/32] dmaengine: at_hdmac: Fix concurrency over descriptor Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 09/32] dmaengine: at_hdmac: Free the memset buf without holding the chan lock Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 10/32] dmaengine: at_hdmac: Fix concurrency over the active list Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 11/32] dmaengine: at_hdmac: Fix descriptor handling when issuing it to hardware Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 12/32] dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 13/32] dmaengine: at_hdmac: Don't allow CPU to reorder channel enable Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 14/32] dmaengine: at_hdmac: Fix impossible condition Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 15/32] dmaengine: at_hdmac: Check return code of dma_async_device_register Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 16/32] dmaengine: at_hdmac: Do not print messages on console while holding the lock Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 17/32] dmaengine: at_hdmac: Return dma_cookie_status()'s ret code when txstate is NULL Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 18/32] dmaengine: at_hdmac: Remove superfluous cast Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 19/32] dmaengine: at_hdmac: Pass residue by address to avoid unnecessary implicit casts Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 20/32] dmaengine: at_hdmac: s/atc_get_bytes_left/atc_get_residue Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 21/32] dmaengine: at_hdmac: Introduce atc_get_llis_residue() Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 22/32] dmaengine: at_hdmac: Use devm_kzalloc() and struct_size() Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 23/32] dmaengine: at_hdmac: Use devm_platform_ioremap_resource Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 24/32] dmaengine: at_hdmac: Use devm_clk_get() Tudor Ambarus
2022-10-25  9:02 ` [PATCH v2 25/32] dmaengine: at_hdmac: Use pm_ptr() Tudor Ambarus
2022-10-25  9:03 ` [PATCH v2 26/32] dmaengine: at_hdmac: Set include entries in alphabetic order Tudor Ambarus
2022-10-25  9:03 ` [PATCH v2 27/32] dmaengine: at_hdmac: Keep register definitions and structures private to at_hdmac.c Tudor Ambarus
2022-10-25  9:03 ` [PATCH v2 28/32] dmaengine: at_hdmac: Use bitfield access macros Tudor Ambarus
2022-10-25  9:03 ` [PATCH v2 29/32] dmaengine: at_hdmac: Rename "dma_common" to "dma_device" Tudor Ambarus
2022-10-25  9:03 ` [PATCH v2 30/32] dmaengine: at_hdmac: Rename "chan_common" to "dma_chan" Tudor Ambarus
2022-10-25  9:03 ` [PATCH v2 31/32] dmaengine: at_hdmac: Remove unused member of at_dma_chan Tudor Ambarus
2022-10-25  9:03 ` [PATCH v2 32/32] dmaengine: at_hdmac: Convert driver to use virt-dma Tudor Ambarus
2022-10-28 12:55   ` Nicolas Ferre
2022-10-25  9:06 ` [PATCH v2 00/32] dmaengine: at_hdmac: Fix concurrency bugs and then convert to virt-dma Tudor.Ambarus
2022-10-28 13:00 ` Nicolas Ferre
2022-11-04 13:22 ` Vinod Koul
2022-11-04 15:14   ` Tudor.Ambarus
2022-11-04 15:21     ` Tudor.Ambarus
2022-11-04 17:59       ` Vinod Koul
2022-11-07  4:33         ` Vinod Koul
2022-11-07  9:00           ` Tudor.Ambarus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).