From fb2a29792bfc8121a48e8b0d3afb42b658dd82d0 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 13 Jul 2015 19:19:15 +0800 Subject: [PATCH] MLK-11248: dmaengine: imx-sdma: add new api for sync with dma and substream There is occasion that dma callback come late after the substream is released. Then there will be kernel dump. [<805866b0>] (imx_pcm_dma_complete) from [<802fad9c>] (sdma_handle_channel_loop.isra.25+0x48/0x54) [<802fad9c>] (sdma_handle_channel_loop.isra.25) from [<802fae48>] (sdma_tasklet+0xa0/0x1d4) [<802fae48>] (sdma_tasklet) from [<800356e0>] (tasklet_action+0x64/0xf8) [<800356e0>] (tasklet_action) from [<80034ea0>] (__do_softirq+0x104/0x218) [<80034ea0>] (__do_softirq) from [<80035220>] (irq_exit+0xa8/0xec) [<80035220>] (irq_exit) from [<8000ed44>] (handle_IRQ+0x3c/0x90) [<8000ed44>] (handle_IRQ) from [<80008578>] (gic_handle_irq+0x28/0x5c) [<80008578>] (gic_handle_irq) from [<80012100>] (__irq_svc+0x40/0x70) The reason is the sdma tasklet is async with audio substream release. ALSA think when terminate dma, the dma should be stopped and no callback be called. This patch is to add new api dma_sync_wait_tasklet(), which is called in snd_dmaengine_pcm_close(). It will make sure the callback not be called after this funtion. Tasklet_kill is to wait scheduled tasklet end. Tasklet_kill can't be added to terminate dma function, because terminate dma function may be called in interrupt, but tasklet_kill can't be called in interrupt context. Signed-off-by: Shengjiu Wang (cherry picked from commit 9815881b6acaa72a705e1fa3c26a852fc81bfce5) --- drivers/dma/imx-sdma.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index cb761a57bc39..9f9fa379ad99 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1599,6 +1599,13 @@ static int sdma_config(struct dma_chan *chan, return sdma_config_channel(chan); } +static void sdma_wait_tasklet(struct dma_chan *chan) +{ + struct sdma_channel *sdmac = to_sdma_chan(chan); + + tasklet_kill(&sdmac->tasklet); +} + static enum dma_status sdma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) @@ -2051,6 +2058,7 @@ static int sdma_probe(struct platform_device *pdev) sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources; sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources; sdma->dma_device.device_tx_status = sdma_tx_status; + sdma->dma_device.device_synchronize = sdma_wait_tasklet; sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg; sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; sdma->dma_device.device_config = sdma_config; -- 2.17.1