diff options
author | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2016-02-11 15:17:48 +0200 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2016-02-22 08:19:23 +0530 |
commit | e4d8817cbe9dad5da7a8487184d1b9ee8c927d92 (patch) | |
tree | 81f5cf754c0bf0ad2fcbfe429b58723e4c7edeca | |
parent | b84730ffcfccbed76e7f623b336e9bba8d78d93e (diff) | |
download | lwn-e4d8817cbe9dad5da7a8487184d1b9ee8c927d92.tar.gz lwn-e4d8817cbe9dad5da7a8487184d1b9ee8c927d92.zip |
dmaengine: edma: Fetch echan->edesc while holding lock in edma_comletion_handler
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>
-rw-r--r-- | drivers/dma/edma.c | 54 |
1 files changed, 27 insertions, 27 deletions
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 81bbfdc20591..29a7723918d9 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -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); } |