GPU: ipu: Fix race in installing IPU chained IRQ handler
authorRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 16 Jun 2015 22:06:30 +0000 (23:06 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 18 Jun 2015 12:03:08 +0000 (14:03 +0200)
The IPU code was installing its chained interrupt handler (which enables
the interrupt) before it was setting its data, which provokes an oops on
kexec.  Fix this by converting to irq_set_chained_handler_and_data().

[drm] Initialized drm 1.1.0 20060810
imx-drm display-subsystem: parent device of /soc/aips-bus@02000000/ldb@020e0008/lvds-channel@1 is not available
imx-drm display-subsystem: parent device of /soc/aips-bus@02000000/ldb@020e0008/lvds-channel@1 is not available
Unable to handle kernel NULL pointer dereference at virtual address 00000070
pgd = c0004000
[00000070] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.1.0-rc6+ #1693
Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
task: d74c0000 ti: d74aa000 task.ti: d74aa000
PC is at ipu_irq_handle+0x28/0xd8
LR is at ipu_irq_handler+0x6c/0xc0
pc : [<c03c56d8>]    lr : [<c03c58a4>]    psr: 200001d3
sp : d74abbd0  ip : d74abc00  fp : d74abbfc
r10: 000001e0  r9 : c0085154  r8 : 00000009
r7 : 00000000  r6 : 00000000  r5 : d74abc04  r4 : c0a6b6a8
r3 : 00000000  r2 : 00000009  r1 : d74abc04  r0 : 00000000
Flags: nzCv  IRQs off  FIQs off  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c5387d  Table: 10004059  DAC: 00000015
Process swapper/0 (pid: 1, stack limit = 0xd74aa210)
Stack: (0xd74abbd0 to 0xd74ac000)
Backtrace:
[<c03c56b0>] (ipu_irq_handle) from [<c03c58a4>] (ipu_irq_handler+0x6c/0xc0)
[<c03c5838>] (ipu_irq_handler) from [<c0080154>] (generic_handle_irq+0x28/0x38)
[<c008012c>] (generic_handle_irq) from [<c0080288>] (__handle_domain_irq+0x5c/0xb8)
[<c008022c>] (__handle_domain_irq) from [<c0009428>] (gic_handle_irq+0x28/0x68)
[<c0009400>] (gic_handle_irq) from [<c0013dc4>] (__irq_svc+0x44/0x5c)
[<c07638fc>] (_raw_spin_unlock_irqrestore) from [<c00803bc>] (__irq_put_desc_unlock+0x1c/0x40)
[<c00803a0>] (__irq_put_desc_unlock) from [<c00841f4>] (__irq_set_handler+0x54/0x5c)
[<c00841a0>] (__irq_set_handler) from [<c03c5f48>] (ipu_probe+0x29c/0x708)
[<c03c5cac>] (ipu_probe) from [<c03d3848>] (platform_drv_probe+0x50/0xac)
[<c03d37f8>] (platform_drv_probe) from [<c03d1f3c>] (driver_probe_device+0x1d4/0x278)

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Alexandre Courbot <gnurou@gmail.com>
Cc: Hans Ulli Kroll <ulli.kroll@googlemail.com>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lkml.kernel.org/r/E1Z4z02-0002SI-Br@rmk-PC.arm.linux.org.uk
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
drivers/gpu/ipu-v3/ipu-common.c

index 67bab5c36056128ba75837e5ea041d390a9e580b..6d2f39d36e445bda4840f06d7eb1f779081f2c22 100644 (file)
@@ -1119,10 +1119,9 @@ static int ipu_irq_init(struct ipu_soc *ipu)
                ct->regs.mask = IPU_INT_CTRL(i / 32);
        }
 
-       irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler);
-       irq_set_handler_data(ipu->irq_sync, ipu);
-       irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler);
-       irq_set_handler_data(ipu->irq_err, ipu);
+       irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
+       irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
+                                        ipu);
 
        return 0;
 }
@@ -1131,10 +1130,8 @@ static void ipu_irq_exit(struct ipu_soc *ipu)
 {
        int i, irq;
 
-       irq_set_chained_handler(ipu->irq_err, NULL);
-       irq_set_handler_data(ipu->irq_err, NULL);
-       irq_set_chained_handler(ipu->irq_sync, NULL);
-       irq_set_handler_data(ipu->irq_sync, NULL);
+       irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
+       irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
 
        /* TODO: remove irq_domain_generic_chips */