Skip to content

Commit

Permalink
kernel/irq: Extend lockdep class for request mutex
Browse files Browse the repository at this point in the history
The IRQ code already has support for lockdep class for the lock mutex
in an interrupt descriptor. Extend this to add a second class for the
request mutex in the descriptor. Not having a class is resulting in
false positive splats in some code paths.

Signed-off-by: Andrew Lunn <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Acked-by: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: https://lkml.kernel.org/r/[email protected]
  • Loading branch information
lunn authored and KAGA-KOKO committed Dec 28, 2017
1 parent beacbc6 commit 39c3fd5
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 35 deletions.
4 changes: 3 additions & 1 deletion arch/powerpc/sysdev/fsl_msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ static int fsl_of_msi_remove(struct platform_device *ofdev)
}

static struct lock_class_key fsl_msi_irq_class;
static struct lock_class_key fsl_msi_irq_request_class;

static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
int offset, int irq_index)
Expand All @@ -373,7 +374,8 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
dev_err(&dev->dev, "No memory for MSI cascade data\n");
return -ENOMEM;
}
irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class);
irq_set_lockdep_class(virt_msir, &fsl_msi_irq_class,
&fsl_msi_irq_request_class);
cascade_data->index = offset;
cascade_data->msi_data = msi;
cascade_data->virq = virt_msir;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpio/gpio-bcm-kona.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ static struct of_device_id const bcm_kona_gpio_of_match[] = {
* category than their parents, so it won't report false recursion.
*/
static struct lock_class_key gpio_lock_class;
static struct lock_class_key gpio_request_class;

static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
Expand All @@ -531,7 +532,7 @@ static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq,
ret = irq_set_chip_data(irq, d->host_data);
if (ret < 0)
return ret;
irq_set_lockdep_class(irq, &gpio_lock_class);
irq_set_lockdep_class(irq, &gpio_lock_class, &gpio_request_class);
irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, handle_simple_irq);
irq_set_noprobe(irq);

Expand Down
4 changes: 3 additions & 1 deletion drivers/gpio/gpio-brcmstb.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ static struct brcmstb_gpio_bank *brcmstb_gpio_hwirq_to_bank(
* category than their parents, so it won't report false recursion.
*/
static struct lock_class_key brcmstb_gpio_irq_lock_class;
static struct lock_class_key brcmstb_gpio_irq_request_class;


static int brcmstb_gpio_irq_map(struct irq_domain *d, unsigned int irq,
Expand All @@ -346,7 +347,8 @@ static int brcmstb_gpio_irq_map(struct irq_domain *d, unsigned int irq,
ret = irq_set_chip_data(irq, &bank->gc);
if (ret < 0)
return ret;
irq_set_lockdep_class(irq, &brcmstb_gpio_irq_lock_class);
irq_set_lockdep_class(irq, &brcmstb_gpio_irq_lock_class,
&brcmstb_gpio_irq_lock_class);
irq_set_chip_and_handler(irq, &priv->irq_chip, handle_level_irq);
irq_set_noprobe(irq);
return 0;
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpio/gpio-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
* than their parents, so it won't report false recursion.
*/
static struct lock_class_key gpio_lock_class;
static struct lock_class_key gpio_request_class;

static int tegra_gpio_probe(struct platform_device *pdev)
{
Expand Down Expand Up @@ -670,7 +671,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)

bank = &tgi->bank_info[GPIO_BANK(gpio)];

irq_set_lockdep_class(irq, &gpio_lock_class);
irq_set_lockdep_class(irq, &gpio_lock_class,
&gpio_request_class);
irq_set_chip_data(irq, bank);
irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
}
Expand Down
27 changes: 18 additions & 9 deletions drivers/gpio/gpiolib.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ LIST_HEAD(gpio_devices);

static void gpiochip_free_hogs(struct gpio_chip *chip);
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
struct lock_class_key *key);
struct lock_class_key *lock_key,
struct lock_class_key *request_key);
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
Expand Down Expand Up @@ -1100,7 +1101,8 @@ static void gpiochip_setup_devs(void)
}

