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:27 +0200
commit6655654dcf979e159d538c0f322988f498d8d821 (patch)
tree076040abc5608744cd7b6e8204e7a9cb3b6dd9cc
parent1f59201537e9ef3a4179add5c7f4df805cc79f41 (diff)
x86/irq: Seperate unused system vectors from spurious entry
again (bnc#1012628).
-rw-r--r--patches.kernel.org/5.2.2-012-x86-irq-Seperate-unused-system-vectors-from-spu.patch223
-rw-r--r--series.conf1
2 files changed, 224 insertions, 0 deletions
diff --git a/patches.kernel.org/5.2.2-012-x86-irq-Seperate-unused-system-vectors-from-spu.patch b/patches.kernel.org/5.2.2-012-x86-irq-Seperate-unused-system-vectors-from-spu.patch
new file mode 100644
index 0000000000..2c472a0ac7
--- /dev/null
+++ b/patches.kernel.org/5.2.2-012-x86-irq-Seperate-unused-system-vectors-from-spu.patch
@@ -0,0 +1,223 @@
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Fri, 28 Jun 2019 13:11:54 +0200
+Subject: [PATCH] x86/irq: Seperate unused system vectors from spurious entry
+ again
+References: bnc#1012628
+Patch-mainline: 5.2.2
+Git-commit: f8a8fe61fec8006575699559ead88b0b833d5cad
+
+commit f8a8fe61fec8006575699559ead88b0b833d5cad upstream.
+
+Quite some time ago the interrupt entry stubs for unused vectors in the
+system vector range got removed and directly mapped to the spurious
+interrupt vector entry point.
+
+Sounds reasonable, but it's subtly broken. The spurious interrupt vector
+entry point pushes vector number 0xFF on the stack which makes the whole
+logic in __smp_spurious_interrupt() pointless.
+
+As a consequence any spurious interrupt which comes from a vector != 0xFF
+is treated as a real spurious interrupt (vector 0xFF) and not
+acknowledged. That subsequently stalls all interrupt vectors of equal and
+lower priority, which brings the system to a grinding halt.
+
+This can happen because even on 64-bit the system vector space is not
+guaranteed to be fully populated. A full compile time handling of the
+unused vectors is not possible because quite some of them are conditonally
+populated at runtime.
+
+Bring the entry stubs back, which wastes 160 bytes if all stubs are unused,
+but gains the proper handling back. There is no point to selectively spare
+some of the stubs which are known at compile time as the required code in
+the IDT management would be way larger and convoluted.
+
+Do not route the spurious entries through common_interrupt and do_IRQ() as
+the original code did. Route it to smp_spurious_interrupt() which evaluates
+the vector number and acts accordingly now that the real vector numbers are
+handed in.
+
+Fixup the pr_warn so the actual spurious vector (0xff) is clearly
+distiguished from the other vectors and also note for the vectored case
+whether it was pending in the ISR or not.
+
+ "Spurious APIC interrupt (vector 0xFF) on CPU#0, should never happen."
+ "Spurious interrupt vector 0xed on CPU#1. Acked."
+ "Spurious interrupt vector 0xee on CPU#1. Not pending!."
+
+Fixes: 2414e021ac8d ("x86: Avoid building unused IRQ entry stubs")
+Reported-by: Jan Kiszka <jan.kiszka@siemens.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Marc Zyngier <marc.zyngier@arm.com>
+Cc: Jan Beulich <jbeulich@suse.com>
+Link: https://lkml.kernel.org/r/20190628111440.550568228@linutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+---
+ arch/x86/entry/entry_32.S | 24 ++++++++++++++++++++++++
+ arch/x86/entry/entry_64.S | 30 ++++++++++++++++++++++++++----
+ arch/x86/include/asm/hw_irq.h | 2 ++
+ arch/x86/kernel/apic/apic.c | 33 ++++++++++++++++++++++-----------
+ arch/x86/kernel/idt.c | 3 ++-
+ 5 files changed, 76 insertions(+), 16 deletions(-)
+
+diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
+index 7b23431be5cb..44c6e6f54bf7 100644
+--- a/arch/x86/entry/entry_32.S
++++ b/arch/x86/entry/entry_32.S
+@@ -1104,6 +1104,30 @@ ENTRY(irq_entries_start)
+ .endr
+ END(irq_entries_start)
+
++#ifdef CONFIG_X86_LOCAL_APIC
++ .align 8
++ENTRY(spurious_entries_start)
++ vector=FIRST_SYSTEM_VECTOR
++ .rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
++ pushl $(~vector+0x80) /* Note: always in signed byte range */
++ vector=vector+1
++ jmp common_spurious
++ .align 8
++ .endr
++END(spurious_entries_start)
++
++common_spurious:
++ ASM_CLAC
++ addl $-0x80, (%esp) /* Adjust vector into the [-256, -1] range */
++ SAVE_ALL switch_stacks=1
++ ENCODE_FRAME_POINTER
++ TRACE_IRQS_OFF
++ movl %esp, %eax
++ call smp_spurious_interrupt
++ jmp ret_from_intr
++ENDPROC(common_interrupt)
++#endif
++
+ /*
+ * the CPU automatically disables interrupts when executing an IRQ vector,
+ * so IRQ-flags tracing has to follow that:
+diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
+index 11aa3b2afa4d..8dbca86c249b 100644
+--- a/arch/x86/entry/entry_64.S
++++ b/arch/x86/entry/entry_64.S
+@@ -375,6 +375,18 @@ ENTRY(irq_entries_start)
+ .endr
+ END(irq_entries_start)
+
++ .align 8
++ENTRY(spurious_entries_start)
++ vector=FIRST_SYSTEM_VECTOR
++ .rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
++ UNWIND_HINT_IRET_REGS
++ pushq $(~vector+0x80) /* Note: always in signed byte range */
++ jmp common_spurious
++ .align 8
++ vector=vector+1
++ .endr
++END(spurious_entries_start)
++
+ .macro DEBUG_ENTRY_ASSERT_IRQS_OFF
+ #ifdef CONFIG_DEBUG_ENTRY
+ pushq %rax
+@@ -571,10 +583,20 @@ _ASM_NOKPROBE(interrupt_entry)
+
+ /* Interrupt entry/exit. */
+
+- /*
+- * The interrupt stubs push (~vector+0x80) onto the stack and
+- * then jump to common_interrupt.
+- */
++/*
++ * The interrupt stubs push (~vector+0x80) onto the stack and
++ * then jump to common_spurious/interrupt.
++ */
++common_spurious:
++ addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
++ call interrupt_entry
++ UNWIND_HINT_REGS indirect=1
++ call smp_spurious_interrupt /* rdi points to pt_regs */
++ jmp ret_from_intr
++END(common_spurious)
++_ASM_NOKPROBE(common_spurious)
++
++/* common_interrupt is a hotpath. Align it */
+ .p2align CONFIG_X86_L1_CACHE_SHIFT
+ common_interrupt:
+ addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
+diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
+index 626e1ac6516e..cbd97e22d2f3 100644
+--- a/arch/x86/include/asm/hw_irq.h
++++ b/arch/x86/include/asm/hw_irq.h
+@@ -150,6 +150,8 @@ extern char irq_entries_start[];
+ #define trace_irq_entries_start irq_entries_start
+ #endif
+
++extern char spurious_entries_start[];
++
+ #define VECTOR_UNUSED NULL
+ #define VECTOR_SHUTDOWN ((void *)~0UL)
+ #define VECTOR_RETRIGGERED ((void *)~1UL)
+diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
+index 85be316665b4..16c21ed97cb2 100644
+--- a/arch/x86/kernel/apic/apic.c
++++ b/arch/x86/kernel/apic/apic.c
+@@ -2041,21 +2041,32 @@ __visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs)
+ entering_irq();
+ trace_spurious_apic_entry(vector);
+
++ inc_irq_stat(irq_spurious_count);
++
++ /*
++ * If this is a spurious interrupt then do not acknowledge
++ */
++ if (vector == SPURIOUS_APIC_VECTOR) {
++ /* See SDM vol 3 */
++ pr_info("Spurious APIC interrupt (vector 0xFF) on CPU#%d, should never happen.\n",
++ smp_processor_id());
++ goto out;
++ }
++
+ /*
+- * Check if this really is a spurious interrupt and ACK it
+- * if it is a vectored one. Just in case...
+- * Spurious interrupts should not be ACKed.
++ * If it is a vectored one, verify it's set in the ISR. If set,
++ * acknowledge it.
+ */
+ v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
+- if (v & (1 << (vector & 0x1f)))
++ if (v & (1 << (vector & 0x1f))) {
++ pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Acked\n",
++ vector, smp_processor_id());
+ ack_APIC_irq();
+-
+- inc_irq_stat(irq_spurious_count);
+-
+- /* see sw-dev-man vol 3, chapter 7.4.13.5 */
+- pr_info("spurious APIC interrupt through vector %02x on CPU#%d, "
+- "should never happen.\n", vector, smp_processor_id());
+-
++ } else {
++ pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Not pending!\n",
++ vector, smp_processor_id());
++ }
++out:
+ trace_spurious_apic_exit(vector);
+ exiting_irq();
+ }
+diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c
+index d2482bbbe3d0..87ef69a72c52 100644
+--- a/arch/x86/kernel/idt.c
++++ b/arch/x86/kernel/idt.c
+@@ -319,7 +319,8 @@ void __init idt_setup_apic_and_irq_gates(void)
+ #ifdef CONFIG_X86_LOCAL_APIC
+ for_each_clear_bit_from(i, system_vectors, NR_VECTORS) {
+ set_bit(i, system_vectors);
+- set_intr_gate(i, spurious_interrupt);
++ entry = spurious_entries_start + 8 * (i - FIRST_SYSTEM_VECTOR);
++ set_intr_gate(i, entry);
+ }
+ #endif
+ }
+--
+2.22.0
+
diff --git a/series.conf b/series.conf
index fa2e8396ba..b7408ef5ca 100644
--- a/series.conf
+++ b/series.conf
@@ -99,6 +99,7 @@
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
patches.kernel.org/5.2.2-011-x86-irq-Handle-spurious-interrupt-after-shutdow.patch
+ patches.kernel.org/5.2.2-012-x86-irq-Seperate-unused-system-vectors-from-spu.patch
########################################################
# Build fixes that apply to the vanilla kernel too.