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>
This commit is contained in:
Peter Ujfalusi 2016-02-11 15:17:48 +02:00 committed by Vinod Koul
parent b84730ffcf
commit e4d8817cbe
1 changed files with 24 additions and 24 deletions

View File

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