From a585f87c863e4e1d496459d382b802bf5ebe3717 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 24 Mar 2014 03:38:10 +0100 Subject: [PATCH] gpio: mxs: Allow for recursive enable_irq_wake() call The scenario here is that someone calls enable_irq_wake() from somewhere in the code. This will result in the lockdep producing a backtrace as can be seen below. In my case, this problem is triggered when using the wl1271 (TI WlCore) driver found in drivers/net/wireless/ti/ . The problem cause is rather obvious from the backtrace, but let's outline the dependency. enable_irq_wake() grabs the IRQ buslock in irq_set_irq_wake(), which in turns calls mxs_gpio_set_wake_irq() . But mxs_gpio_set_wake_irq() calls enable_irq_wake() again on the one-level-higher IRQ , thus it tries to grab the IRQ buslock again in irq_set_irq_wake() . Because the spinlock in irq_set_irq_wake()->irq_get_desc_buslock()->__irq_get_desc_lock() is not marked as recursive, lockdep will spew the stuff below. We know we can safely re-enter the lock, so use IRQ_GC_INIT_NESTED_LOCK to fix the spew. ============================================= [ INFO: possible recursive locking detected ] 3.10.33-00012-gf06b763-dirty #61 Not tainted --------------------------------------------- kworker/0:1/18 is trying to acquire lock: (&irq_desc_lock_class){-.-...}, at: [] __irq_get_desc_lock+0x48/0x88 but task is already holding lock: (&irq_desc_lock_class){-.-...}, at: [] __irq_get_desc_lock+0x48/0x88 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&irq_desc_lock_class); lock(&irq_desc_lock_class); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by kworker/0:1/18: #0: (events){.+.+.+}, at: [] process_one_work+0x134/0x4a4 #1: ((&fw_work->work)){+.+.+.}, at: [] process_one_work+0x134/0x4a4 #2: (&irq_desc_lock_class){-.-...}, at: [] __irq_get_desc_lock+0x48/0x88 stack backtrace: CPU: 0 PID: 18 Comm: kworker/0:1 Not tainted 3.10.33-00012-gf06b763-dirty #61 Workqueue: events request_firmware_work_func [] (unwind_backtrace+0x0/0xf0) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (__lock_acquire+0x140c/0x1a64) [] (__lock_acquire+0x140c/0x1a64) from [] (lock_acquire+0x9c/0x104) [] (lock_acquire+0x9c/0x104) from [] (_raw_spin_lock_irqsave+0x44/0x58) [] (_raw_spin_lock_irqsave+0x44/0x58) from [] (__irq_get_desc_lock+0x48/0x88) [] (__irq_get_desc_lock+0x48/0x88) from [] (irq_set_irq_wake+0x20/0xf4) [] (irq_set_irq_wake+0x20/0xf4) from [] (mxs_gpio_set_wake_irq+0x1c/0x24) [] (mxs_gpio_set_wake_irq+0x1c/0x24) from [] (set_irq_wake_real+0x30/0x44) [] (set_irq_wake_real+0x30/0x44) from [] (irq_set_irq_wake+0x8c/0xf4) [] (irq_set_irq_wake+0x8c/0xf4) from [] (wlcore_nvs_cb+0x10c/0x97c) [] (wlcore_nvs_cb+0x10c/0x97c) from [] (request_firmware_work_func+0x38/0x58) [] (request_firmware_work_func+0x38/0x58) from [] (process_one_work+0x1c0/0x4a4) [] (process_one_work+0x1c0/0x4a4) from [] (worker_thread+0x138/0x394) [] (worker_thread+0x138/0x394) from [] (kthread+0xa4/0xb0) [] (kthread+0xa4/0xb0) from [] (ret_from_fork+0x14/0x34) wlcore: loaded Cc: stable@vger.kernel.org Signed-off-by: Marek Vasut Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 532bcb336eff54..8ffdd7d2bade4c 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -214,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; ct->regs.mask = PINCTRL_IRQEN(port); - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); + irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, + IRQ_NOREQUEST, 0); } static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)