int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
struct lock_class_key *key)
struct lock_class_key *lock_key,
struct lock_class_key *request_key)
{
unsigned long flags;
int status = 0;
Expand Down Expand Up @@ -1246,7 +1248,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
if (status)
goto err_remove_from_list;

status = gpiochip_add_irqchip(chip, key);
status = gpiochip_add_irqchip(chip, lock_key, request_key);
if (status)
goto err_remove_chip;

Expand Down Expand Up @@ -1632,7 +1634,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
* 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->irq.lock_key);
irq_set_lockdep_class(irq, chip->irq.lock_key, chip->irq.request_key);
irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq.handler);
/* Chips that use nested thread handlers have them marked */
if (chip->irq.threaded)
Expand Down Expand Up @@ -1712,10 +1714,12 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
/**
* gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
* @gpiochip: the GPIO chip to add the IRQ chip to
* @lock_key: lockdep class
* @lock_key: lockdep class for IRQ lock
* @request_key: lockdep class for IRQ request
*/
static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
struct lock_class_key *lock_key)
struct lock_class_key *lock_key,
struct lock_class_key *request_key)
{
struct irq_chip *irqchip = gpiochip->irq.chip;
const struct irq_domain_ops *ops;
Expand Down Expand Up @@ -1753,6 +1757,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
gpiochip->to_irq = gpiochip_to_irq;
gpiochip->irq.default_type = type;
gpiochip->irq.lock_key = lock_key;
gpiochip->irq.request_key = request_key;

if (gpiochip->irq.domain_ops)
ops = gpiochip->irq.domain_ops;
Expand Down Expand Up @@ -1850,7 +1855,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
* @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.
* @threaded: whether this irqchip uses a nested thread handler
* @lock_key: lockdep class
* @lock_key: lockdep class for IRQ lock
* @request_key: lockdep class for IRQ request
*
* This function closely associates a certain irqchip with a certain
* gpiochip, providing an irq domain to translate the local IRQs to
Expand All @@ -1872,7 +1878,8 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
irq_flow_handler_t handler,
unsigned int type,
bool threaded,
struct lock_class_key *lock_key)
struct lock_class_key *lock_key,
struct lock_class_key *request_key)
{
struct device_node *of_node;

Expand Down Expand Up @@ -1913,6 +1920,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
gpiochip->irq.default_type = type;
gpiochip->to_irq = gpiochip_to_irq;
gpiochip->irq.lock_key = lock_key;
gpiochip->irq.request_key = request_key;
gpiochip->irq.domain = irq_domain_add_simple(of_node,
gpiochip->ngpio, first_irq,
&gpiochip_domain_ops, gpiochip);
Expand Down Expand Up @@ -1940,7 +1948,8 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
#else /* CONFIG_GPIOLIB_IRQCHIP */

static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
struct lock_class_key *key)
struct lock_class_key *lock_key,
struct lock_class_key *request_key)
{
return 0;
}
Expand Down
6 changes: 5 additions & 1 deletion drivers/irqchip/irq-renesas-intc-irqpin.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id)
*/
static struct lock_class_key intc_irqpin_irq_lock_class;

/* And this is for the request mutex */
static struct lock_class_key intc_irqpin_irq_request_class;

static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
Expand All @@ -352,7 +355,8 @@ static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq,

intc_irqpin_dbg(&p->irq[hw], "map");
irq_set_chip_data(virq, h->host_data);
irq_set_lockdep_class(virq, &intc_irqpin_irq_lock_class);
irq_set_lockdep_class(virq, &intc_irqpin_irq_lock_class,
&intc_irqpin_irq_request_class);
irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
return 0;
}
Expand Down
4 changes: 3 additions & 1 deletion drivers/mfd/arizona-irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,16 @@ static struct irq_chip arizona_irq_chip = {
};

static struct lock_class_key arizona_irq_lock_class;
static struct lock_class_key arizona_irq_request_class;

static int arizona_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct arizona *data = h->host_data;

irq_set_chip_data(virq, data);
irq_set_lockdep_class(virq, &arizona_irq_lock_class);
irq_set_lockdep_class(virq, &arizona_irq_lock_class,
&arizona_irq_request_class);
irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_simple_irq);
irq_set_nested_thread(virq, 1);
irq_set_noprobe(virq);
Expand Down
5 changes: 4 additions & 1 deletion drivers/pinctrl/pinctrl-single.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ static enum pin_config_param pcs_bias[] = {
*/
static struct lock_class_key pcs_lock_class;

/* Class for the IRQ request mutex */
static struct lock_class_key pcs_request_class;

/*
* REVISIT: Reads and writes could eventually use regmap or something
* generic. But at least on omaps, some mux registers are performance
Expand Down Expand Up @@ -1486,7 +1489,7 @@ static int pcs_irqdomain_map(struct irq_domain *d, unsigned int irq,
irq_set_chip_data(irq, pcs_soc);
irq_set_chip_and_handler(irq, &pcs->chip,
handle_level_irq);
irq_set_lockdep_class(irq, &pcs_lock_class);
irq_set_lockdep_class(irq, &pcs_lock_class, &pcs_request_class);
irq_set_noprobe(irq);

return 0;
Expand Down
33 changes: 21 additions & 12 deletions include/linux/gpio/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ struct gpio_irq_chip {
/**
* @lock_key:
*
* Per GPIO IRQ chip lockdep class.
* Per GPIO IRQ chip lockdep classes.
*/
struct lock_class_key *lock_key;
struct lock_class_key *request_key;

/**
* @parent_handler:
Expand Down Expand Up @@ -323,7 +324,8 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,

/* add/remove chips */
extern int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
struct lock_class_key *lock_key);
struct lock_class_key *lock_key,
struct lock_class_key *request_key);

