summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorStephen Boyd <swboyd@chromium.org>2020-01-14 15:11:03 -0800
committerLinus Walleij <linus.walleij@linaro.org>2020-01-15 11:22:42 +0100
commitc34f6dc8c9e6bbe9fba1d53acd6d9a3889599da3 (patch)
treecf5eef267f3814557b6445a72992b1ccd30514f0 /drivers/gpio
parentddb4e53fc72ec907f99199749cb4c71af4794607 (diff)
gpiolib: Set lockdep class for hierarchical irq domains
I see the following lockdep splat in the qcom pinctrl driver when attempting to suspend the device. ============================================ WARNING: possible recursive locking detected 5.4.2 #2 Tainted: G S -------------------------------------------- cat/6536 is trying to acquire lock: ffffff814787ccc0 (&irq_desc_lock_class){-.-.}, at: __irq_get_desc_lock+0x64/0x94 but task is already holding lock: ffffff81436740c0 (&irq_desc_lock_class){-.-.}, at: __irq_get_desc_lock+0x64/0x94 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 7 locks held by cat/6536: #0: ffffff8140e0c420 (sb_writers#7){.+.+}, at: vfs_write+0xc8/0x19c #1: ffffff8121eec480 (&of->mutex){+.+.}, at: kernfs_fop_write+0x128/0x1f4 #2: ffffff8147cad668 (kn->count#263){.+.+}, at: kernfs_fop_write+0x130/0x1f4 #3: ffffffd011446000 (system_transition_mutex){+.+.}, at: pm_suspend+0x108/0x354 #4: ffffff814302b970 (&dev->mutex){....}, at: __device_suspend+0x16c/0x420 #5: ffffff81436740c0 (&irq_desc_lock_class){-.-.}, at: __irq_get_desc_lock+0x64/0x94 #6: ffffff81479b8c10 (&pctrl->lock){....}, at: msm_gpio_irq_set_wake+0x48/0x7c stack backtrace: CPU: 4 PID: 6536 Comm: cat Tainted: G S 5.4.2 #2 Call trace: dump_backtrace+0x0/0x174 show_stack+0x20/0x2c dump_stack+0xdc/0x144 __lock_acquire+0x52c/0x2268 lock_acquire+0x1dc/0x220 _raw_spin_lock_irqsave+0x64/0x80 __irq_get_desc_lock+0x64/0x94 irq_set_irq_wake+0x40/0x144 msm_gpio_irq_set_wake+0x5c/0x7c set_irq_wake_real+0x40/0x5c irq_set_irq_wake+0x70/0x144 cros_ec_rtc_suspend+0x38/0x4c platform_pm_suspend+0x34/0x60 dpm_run_callback+0x64/0xcc __device_suspend+0x314/0x420 dpm_suspend+0xf8/0x298 dpm_suspend_start+0x84/0xb4 suspend_devices_and_enter+0xbc/0x628 pm_suspend+0x214/0x354 state_store+0xb0/0x108 kobj_attr_store+0x14/0x24 sysfs_kf_write+0x4c/0x64 kernfs_fop_write+0x158/0x1f4 __vfs_write+0x54/0x18c vfs_write+0xdc/0x19c ksys_write+0x7c/0xe4 __arm64_sys_write+0x20/0x2c el0_svc_common+0xa8/0x160 el0_svc_compat_handler+0x2c/0x38 el0_svc_compat+0x8/0x10 This is because the msm_gpio_irq_set_wake() function calls irq_set_irq_wake() as a backup in case the irq comes in during the path to idle. Given that we're calling irqchip functions from within an irqchip we need to set the lockdep class to be different for this child controller vs. the default one that the parent irqchip gets. This used to be done before this driver was converted to hierarchical irq domains in commit e35a6ae0eb3a ("pinctrl/msm: Setup GPIO chip in hierarchy") via the gpiochip_irq_map() function. With hierarchical irq domains this function has been replaced by gpiochip_hierarchy_irq_domain_alloc(). Therefore, set the lockdep class like was done previously in the irq domain path so we can avoid this lockdep warning. Fixes: fdd61a013a24 ("gpio: Add support for hierarchical IRQ domains") Cc: Thierry Reding <treding@nvidia.com> Cc: Brian Masney <masneyb@onstation.org> Cc: Lina Iyer <ilina@codeaurora.org> Cc: Marc Zyngier <maz@kernel.org> Cc: Maulik Shah <mkshah@codeaurora.org> Signed-off-by: Stephen Boyd <swboyd@chromium.org> Link: https://lore.kernel.org/r/20200114231103.85641-1-swboyd@chromium.org Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e5057c0ca7e4..91a0e83c465d 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2032,6 +2032,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
parent_type);
chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
irq, parent_hwirq);
+ irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key);
ret = irq_domain_alloc_irqs_parent(d, irq, 1, &parent_fwspec);
if (ret)
chip_err(gc,