The proper place for the main logic of the soft LLP mode is
dwc_scan_descriptors. It prevents to get the transfer unexpectedly aborted in
case the user calls dwc_tx_status.

Signed-off-by: Andy Shevchenko <andriy.shevche...@linux.intel.com>
---
 drivers/dma/dw_dmac.c |   43 +++++++++++++++++++++----------------------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 28593b7..3935ed7 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -400,6 +400,20 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct 
dw_dma_chan *dwc)
        if (status_xfer & dwc->mask) {
                /* Everything we've submitted is done */
                dma_writel(dw, CLEAR.XFER, dwc->mask);
+
+               if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
+                       if (dwc->tx_node_active != dwc->tx_list) {
+                               desc = to_dw_desc(dwc->tx_node_active);
+
+                               /* Submit next block */
+                               dwc_do_single_block(dwc, desc);
+                               spin_unlock_irqrestore(&dwc->lock, flags);
+
+                               return;
+                       }
+                       /* We are done here */
+                       clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+               }
                spin_unlock_irqrestore(&dwc->lock, flags);
 
                dwc_complete_all(dw, dwc);
@@ -411,6 +425,12 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct 
dw_dma_chan *dwc)
                return;
        }
 
+       if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
+               dev_vdbg(chan2dev(&dwc->chan), "%s: soft LLP mode\n", __func__);
+               spin_unlock_irqrestore(&dwc->lock, flags);
+               return;
+       }
+
        dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__,
                        (unsigned long long)llp);
 
@@ -596,29 +616,8 @@ static void dw_dma_tasklet(unsigned long data)
                        dwc_handle_cyclic(dw, dwc, status_err, status_xfer);
                else if (status_err & (1 << i))
                        dwc_handle_error(dw, dwc);
-               else if (status_xfer & (1 << i)) {
-                       unsigned long flags;
-
-                       spin_lock_irqsave(&dwc->lock, flags);
-                       if (test_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags)) {
-                               if (dwc->tx_node_active != dwc->tx_list) {
-                                       struct dw_desc *desc =
-                                               to_dw_desc(dwc->tx_node_active);
-
-                                       dma_writel(dw, CLEAR.XFER, dwc->mask);
-
-                                       dwc_do_single_block(dwc, desc);
-
-                                       spin_unlock_irqrestore(&dwc->lock, 
flags);
-                                       continue;
-                               }
-                               /* we are done here */
-                               clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
-                       }
-                       spin_unlock_irqrestore(&dwc->lock, flags);
-
+               else if (status_xfer & (1 << i))
                        dwc_scan_descriptors(dw, dwc);
-               }
        }
 
        /*
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to