Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2019-07-21 10:23:21 +0200
committerJiri Slaby <jslaby@suse.cz>2019-07-21 10:23:25 +0200
commit4ee6c7927d0e5106c4f51f3d3dac18c71175ca57 (patch)
treee110aed7a31cf7524900a9451e6f3bc76792a1aa
parent022194a429c0bf06dbc2cc8501199fb3c31c4903 (diff)
genirq: Delay deactivation in free_irq() (bnc#1012628).
-rw-r--r--patches.kernel.org/5.2.2-007-genirq-Delay-deactivation-in-free_irq.patch162
-rw-r--r--series.conf1
2 files changed, 163 insertions, 0 deletions
diff --git a/patches.kernel.org/5.2.2-007-genirq-Delay-deactivation-in-free_irq.patch b/patches.kernel.org/5.2.2-007-genirq-Delay-deactivation-in-free_irq.patch
new file mode 100644
index 0000000000..be3879312f
--- /dev/null
+++ b/patches.kernel.org/5.2.2-007-genirq-Delay-deactivation-in-free_irq.patch
@@ -0,0 +1,162 @@
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Fri, 28 Jun 2019 13:11:49 +0200
+Subject: [PATCH] genirq: Delay deactivation in free_irq()
+References: bnc#1012628
+Patch-mainline: 5.2.2
+Git-commit: 4001d8e8762f57d418b66e4e668601791900a1dd
+
+commit 4001d8e8762f57d418b66e4e668601791900a1dd upstream.
+
+When interrupts are shutdown, they are immediately deactivated in the
+irqdomain hierarchy. While this looks obviously correct there is a subtle
+issue:
+
+There might be an interrupt in flight when free_irq() is invoking the
+shutdown. This is properly handled at the irq descriptor / primary handler
+level, but the deactivation might completely disable resources which are
+required to acknowledge the interrupt.
+
+Split the shutdown code and deactivate the interrupt after synchronization
+in free_irq(). Fixup all other usage sites where this is not an issue to
+invoke the combined shutdown_and_deactivate() function instead.
+
+This still might be an issue if the interrupt in flight servicing is
+delayed on a remote CPU beyond the invocation of synchronize_irq(), but
+that cannot be handled at that level and needs to be handled in the
+synchronize_irq() context.
+
+Fixes: f8264e34965a ("irqdomain: Introduce new interfaces to support hierarchy irqdomains")
+Reported-by: Robert Hodaszi <Robert.Hodaszi@digi.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
+Link: https://lkml.kernel.org/r/20190628111440.098196390@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+---
+ kernel/irq/autoprobe.c | 6 +++---
+ kernel/irq/chip.c | 6 ++++++
+ kernel/irq/cpuhotplug.c | 2 +-
+ kernel/irq/internals.h | 1 +
+ kernel/irq/manage.c | 12 +++++++++++-
+ 5 files changed, 22 insertions(+), 5 deletions(-)
+
+diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
+index 16cbf6beb276..ae60cae24e9a 100644
+--- a/kernel/irq/autoprobe.c
++++ b/kernel/irq/autoprobe.c
+@@ -90,7 +90,7 @@ unsigned long probe_irq_on(void)
+ /* It triggered already - consider it spurious. */
+ if (!(desc->istate & IRQS_WAITING)) {
+ desc->istate &= ~IRQS_AUTODETECT;
+- irq_shutdown(desc);
++ irq_shutdown_and_deactivate(desc);
+ } else
+ if (i < 32)
+ mask |= 1 << i;
+@@ -127,7 +127,7 @@ unsigned int probe_irq_mask(unsigned long val)
+ mask |= 1 << i;
+
+ desc->istate &= ~IRQS_AUTODETECT;
+- irq_shutdown(desc);
++ irq_shutdown_and_deactivate(desc);
+ }
+ raw_spin_unlock_irq(&desc->lock);
+ }
+@@ -169,7 +169,7 @@ int probe_irq_off(unsigned long val)
+ nr_of_irqs++;
+ }
+ desc->istate &= ~IRQS_AUTODETECT;
+- irq_shutdown(desc);
++ irq_shutdown_and_deactivate(desc);
+ }
+ raw_spin_unlock_irq(&desc->lock);
+ }
+diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
+index 29d6c7d070b4..3ff4a1260885 100644
+--- a/kernel/irq/chip.c
++++ b/kernel/irq/chip.c
+@@ -314,6 +314,12 @@ void irq_shutdown(struct irq_desc *desc)
+ }
+ irq_state_clr_started(desc);
+ }
++}
++
++
++void irq_shutdown_and_deactivate(struct irq_desc *desc)
++{
++ irq_shutdown(desc);
+ /*
+ * This must be called even if the interrupt was never started up,
+ * because the activation can happen before the interrupt is
+diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c
+index 5b1072e394b2..6c7ca2e983a5 100644
+--- a/kernel/irq/cpuhotplug.c
++++ b/kernel/irq/cpuhotplug.c
+@@ -116,7 +116,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
+ */
+ if (irqd_affinity_is_managed(d)) {
+ irqd_set_managed_shutdown(d);
+- irq_shutdown(desc);
++ irq_shutdown_and_deactivate(desc);
+ return false;
+ }
+ affinity = cpu_online_mask;
+diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
+index 70c3053bc1f6..9c957f8b1198 100644
+--- a/kernel/irq/internals.h
++++ b/kernel/irq/internals.h
+@@ -82,6 +82,7 @@ extern int irq_activate_and_startup(struct irq_desc *desc, bool resend);
+ extern int irq_startup(struct irq_desc *desc, bool resend, bool force);
+
+ extern void irq_shutdown(struct irq_desc *desc);
++extern void irq_shutdown_and_deactivate(struct irq_desc *desc);
+ extern void irq_enable(struct irq_desc *desc);
+ extern void irq_disable(struct irq_desc *desc);
+ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
+diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
+index 78f3ddeb7fe4..54a41da65eb3 100644
+--- a/kernel/irq/manage.c
++++ b/kernel/irq/manage.c
+@@ -13,6 +13,7 @@
+ #include <linux/module.h>
+ #include <linux/random.h>
+ #include <linux/interrupt.h>
++#include <linux/irqdomain.h>
+ #include <linux/slab.h>
+ #include <linux/sched.h>
+ #include <linux/sched/rt.h>
+@@ -1699,6 +1700,7 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
+ /* If this was the last handler, shut down the IRQ line: */
+ if (!desc->action) {
+ irq_settings_clr_disable_unlazy(desc);
++ /* Only shutdown. Deactivate after synchronize_hardirq() */
+ irq_shutdown(desc);
+ }
+
+@@ -1768,6 +1770,14 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
+ * require it to deallocate resources over the slow bus.
+ */
+ chip_bus_lock(desc);
++ /*
++ * There is no interrupt on the fly anymore. Deactivate it
++ * completely.
++ */
++ raw_spin_lock_irqsave(&desc->lock, flags);
++ irq_domain_deactivate_irq(&desc->irq_data);
++ raw_spin_unlock_irqrestore(&desc->lock, flags);
++
+ irq_release_resources(desc);
+ chip_bus_sync_unlock(desc);
+ irq_remove_timings(desc);
+@@ -1855,7 +1865,7 @@ static const void *__cleanup_nmi(unsigned int irq, struct irq_desc *desc)
+ }
+
+ irq_settings_clr_disable_unlazy(desc);
+- irq_shutdown(desc);
++ irq_shutdown_and_deactivate(desc);
+
+ irq_release_resources(desc);
+
+--
+2.22.0
+
diff --git a/series.conf b/series.conf
index 8bd6985e88..93a03ff795 100644
--- a/series.conf
+++ b/series.conf
@@ -94,6 +94,7 @@
patches.kernel.org/5.2.2-004-nilfs2-do-not-use-unexported-cpu_to_le32-le32_t.patch
patches.kernel.org/5.2.2-005-drivers-base-cacheinfo-Ensure-cpu-hotplug-work-.patch
patches.kernel.org/5.2.2-006-firmware-improve-LSM-IMA-security-behaviour.patch
+ patches.kernel.org/5.2.2-007-genirq-Delay-deactivation-in-free_irq.patch
########################################################
# Build fixes that apply to the vanilla kernel too.