Home Home > GIT Browse > stable
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:26 +0200
commitc4ec1ff3d406a900904aa20d751be440363009c8 (patch)
treeb01fbe62c955ff91f2765add75648247bd290392
parent859bdc8388377c26b0d55c9054c48b3d4276dba0 (diff)
x86/ioapic: Implement irq_get_irqchip_state() callback
-rw-r--r--patches.kernel.org/5.2.2-010-x86-ioapic-Implement-irq_get_irqchip_state-call.patch119
-rw-r--r--series.conf1
2 files changed, 120 insertions, 0 deletions
diff --git a/patches.kernel.org/5.2.2-010-x86-ioapic-Implement-irq_get_irqchip_state-call.patch b/patches.kernel.org/5.2.2-010-x86-ioapic-Implement-irq_get_irqchip_state-call.patch
new file mode 100644
index 0000000000..84908669b2
--- /dev/null
+++ b/patches.kernel.org/5.2.2-010-x86-ioapic-Implement-irq_get_irqchip_state-call.patch
@@ -0,0 +1,119 @@
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Fri, 28 Jun 2019 13:11:52 +0200
+Subject: [PATCH] x86/ioapic: Implement irq_get_irqchip_state() callback
+References: bnc#1012628
+Patch-mainline: 5.2.2
+Git-commit: dfe0cf8b51b07e56ded571e3de0a4a9382517231
+
+commit dfe0cf8b51b07e56ded571e3de0a4a9382517231 upstream.
+
+When an interrupt is shut down in free_irq() there might be an inflight
+interrupt pending in the IO-APIC remote IRR which is not yet serviced. That
+means the interrupt has been sent to the target CPUs local APIC, but the
+target CPU is in a state which delays the servicing.
+
+So free_irq() would proceed to free resources and to clear the vector
+because synchronize_hardirq() does not see an interrupt handler in
+progress.
+
+That can trigger a spurious interrupt warning, which is harmless and just
+confuses users, but it also can leave the remote IRR in a stale state
+because once the handler is invoked the interrupt resources might be freed
+already and therefore acknowledgement is not possible anymore.
+
+Implement the irq_get_irqchip_state() callback for the IO-APIC irq chip. The
+callback is invoked from free_irq() via __synchronize_hardirq(). Check the
+remote IRR bit of the interrupt and return 'in flight' if it is set and the
+interrupt is configured in level mode. For edge mode the remote IRR has no
+meaning.
+
+As this is only meaningful for level triggered interrupts this won't cure
+the potential spurious interrupt warning for edge triggered interrupts, but
+the edge trigger case does not result in stale hardware state. This has to
+be addressed at the vector/interrupt entry level seperately.
+
+Fixes: 464d12309e1b ("x86/vector: Switch IOAPIC to global reservation mode")
+Reported-by: Robert Hodaszi <Robert.Hodaszi@digi.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Marc Zyngier <marc.zyngier@arm.com>
+Link: https://lkml.kernel.org/r/20190628111440.370295517@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+---
+ arch/x86/kernel/apic/io_apic.c | 46 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 46 insertions(+)
+
+diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
+index 53aa234a6803..c9fec0657eea 100644
+--- a/arch/x86/kernel/apic/io_apic.c
++++ b/arch/x86/kernel/apic/io_apic.c
+@@ -1893,6 +1893,50 @@ static int ioapic_set_affinity(struct irq_data *irq_data,
+ return ret;
+ }
+
++/*
++ * Interrupt shutdown masks the ioapic pin, but the interrupt might already
++ * be in flight, but not yet serviced by the target CPU. That means
++ * __synchronize_hardirq() would return and claim that everything is calmed
++ * down. So free_irq() would proceed and deactivate the interrupt and free
++ * resources.
++ *
++ * Once the target CPU comes around to service it it will find a cleared
++ * vector and complain. While the spurious interrupt is harmless, the full
++ * release of resources might prevent the interrupt from being acknowledged
++ * which keeps the hardware in a weird state.
++ *
++ * Verify that the corresponding Remote-IRR bits are clear.
++ */
++static int ioapic_irq_get_chip_state(struct irq_data *irqd,
++ enum irqchip_irq_state which,
++ bool *state)
++{
++ struct mp_chip_data *mcd = irqd->chip_data;
++ struct IO_APIC_route_entry rentry;
++ struct irq_pin_list *p;
++
++ if (which != IRQCHIP_STATE_ACTIVE)
++ return -EINVAL;
++
++ *state = false;
++ raw_spin_lock(&ioapic_lock);
++ for_each_irq_pin(p, mcd->irq_2_pin) {
++ rentry = __ioapic_read_entry(p->apic, p->pin);
++ /*
++ * The remote IRR is only valid in level trigger mode. It's
++ * meaning is undefined for edge triggered interrupts and
++ * irrelevant because the IO-APIC treats them as fire and
++ * forget.
++ */
++ if (rentry.irr && rentry.trigger) {
++ *state = true;
++ break;
++ }
++ }
++ raw_spin_unlock(&ioapic_lock);
++ return 0;
++}
++
+ static struct irq_chip ioapic_chip __read_mostly = {
+ .name = "IO-APIC",
+ .irq_startup = startup_ioapic_irq,
+@@ -1902,6 +1946,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
+ .irq_eoi = ioapic_ack_level,
+ .irq_set_affinity = ioapic_set_affinity,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
++ .irq_get_irqchip_state = ioapic_irq_get_chip_state,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+ };
+
+@@ -1914,6 +1959,7 @@ static struct irq_chip ioapic_ir_chip __read_mostly = {
+ .irq_eoi = ioapic_ir_ack_level,
+ .irq_set_affinity = ioapic_set_affinity,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
++ .irq_get_irqchip_state = ioapic_irq_get_chip_state,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+ };
+
+--
+2.22.0
+
diff --git a/series.conf b/series.conf
index 1d37f1b9ed..2b9fb49862 100644
--- a/series.conf
+++ b/series.conf
@@ -97,6 +97,7 @@
patches.kernel.org/5.2.2-007-genirq-Delay-deactivation-in-free_irq.patch
patches.kernel.org/5.2.2-008-genirq-Fix-misleading-synchronize_irq-documenta.patch
patches.kernel.org/5.2.2-009-genirq-Add-optional-hardware-synchronization-fo.patch
+ patches.kernel.org/5.2.2-010-x86-ioapic-Implement-irq_get_irqchip_state-call.patch
########################################################
# Build fixes that apply to the vanilla kernel too.