Re: [GIT pull] irq updates for 4.13

From: Thomas Gleixner
Date: Tue Jul 11 2017 - 06:52:26 EST


Sebastian,

On Tue, 11 Jul 2017, Thomas Gleixner wrote:
> On Tue, 11 Jul 2017, Sebastian Reichel wrote:
> So this crashes in do_raw_spin_unlock_irqrestore() !?! I just have to
> wonder how the raw_spin_lock() succeeded. That does not make any sense.

can you please apply the patch below on top of 4.12? It's a backport
isolating the resource request changes.

Thanks,

tglx

8<----------------------
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1198,6 +1198,18 @@ static int
if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
new->flags &= ~IRQF_ONESHOT;

+ mutex_lock(&desc->request_mutex);
+ if (!desc->action) {
+ ret = irq_request_resources(desc);
+ if (ret) {
+ pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
+ new->name, irq, desc->irq_data.chip->name);
+ goto out_mutex;
+ }
+ }
+
+ chip_bus_lock(desc);
+
/*
* The following block of code has to be executed atomically
*/
@@ -1298,13 +1310,6 @@ static int
}

if (!shared) {
- ret = irq_request_resources(desc);
- if (ret) {
- pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
- new->name, irq, desc->irq_data.chip->name);
- goto out_mask;
- }
-
init_waitqueue_head(&desc->wait_for_threads);

/* Setup the type (level, edge polarity) if configured: */
@@ -1312,10 +1317,8 @@ static int
ret = __irq_set_trigger(desc,
new->flags & IRQF_TRIGGER_MASK);

- if (ret) {
- irq_release_resources(desc);
+ if (ret)
goto out_mask;
- }
}

desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \
@@ -1373,6 +1376,8 @@ static int
}

raw_spin_unlock_irqrestore(&desc->lock, flags);
+ chip_bus_sync_unlock(desc);
+ mutex_unlock(&desc->request_mutex);

/*
* Strictly no need to wake it up, but hung_task complains
@@ -1402,6 +1407,13 @@ static int

out_mask:
raw_spin_unlock_irqrestore(&desc->lock, flags);
+ chip_bus_sync_unlock(desc);
+ if (!desc->action)
+ irq_release_resources(desc);
+
+out_mutex:
+ mutex_unlock(&desc->request_mutex);
+
free_cpumask_var(mask);

out_thread:
@@ -1443,9 +1455,7 @@ int setup_irq(unsigned int irq, struct i
if (retval < 0)
return retval;

- chip_bus_lock(desc);
retval = __setup_irq(irq, desc, act);
- chip_bus_sync_unlock(desc);

if (retval)
irq_chip_pm_put(&desc->irq_data);
@@ -1469,6 +1479,7 @@ static struct irqaction *__free_irq(unsi
if (!desc)
return NULL;

+ mutex_lock(&desc->request_mutex);
chip_bus_lock(desc);
raw_spin_lock_irqsave(&desc->lock, flags);

@@ -1501,7 +1512,6 @@ static struct irqaction *__free_irq(unsi
if (!desc->action) {
irq_settings_clr_disable_unlazy(desc);
irq_shutdown(desc);
- irq_release_resources(desc);
}

#ifdef CONFIG_SMP
@@ -1543,6 +1553,11 @@ static struct irqaction *__free_irq(unsi
}
}

+ if (!desc->action)
+ irq_release_resources(desc);
+
+ mutex_unlock(&desc->request_mutex);
+
irq_chip_pm_put(&desc->irq_data);
module_put(desc->owner);
kfree(action->secondary);
@@ -1699,9 +1714,7 @@ int request_threaded_irq(unsigned int ir
return retval;
}

- chip_bus_lock(desc);
retval = __setup_irq(irq, desc, action);
- chip_bus_sync_unlock(desc);

if (retval) {
irq_chip_pm_put(&desc->irq_data);
@@ -1949,9 +1962,7 @@ int setup_percpu_irq(unsigned int irq, s
if (retval < 0)
return retval;

- chip_bus_lock(desc);
retval = __setup_irq(irq, desc, act);
- chip_bus_sync_unlock(desc);

if (retval)
irq_chip_pm_put(&desc->irq_data);
@@ -2005,9 +2016,7 @@ int request_percpu_irq(unsigned int irq,
return retval;
}

- chip_bus_lock(desc);
retval = __setup_irq(irq, desc, action);
- chip_bus_sync_unlock(desc);

if (retval) {
irq_chip_pm_put(&desc->irq_data);
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -3,6 +3,7 @@

#include <linux/rcupdate.h>
#include <linux/kobject.h>
+#include <linux/mutex.h>

/*
* Core internal functions to deal with irq descriptors
@@ -45,6 +46,7 @@ struct pt_regs;
* IRQF_FORCE_RESUME set
* @rcu: rcu head for delayed free
* @kobj: kobject used to represent this struct in sysfs
+ * @request_mutex: mutex to protect request/free before locking desc->lock
* @dir: /proc/irq/ procfs entry
* @name: flow handler name for /proc/interrupts output
*/
@@ -92,6 +94,7 @@ struct irq_desc {
struct rcu_head rcu;
struct kobject kobj;
#endif
+ struct mutex request_mutex;
int parent_irq;
struct module *owner;
const char *name;
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -359,6 +359,7 @@ static struct irq_desc *alloc_desc(int i

raw_spin_lock_init(&desc->lock);
lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+ mutex_init(&desc->request_mutex);
init_rcu_head(&desc->rcu);

desc_set_defaults(irq, desc, node, affinity, owner);