MLK-13849 dma: imx-sdma: fix kernel crashs when play Audio by HDMI
authorRobin Gong <yibin.gong@nxp.com>
Thu, 9 Feb 2017 03:00:55 +0000 (11:00 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:58:10 +0000 (14:58 -0500)
In cyclic/loop mode, DMA call shouldn't touch dma cookie, since only one
time need to be submitted, otherwise, below kernel bug will be triggered:

Playing WAVE '/unit_tests/audio8k16S.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo
------------[ cut here ]------------
Kernel BUG at 8043d030 [verbose debug info unavailable]
Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
Modules linked in: ov5642_camera mxc_v4l2_capture ipu_bg_overlay_sdc ipu_still ipu_prp_enc ipu_csi_enc ipu_fg_overlay_sdc ov5640_camera_mipi_int ov5640_camera_int v4l2_int_device mxc_dcic
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.9.5-01681-g6dbd27b #7
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
task: 80f06600 task.stack: 80f00000
PC is at mxc_sdma_handle_channel_normal+0xc0/0xd8
LR is at tasklet_action+0x94/0x14c

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Signed-off-by: Mihai Serban <mihai.serban@nxp.com>
drivers/dma/imx-sdma.c

index 5fbe320..6a86e6d 100644 (file)
@@ -821,10 +821,14 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
                int channel = fls(stat) - 1;
                struct sdma_channel *sdmac = &sdma->channel[channel];
 
-               if ((sdmac->flags & IMX_DMA_SG_LOOP) &&
-                       (sdmac->peripheral_type != IMX_DMATYPE_HDMI))
-                       sdma_update_channel_loop(sdmac);
-               else
+               if (sdmac->flags & IMX_DMA_SG_LOOP) {
+                       if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
+                               sdma_update_channel_loop(sdmac);
+                       else
+                               dmaengine_desc_get_callback_invoke(&sdmac->desc,
+                                                                       NULL);
+
+               } else
                        tasklet_schedule(&sdmac->tasklet);
 
                __clear_bit(channel, &stat);