Commit 02939cd1 authored by Sascha Hauer's avatar Sascha Hauer Committed by Vinod Koul

dmaengine: imx-sdma: Fix memory leak

The current descriptor is not on any list of the virtual DMA channel.
Once sdma_terminate_all() is called when a descriptor is currently
in flight then this one is forgotten to be freed. We have to call
vchan_terminate_vdesc() on this descriptor to re-add it to the lists.
Now that we also free the currently running descriptor we can (and
actually have to) remove the current descriptor from its list also
for the cyclic case.
Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Reviewed-by: default avatarRobin Gong <yibin.gong@nxp.com>
Tested-by: default avatarRobin Gong <yibin.gong@nxp.com>
Link: https://lore.kernel.org/r/20191216105328.15198-10-s.hauer@pengutronix.deSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent a1ff6a07
...@@ -760,11 +760,7 @@ static void sdma_start_desc(struct sdma_channel *sdmac) ...@@ -760,11 +760,7 @@ static void sdma_start_desc(struct sdma_channel *sdmac)
return; return;
} }
sdmac->desc = desc = to_sdma_desc(&vd->tx); sdmac->desc = desc = to_sdma_desc(&vd->tx);
/*
* Do not delete the node in desc_issued list in cyclic mode, otherwise
* the desc allocated will never be freed in vchan_dma_desc_free_list
*/
if (!(sdmac->flags & IMX_DMA_SG_LOOP))
list_del(&vd->node); list_del(&vd->node);
sdma->channel_control[channel].base_bd_ptr = desc->bd_phys; sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
...@@ -1071,7 +1067,6 @@ static void sdma_channel_terminate_work(struct work_struct *work) ...@@ -1071,7 +1067,6 @@ static void sdma_channel_terminate_work(struct work_struct *work)
spin_lock_irqsave(&sdmac->vc.lock, flags); spin_lock_irqsave(&sdmac->vc.lock, flags);
vchan_get_all_descriptors(&sdmac->vc, &head); vchan_get_all_descriptors(&sdmac->vc, &head);
sdmac->desc = NULL;
spin_unlock_irqrestore(&sdmac->vc.lock, flags); spin_unlock_irqrestore(&sdmac->vc.lock, flags);
vchan_dma_desc_free_list(&sdmac->vc, &head); vchan_dma_desc_free_list(&sdmac->vc, &head);
sdmac->context_loaded = false; sdmac->context_loaded = false;
...@@ -1080,11 +1075,19 @@ static void sdma_channel_terminate_work(struct work_struct *work) ...@@ -1080,11 +1075,19 @@ static void sdma_channel_terminate_work(struct work_struct *work)
static int sdma_terminate_all(struct dma_chan *chan) static int sdma_terminate_all(struct dma_chan *chan)
{ {
struct sdma_channel *sdmac = to_sdma_chan(chan); struct sdma_channel *sdmac = to_sdma_chan(chan);
unsigned long flags;
spin_lock_irqsave(&sdmac->vc.lock, flags);
sdma_disable_channel(chan); sdma_disable_channel(chan);
if (sdmac->desc) if (sdmac->desc) {
vchan_terminate_vdesc(&sdmac->desc->vd);
sdmac->desc = NULL;
schedule_work(&sdmac->terminate_worker); schedule_work(&sdmac->terminate_worker);
}
spin_unlock_irqrestore(&sdmac->vc.lock, flags);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment