dw_dmac: move soft LLP code from tasklet to dwc_scan_descriptors
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Fri, 18 Jan 2013 12:14:15 +0000 (14:14 +0200)
committerVinod Koul <vinod.koul@intel.com>
Mon, 21 Jan 2013 04:49:21 +0000 (20:49 -0800)
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.shevchenko@linux.intel.com>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/dw_dmac.c

index 635a4a5d31ae7a8680d7e201369123860fe31c12..dc3b9558a25c4a9f1182c328bcce7f33dd5d9374 100644 (file)
@@ -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);
-               }
        }
 
        /*