Commit 16c72f37 authored by Michael Grzeschik's avatar Michael Grzeschik Committed by Greg Kroah-Hartman

dmaengine: imx-dma: fix lockdep issue between irqhandler and tasklet

commit 5a276fa6 upstream.

The tasklet and irqhandler are using spin_lock while other routines are
using spin_lock_irqsave/restore. This leads to lockdep issues as
described bellow. This patch is changing the code to use
spinlock_irq_save/restore in both code pathes.

As imxdma_xfer_desc always gets called with spin_lock_irqsave lock held,
this patch also removes the spare call inside the routine to avoid
double locking.

[  403.358162] =================================
[  403.362549] [ INFO: inconsistent lock state ]
[  403.366945] 3.10.0-20130823+ #904 Not tainted
[  403.371331] ---------------------------------
[  403.375721] inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
[  403.381769] swapper/0 [HC0[0]:SC1[1]:HE1:SE0] takes:
[  403.386762]  (&(&imxdma->lock)->rlock){?.-...}, at: [<c019d77c>] imxdma_tasklet+0x20/0x134
[  403.395201] {IN-HARDIRQ-W} state was registered at:
[  403.400108]   [<c004b264>] mark_lock+0x2a0/0x6b4
[  403.404798]   [<c004d7c8>] __lock_acquire+0x650/0x1a64
[  403.410004]   [<c004f15c>] lock_acquire+0x94/0xa8
[  403.414773]   [<c02f74e4>] _raw_spin_lock+0x54/0x8c
[  403.419720]   [<c019d094>] dma_irq_handler+0x78/0x254
[  403.424845]   [<c0061124>] handle_irq_event_percpu+0x38/0x1b4
[  403.430670]   [<c00612e4>] handle_irq_event+0x44/0x64
[  403.435789]   [<c0063a70>] handle_level_irq+0xd8/0xf0
[  403.440903]   [<c0060a20>] generic_handle_irq+0x28/0x38
[  403.446194]   [<c0009cc4>] handle_IRQ+0x68/0x8c
[  403.450789]   [<c0008714>] avic_handle_irq+0x3c/0x48
[  403.455811]   [<c0008f84>] __irq_svc+0x44/0x74
[  403.460314]   [<c0040b04>] cpu_startup_entry+0x88/0xf4
[  403.465525]   [<c02f00d0>] rest_init+0xb8/0xe0
[  403.470045]   [<c03e07dc>] start_kernel+0x28c/0x2d4
[  403.474986]   [<a0008040>] 0xa0008040
[  403.478709] irq event stamp: 50854
[  403.482140] hardirqs last  enabled at (50854): [<c001c6b8>] tasklet_action+0x38/0xdc
[  403.489954] hardirqs last disabled at (50853): [<c001c6a0>] tasklet_action+0x20/0xdc
[  403.497761] softirqs last  enabled at (50850): [<c001bc64>] _local_bh_enable+0x14/0x18
[  403.505741] softirqs last disabled at (50851): [<c001c268>] irq_exit+0x88/0xdc
[  403.513026]
[  403.513026] other info that might help us debug this:
[  403.519593]  Possible unsafe locking scenario:
[  403.519593]
[  403.525548]        CPU0
[  403.528020]        ----
[  403.530491]   lock(&(&imxdma->lock)->rlock);
[  403.534828]   <Interrupt>
[  403.537474]     lock(&(&imxdma->lock)->rlock);
[  403.541983]
[  403.541983]  *** DEADLOCK ***
[  403.541983]
[  403.547951] no locks held by swapper/0.
[  403.551813]
[  403.551813] stack backtrace:
[  403.556222] CPU: 0 PID: 0 Comm: swapper Not tainted 3.10.0-20130823+ #904
[  403.563039] Backtrace:
[  403.565581] [<c000b98c>] (dump_backtrace+0x0/0x10c) from [<c000bb28>] (show_stack+0x18/0x1c)
[  403.574054]  r6:00000000 r5:c05c51d8 r4:c040bd58 r3:00200000
[  403.579872] [<c000bb10>] (show_stack+0x0/0x1c) from [<c02f398c>] (dump_stack+0x20/0x28)
[  403.587955] [<c02f396c>] (dump_stack+0x0/0x28) from [<c02f29c8>] (print_usage_bug.part.28+0x224/0x28c)
[  403.597340] [<c02f27a4>] (print_usage_bug.part.28+0x0/0x28c) from [<c004b404>] (mark_lock+0x440/0x6b4)
[  403.606682]  r8:c004a41c r7:00000000 r6:c040bd58 r5:c040c040 r4:00000002
[  403.613566] [<c004afc4>] (mark_lock+0x0/0x6b4) from [<c004d844>] (__lock_acquire+0x6cc/0x1a64)
[  403.622244] [<c004d178>] (__lock_acquire+0x0/0x1a64) from [<c004f15c>] (lock_acquire+0x94/0xa8)
[  403.631010] [<c004f0c8>] (lock_acquire+0x0/0xa8) from [<c02f74e4>] (_raw_spin_lock+0x54/0x8c)
[  403.639614] [<c02f7490>] (_raw_spin_lock+0x0/0x8c) from [<c019d77c>] (imxdma_tasklet+0x20/0x134)
[  403.648434]  r6:c3847010 r5:c040e890 r4:c38470d4
[  403.653194] [<c019d75c>] (imxdma_tasklet+0x0/0x134) from [<c001c70c>] (tasklet_action+0x8c/0xdc)
[  403.662013]  r8:c0599160 r7:00000000 r6:00000000 r5:c040e890 r4:c3847114 r3:c019d75c
[  403.670042] [<c001c680>] (tasklet_action+0x0/0xdc) from [<c001bd4c>] (__do_softirq+0xe4/0x1f0)
[  403.678687]  r7:00000101 r6:c0402000 r5:c059919c r4:00000001
[  403.684498] [<c001bc68>] (__do_softirq+0x0/0x1f0) from [<c001c268>] (irq_exit+0x88/0xdc)
[  403.692652] [<c001c1e0>] (irq_exit+0x0/0xdc) from [<c0009cc8>] (handle_IRQ+0x6c/0x8c)
[  403.700514]  r4:00000030 r3:00000110
[  403.704192] [<c0009c5c>] (handle_IRQ+0x0/0x8c) from [<c0008714>] (avic_handle_irq+0x3c/0x48)
[  403.712664]  r5:c0403f28 r4:c0593ebc
[  403.716343] [<c00086d8>] (avic_handle_irq+0x0/0x48) from [<c0008f84>] (__irq_svc+0x44/0x74)
[  403.724733] Exception stack(0xc0403f28 to 0xc0403f70)
[  403.729841] 3f20:                   00000001 00000004 00000000 20000013 c0402000 c04104a8
[  403.738078] 3f40: 00000002 c0b69620 a0004000 41069264 a03fb5f4 c0403f7c c0403f40 c0403f70
[  403.746301] 3f60: c004b92c c0009e74 20000013 ffffffff
[  403.751383]  r6:ffffffff r5:20000013 r4:c0009e74 r3:c004b92c
[  403.757210] [<c0009e30>] (arch_cpu_idle+0x0/0x4c) from [<c0040b04>] (cpu_startup_entry+0x88/0xf4)
[  403.766161] [<c0040a7c>] (cpu_startup_entry+0x0/0xf4) from [<c02f00d0>] (rest_init+0xb8/0xe0)
[  403.774753] [<c02f0018>] (rest_init+0x0/0xe0) from [<c03e07dc>] (start_kernel+0x28c/0x2d4)
[  403.783051]  r6:c03fc484 r5:ffffffff r4:c040a0e0
[  403.787797] [<c03e0550>] (start_kernel+0x0/0x2d4) from [<a0008040>] (0xa0008040)
Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
Cc: Jonghwan Choi <jhbird.choi@samsung.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 04283173
...@@ -414,17 +414,18 @@ static void dma_irq_handle_channel(struct imxdma_channel *imxdmac) ...@@ -414,17 +414,18 @@ static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
struct imxdma_engine *imxdma = imxdmac->imxdma; struct imxdma_engine *imxdma = imxdmac->imxdma;
int chno = imxdmac->channel; int chno = imxdmac->channel;
struct imxdma_desc *desc; struct imxdma_desc *desc;
unsigned long flags;
spin_lock(&imxdma->lock); spin_lock_irqsave(&imxdma->lock, flags);
if (list_empty(&imxdmac->ld_active)) { if (list_empty(&imxdmac->ld_active)) {
spin_unlock(&imxdma->lock); spin_unlock_irqrestore(&imxdma->lock, flags);
goto out; goto out;
} }
desc = list_first_entry(&imxdmac->ld_active, desc = list_first_entry(&imxdmac->ld_active,
struct imxdma_desc, struct imxdma_desc,
node); node);
spin_unlock(&imxdma->lock); spin_unlock_irqrestore(&imxdma->lock, flags);
if (desc->sg) { if (desc->sg) {
u32 tmp; u32 tmp;
...@@ -496,7 +497,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d) ...@@ -496,7 +497,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
{ {
struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan); struct imxdma_channel *imxdmac = to_imxdma_chan(d->desc.chan);
struct imxdma_engine *imxdma = imxdmac->imxdma; struct imxdma_engine *imxdma = imxdmac->imxdma;
unsigned long flags;
int slot = -1; int slot = -1;
int i; int i;
...@@ -504,7 +504,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d) ...@@ -504,7 +504,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
switch (d->type) { switch (d->type) {
case IMXDMA_DESC_INTERLEAVED: case IMXDMA_DESC_INTERLEAVED:
/* Try to get a free 2D slot */ /* Try to get a free 2D slot */
spin_lock_irqsave(&imxdma->lock, flags);
for (i = 0; i < IMX_DMA_2D_SLOTS; i++) { for (i = 0; i < IMX_DMA_2D_SLOTS; i++) {
if ((imxdma->slots_2d[i].count > 0) && if ((imxdma->slots_2d[i].count > 0) &&
((imxdma->slots_2d[i].xsr != d->x) || ((imxdma->slots_2d[i].xsr != d->x) ||
...@@ -514,10 +513,8 @@ static int imxdma_xfer_desc(struct imxdma_desc *d) ...@@ -514,10 +513,8 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
slot = i; slot = i;
break; break;
} }
if (slot < 0) { if (slot < 0)
spin_unlock_irqrestore(&imxdma->lock, flags);
return -EBUSY; return -EBUSY;
}
imxdma->slots_2d[slot].xsr = d->x; imxdma->slots_2d[slot].xsr = d->x;
imxdma->slots_2d[slot].ysr = d->y; imxdma->slots_2d[slot].ysr = d->y;
...@@ -526,7 +523,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d) ...@@ -526,7 +523,6 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
imxdmac->slot_2d = slot; imxdmac->slot_2d = slot;
imxdmac->enabled_2d = true; imxdmac->enabled_2d = true;
spin_unlock_irqrestore(&imxdma->lock, flags);
if (slot == IMX_DMA_2D_SLOT_A) { if (slot == IMX_DMA_2D_SLOT_A) {
d->config_mem &= ~CCR_MSEL_B; d->config_mem &= ~CCR_MSEL_B;
...@@ -602,8 +598,9 @@ static void imxdma_tasklet(unsigned long data) ...@@ -602,8 +598,9 @@ static void imxdma_tasklet(unsigned long data)
struct imxdma_channel *imxdmac = (void *)data; struct imxdma_channel *imxdmac = (void *)data;
struct imxdma_engine *imxdma = imxdmac->imxdma; struct imxdma_engine *imxdma = imxdmac->imxdma;
struct imxdma_desc *desc; struct imxdma_desc *desc;
unsigned long flags;
spin_lock(&imxdma->lock); spin_lock_irqsave(&imxdma->lock, flags);
if (list_empty(&imxdmac->ld_active)) { if (list_empty(&imxdmac->ld_active)) {
/* Someone might have called terminate all */ /* Someone might have called terminate all */
...@@ -640,7 +637,7 @@ static void imxdma_tasklet(unsigned long data) ...@@ -640,7 +637,7 @@ static void imxdma_tasklet(unsigned long data)
__func__, imxdmac->channel); __func__, imxdmac->channel);
} }
out: out:
spin_unlock(&imxdma->lock); spin_unlock_irqrestore(&imxdma->lock, flags);
} }
static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
......
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