[PATCH v5 04/10] dmaengine: dw: extract hardware-LLP residue calculation
From: James Hilliard
Date: Mon Nov 02 2026 - 14:46:24 EST
From: Serge Semin <fancer.lancer@xxxxxxxxx>
Move the hardware-LLP residue calculation into
dwc_get_hard_llp_desc_residue() so it can be reused independently of
completion handling.
Keep the scanner's LLP snapshot, descriptor updates and early returns
unchanged. The helper reports whether it found the current descriptor,
including when that descriptor has zero residue, rather than using the
residue value as a completion indication.
Signed-off-by: Serge Semin <fancer.lancer@xxxxxxxxx>
[james: extract the calculation without changing scanner behavior]
Signed-off-by: James Hilliard <james.hilliard1@xxxxxxxxx>
---
Changelog RFC:
- Instead of just dropping the dwc_scan_descriptors() method invocation
calculate the residue in the Tx-status getter.
---
drivers/dma/dw/core.c | 58 +++++++++++++++++++++++++++++----------------------
1 file changed, 33 insertions(+), 25 deletions(-)
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 2d69fab06601..5a1caca7ad68 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -267,6 +267,38 @@ static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
return dw->block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
}
+static bool dwc_get_hard_llp_desc_residue(struct dw_dma_chan *dwc,
+ struct dw_desc *desc, dma_addr_t llp)
+{
+ struct dw_desc *child;
+
+ /* Initial residue value */
+ desc->residue = desc->total_len;
+
+ /* Check first descriptors addr */
+ if (desc->txd.phys == DWC_LLP_LOC(llp))
+ return true;
+
+ /* Check first descriptors llp */
+ if (lli_read(desc, llp) == llp) {
+ /* This one is currently in progress */
+ desc->residue -= dwc_get_sent(dwc);
+ return true;
+ }
+
+ desc->residue -= desc->len;
+ list_for_each_entry(child, &desc->tx_list, desc_node) {
+ if (lli_read(child, llp) == llp) {
+ /* Currently in progress */
+ desc->residue -= dwc_get_sent(dwc);
+ return true;
+ }
+ desc->residue -= child->len;
+ }
+
+ return false;
+}
+
static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
{
dma_addr_t llp;
@@ -354,34 +386,10 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
dev_vdbg(dmaengine_chan_dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp);
list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
- /* Initial residue value */
- desc->residue = desc->total_len;
-
- /* Check first descriptors addr */
- if (desc->txd.phys == DWC_LLP_LOC(llp)) {
- spin_unlock_irqrestore(&dwc->lock, flags);
- return;
- }
-
- /* Check first descriptors llp */
- if (lli_read(desc, llp) == llp) {
- /* This one is currently in progress */
- desc->residue -= dwc_get_sent(dwc);
+ if (dwc_get_hard_llp_desc_residue(dwc, desc, llp)) {
spin_unlock_irqrestore(&dwc->lock, flags);
return;
}
-
- desc->residue -= desc->len;
- list_for_each_entry(child, &desc->tx_list, desc_node) {
- if (lli_read(child, llp) == llp) {
- /* Currently in progress */
- desc->residue -= dwc_get_sent(dwc);
- spin_unlock_irqrestore(&dwc->lock, flags);
- return;
- }
- desc->residue -= child->len;
- }
-
}
/* Residue describes source reads; only RAW.XFER completes a transfer. */
--
2.53.0