/**
* gpiochip_add_data() - register a gpio_chip
Expand All @@ -350,11 +352,13 @@ extern int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
*/
#ifdef CONFIG_LOCKDEP
#define gpiochip_add_data(chip, data) ({ \
static struct lock_class_key key; \
gpiochip_add_data_with_key(chip, data, &key); \
static struct lock_class_key lock_key; \
static struct lock_class_key request_key; \
gpiochip_add_data_with_key(chip, data, &lock_key, \
&request_key); \
})
#else
#define gpiochip_add_data(chip, data) gpiochip_add_data_with_key(chip, data, NULL)
#define gpiochip_add_data(chip, data) gpiochip_add_data_with_key(chip, data, NULL, NULL)
#endif

static inline int gpiochip_add(struct gpio_chip *chip)
Expand Down Expand Up @@ -429,7 +433,8 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
irq_flow_handler_t handler,
unsigned int type,
bool threaded,
struct lock_class_key *lock_key);
struct lock_class_key *lock_key,
struct lock_class_key *request_key);

#ifdef CONFIG_LOCKDEP

Expand All @@ -445,10 +450,12 @@ static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
irq_flow_handler_t handler,
unsigned int type)
{
static struct lock_class_key key;
static struct lock_class_key lock_key;
static struct lock_class_key request_key;

return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
handler, type, false, &key);
handler, type, false,
&lock_key, &request_key);
}

static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
Expand All @@ -458,10 +465,12 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
unsigned int type)
{

static struct lock_class_key key;
static struct lock_class_key lock_key;
static struct lock_class_key request_key;

return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
handler, type, true, &key);
handler, type, true,
&lock_key, &request_key);
}
#else
static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
Expand All @@ -471,7 +480,7 @@ static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
unsigned int type)
{
return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
handler, type, false, NULL);
handler, type, false, NULL, NULL);
}

static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
Expand All @@ -481,7 +490,7 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
unsigned int type)
{
return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
handler, type, true, NULL);
handler, type, true, NULL, NULL);
}
#endif /* CONFIG_LOCKDEP */

Expand Down
9 changes: 6 additions & 3 deletions include/linux/irqdesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,15 @@ static inline bool irq_is_percpu_devid(unsigned int irq)
}

static inline void
irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class)
irq_set_lockdep_class(unsigned int irq, struct lock_class_key *lock_class,
struct lock_class_key *request_class)
{
struct irq_desc *desc = irq_to_desc(irq);

if (desc)
lockdep_set_class(&desc->lock, class);
if (desc) {
lockdep_set_class(&desc->lock, lock_class);
lockdep_set_class(&desc->request_mutex, request_class);
}
}

#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
Expand Down
11 changes: 7 additions & 4 deletions kernel/irq/generic-chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,11 @@ irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq)
EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip);

/*
* Separate lockdep class for interrupt chip which can nest irq_desc
* lock.
* Separate lockdep classes for interrupt chip which can nest irq_desc
* lock and request mutex.
*/
static struct lock_class_key irq_nested_lock_class;
static struct lock_class_key irq_nested_request_class;

/*
* irq_map_generic_chip - Map a generic chip for an irq domain
Expand Down Expand Up @@ -409,7 +410,8 @@ int irq_map_generic_chip(struct irq_domain *d, unsigned int virq,
set_bit(idx, &gc->installed);

if (dgc->gc_flags & IRQ_GC_INIT_NESTED_LOCK)
irq_set_lockdep_class(virq, &irq_nested_lock_class);
irq_set_lockdep_class(virq, &irq_nested_lock_class,
&irq_nested_request_class);

if (chip->irq_calc_mask)
chip->irq_calc_mask(data);
Expand Down Expand Up @@ -479,7 +481,8 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
continue;

if (flags & IRQ_GC_INIT_NESTED_LOCK)
irq_set_lockdep_class(i, &irq_nested_lock_class);
irq_set_lockdep_class(i, &irq_nested_lock_class,
&irq_nested_request_class);

if (!(flags & IRQ_GC_NO_MASK)) {
struct irq_data *d = irq_get_irq_data(i);
Expand Down

0 comments on commit 39c3fd5

Please sign in to comment.