From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754732AbbHNJBH (ORCPT ); Fri, 14 Aug 2015 05:01:07 -0400 Received: from arroyo.ext.ti.com ([192.94.94.40]:55817 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753956AbbHNJBA (ORCPT ); Fri, 14 Aug 2015 05:01:00 -0400 Message-ID: <55CDAE41.7060400@ti.com> Date: Fri, 14 Aug 2015 12:00:49 +0300 From: Roger Quadros User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.8.0 MIME-Version: 1.0 To: Grygorii Strashko , Linus Walleij , Alexandre Courbot CC: , , , , Geert Uytterhoeven Subject: Re: [PATCH] gpiolib: irqchip: use different lockdep class for each gpio irqchip References: <1439477919-24356-1-git-send-email-grygorii.strashko@ti.com> In-Reply-To: <1439477919-24356-1-git-send-email-grygorii.strashko@ti.com> Content-Type: text/plain; charset="windows-1252" Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 13/08/15 17:58, Grygorii Strashko wrote: > Since IRQ chip helpers were introduced drivers lose ability to > register separate lockdep classes for each registered GPIO IRQ > chip and the gpiolib now is using shared lockdep class for > all GPIO IRQ chips (gpiochip_irq_lock_class). > As result, lockdep will produce warning when there are min two > stacked GPIO chips and all of them are interrupt controllers. > > HW configuration which generates lockdep warning (TI dra7-evm): > > [SOC GPIO bankA.gpioX] > <- irq - [pcf875x.gpioY] > <- irq - DevZ.enable_irq_wake(pcf_gpioY_irq); > The issue was reported in [1] and discussed [2]. > > ============================================= > [ INFO: possible recursive locking detected ] > 4.2.0-rc6-00013-g5d050ed-dirty #55 Not tainted > --------------------------------------------- > sh/63 is trying to acquire lock: > (class){......}, at: [] __irq_get_desc_lock+0x50/0x94 > > but task is already holding lock: > (class){......}, at: [] __irq_get_desc_lock+0x50/0x94 > > other info that might help us debug this: > Possible unsafe locking scenario: > > CPU0 > ---- > lock(class); > lock(class); > > *** DEADLOCK *** > > May be due to missing lock nesting notation > > 7 locks held by sh/63: > #0: (sb_writers#4){.+.+.+}, at: [] vfs_write+0x13c/0x164 > #1: (&of->mutex){+.+.+.}, at: [] kernfs_fop_write+0x4c/0x1a0 > #2: (s_active#36){.+.+.+}, at: [] kernfs_fop_write+0x54/0x1a0 > #3: (pm_mutex){+.+.+.}, at: [] pm_suspend+0xec/0x4c4 > #4: (&dev->mutex){......}, at: [] __device_suspend+0xd4/0x398 > #5: (&gpio->lock){+.+.+.}, at: [] __irq_get_desc_lock+0x74/0x94 > #6: (class){......}, at: [] __irq_get_desc_lock+0x50/0x94 > > stack backtrace: > CPU: 0 PID: 63 Comm: sh Not tainted 4.2.0-rc6-00013-g5d050ed-dirty #55 > Hardware name: Generic DRA74X (Flattened Device Tree) > [] (unwind_backtrace) from [] (show_stack+0x10/0x14) > [] (show_stack) from [] (dump_stack+0x84/0x9c) > [] (dump_stack) from [] (__lock_acquire+0x19c0/0x1e20) > [] (__lock_acquire) from [] (lock_acquire+0xa8/0x128) > [] (lock_acquire) from [] (_raw_spin_lock_irqsave+0x38/0x4c) > [] (_raw_spin_lock_irqsave) from [] (__irq_get_desc_lock+0x50/0x94) > [] (__irq_get_desc_lock) from [] (irq_set_irq_wake+0x20/0xfc) > [] (irq_set_irq_wake) from [] (pcf857x_irq_set_wake+0x24/0x54) > [] (pcf857x_irq_set_wake) from [] (irq_set_irq_wake+0x8c/0xfc) > [] (irq_set_irq_wake) from [] (gpio_keys_suspend+0x70/0xd4) > [] (gpio_keys_suspend) from [] (dpm_run_callback+0x50/0x124) > [] (dpm_run_callback) from [] (__device_suspend+0x10c/0x398) > [] (__device_suspend) from [] (dpm_suspend+0x134/0x2f4) > [] (dpm_suspend) from [] (suspend_devices_and_enter+0xa8/0x728) > [] (suspend_devices_and_enter) from [] (pm_suspend+0x32c/0x4c4) > [] (pm_suspend) from [] (state_store+0x64/0xb8) > [] (state_store) from [] (kernfs_fop_write+0xbc/0x1a0) > [] (kernfs_fop_write) from [] (__vfs_write+0x20/0xd8) > [] (__vfs_write) from [] (vfs_write+0x90/0x164) > [] (vfs_write) from [] (SyS_write+0x44/0x9c) > [] (SyS_write) from [] (ret_fast_syscall+0x0/0x54) > > Lets fix it by using separate lockdep class for each registered GPIO > IRQ Chip. This is done by wrapping gpiochip_irqchip_add call into macros. > > The implementation of this patch inspired by solution done by Nicolas > Boichat for regmap [3] > > [1] http://www.spinics.net/lists/linux-gpio/msg05844.html > [2] http://www.spinics.net/lists/linux-gpio/msg06021.html > [3] http://www.spinics.net/lists/arm-kernel/msg429834.html > > Cc: Geert Uytterhoeven > Cc: Roger Quadros > Reported-by: Roger Quadros > Signed-off-by: Grygorii Strashko Nice !! :) Tested-by: Roger Quadros cheers, -roger > --- > drivers/gpio/gpiolib.c | 27 ++++++++++++++------------- > include/linux/gpio/driver.h | 27 ++++++++++++++++++++++----- > 2 files changed, 36 insertions(+), 18 deletions(-) > > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c > index bf4bd1d..75dddc1 100644 > --- a/drivers/gpio/gpiolib.c > +++ b/drivers/gpio/gpiolib.c > @@ -456,12 +456,6 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, > } > EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); > > -/* > - * This lock class tells lockdep that GPIO irqs are in a different > - * category than their parents, so it won't report false recursion. > - */ > -static struct lock_class_key gpiochip_irq_lock_class; > - > /** > * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip > * @d: the irqdomain used by this irqchip > @@ -478,7 +472,11 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, > struct gpio_chip *chip = d->host_data; > > irq_set_chip_data(irq, chip); > - irq_set_lockdep_class(irq, &gpiochip_irq_lock_class); > + /* > + * This lock class tells lockdep that GPIO irqs are in a different > + * category than their parents, so it won't report false recursion. > + */ > + irq_set_lockdep_class(irq, chip->lock_key); > irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); > /* Chips that can sleep need nested thread handlers */ > if (chip->can_sleep && !chip->irq_not_threaded) > @@ -584,6 +582,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) > * @handler: the irq handler to use (often a predefined irq core function) > * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE > * to have the core avoid setting up any default type in the hardware. > + * @lock_key: lockdep class > * > * This function closely associates a certain irqchip with a certain > * gpiochip, providing an irq domain to translate the local IRQs to > @@ -599,11 +598,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) > * the pins on the gpiochip can generate a unique IRQ. Everything else > * need to be open coded. > */ > -int gpiochip_irqchip_add(struct gpio_chip *gpiochip, > - struct irq_chip *irqchip, > - unsigned int first_irq, > - irq_flow_handler_t handler, > - unsigned int type) > +int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, > + struct irq_chip *irqchip, > + unsigned int first_irq, > + irq_flow_handler_t handler, > + unsigned int type, > + struct lock_class_key *lock_key) > { > struct device_node *of_node; > unsigned int offset; > @@ -629,6 +629,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, > gpiochip->irq_handler = handler; > gpiochip->irq_default_type = type; > gpiochip->to_irq = gpiochip_to_irq; > + gpiochip->lock_key = lock_key; > gpiochip->irqdomain = irq_domain_add_simple(of_node, > gpiochip->ngpio, first_irq, > &gpiochip_domain_ops, gpiochip); > @@ -658,7 +659,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, > > return 0; > } > -EXPORT_SYMBOL_GPL(gpiochip_irqchip_add); > +EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add); > > #else /* CONFIG_GPIOLIB_IRQCHIP */ > > diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h > index c8393cd..dd1dfbb 100644 > --- a/include/linux/gpio/driver.h > +++ b/include/linux/gpio/driver.h > @@ -6,6 +6,7 @@ > #include > #include > #include > +#include > #include > > struct device; > @@ -62,6 +63,7 @@ struct seq_file; > * implies that if the chip supports IRQs, these IRQs need to be threaded > * as the chip access may sleep when e.g. reading out the IRQ status > * registers. > + * @exported: flags if the gpiochip is exported for use from sysfs. Private. > * @irq_not_threaded: flag must be set if @can_sleep is set but the > * IRQs don't need to be threaded > * > @@ -126,6 +128,7 @@ struct gpio_chip { > irq_flow_handler_t irq_handler; > unsigned int irq_default_type; > int irq_parent; > + struct lock_class_key *lock_key; > #endif > > #if defined(CONFIG_OF_GPIO) > @@ -171,11 +174,25 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, > int parent_irq, > irq_flow_handler_t parent_handler); > > -int gpiochip_irqchip_add(struct gpio_chip *gpiochip, > - struct irq_chip *irqchip, > - unsigned int first_irq, > - irq_flow_handler_t handler, > - unsigned int type); > +int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, > + struct irq_chip *irqchip, > + unsigned int first_irq, > + irq_flow_handler_t handler, > + unsigned int type, > + struct lock_class_key *lock_key); > + > +#ifdef CONFIG_LOCKDEP > +#define gpiochip_irqchip_add(...) \ > +( \ > + ({ \ > + static struct lock_class_key _key; \ > + _gpiochip_irqchip_add(__VA_ARGS__, &_key); \ > + }) \ > +) > +#else > +#define gpiochip_irqchip_add(...) \ > + _gpiochip_irqchip_add(__VA_ARGS__, NULL) > +#endif > > #endif /* CONFIG_GPIOLIB_IRQCHIP */ > >