dmaengine: edma: Fetch echan->edesc while holding lock in edma_comletion_handler
authorPeter Ujfalusi <peter.ujfalusi@ti.com>
Thu, 11 Feb 2016 13:17:48 +0000 (15:17 +0200)
committerVinod Koul <vinod.koul@intel.com>
Mon, 22 Feb 2016 02:49:23 +0000 (08:19 +0530)
In order to avoid possible race condition when client drivers are using
dmaengine_terminate_sync() call to disable the channel.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Suggested-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/edma.c

index 81bbfdc205919d8605d0de142a2e4e4549ee3d8d..29a7723918d96093ead93e36641c96f46a401e1a 100644 (file)
@@ -1369,36 +1369,36 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
 static void edma_completion_handler(struct edma_chan *echan)
 {
        struct device *dev = echan->vchan.chan.device->dev;
-       struct edma_desc *edesc = echan->edesc;
-
-       if (!edesc)
-               return;
+       struct edma_desc *edesc;
 
        spin_lock(&echan->vchan.lock);
-       if (edesc->cyclic) {
-               vchan_cyclic_callback(&edesc->vdesc);
-               spin_unlock(&echan->vchan.lock);
-               return;
-       } else if (edesc->processed == edesc->pset_nr) {
-               edesc->residue = 0;
-               edma_stop(echan);
-               vchan_cookie_complete(&edesc->vdesc);
-               echan->edesc = NULL;
-
-               dev_dbg(dev, "Transfer completed on channel %d\n",
-                       echan->ch_num);
-       } else {
-               dev_dbg(dev, "Sub transfer completed on channel %d\n",
-                       echan->ch_num);
-
-               edma_pause(echan);
-
-               /* Update statistics for tx_status */
-               edesc->residue -= edesc->sg_len;
-               edesc->residue_stat = edesc->residue;
-               edesc->processed_stat = edesc->processed;
+       edesc = echan->edesc;
+       if (edesc) {
+               if (edesc->cyclic) {
+                       vchan_cyclic_callback(&edesc->vdesc);
+                       spin_unlock(&echan->vchan.lock);
+                       return;
+               } else if (edesc->processed == edesc->pset_nr) {
+                       edesc->residue = 0;
+                       edma_stop(echan);
+                       vchan_cookie_complete(&edesc->vdesc);
+                       echan->edesc = NULL;
+
+                       dev_dbg(dev, "Transfer completed on channel %d\n",
+                               echan->ch_num);
+               } else {
+                       dev_dbg(dev, "Sub transfer completed on channel %d\n",
+                               echan->ch_num);
+
+                       edma_pause(echan);
+
+                       /* Update statistics for tx_status */
+                       edesc->residue -= edesc->sg_len;
+                       edesc->residue_stat = edesc->residue;
+                       edesc->processed_stat = edesc->processed;
+               }
+               edma_execute(echan);
        }
-       edma_execute(echan);
 
        spin_unlock(&echan->vchan.lock);
 }