Skip to content

Commit 6a1cb5f

Browse files
committed
x86/apic: Add static key to Control IPI shorthands
The IPI shorthand functionality delivers IPI/NMI broadcasts to all CPUs in the system. This can have similar side effects as the MCE broadcasting when CPUs are waiting in the BIOS or are offlined. The kernel tracks already the state of offlined CPUs whether they have been brought up at least once so that the CR4 MCE bit is set to make sure that MCE broadcasts can't brick the machine. Utilize that information and compare it to the cpu_present_mask. If all present CPUs have been brought up at least once then the broadcast side effect is mitigated by disabling regular interrupt/IPI delivery in the APIC itself and by the cpu offline check at the begin of the NMI handler. Use a static key to switch between broadcasting via shorthands or sending the IPI/NMI one by one. Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent bdda3b9 commit 6a1cb5f

File tree

4 files changed

+33
-1
lines changed

4 files changed

+33
-1
lines changed

arch/x86/include/asm/apic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,8 +505,10 @@ extern int default_check_phys_apicid_present(int phys_apicid);
505505

506506
#ifdef CONFIG_SMP
507507
bool apic_id_is_primary_thread(unsigned int id);
508+
void apic_smt_update(void);
508509
#else
509510
static inline bool apic_id_is_primary_thread(unsigned int id) { return false; }
511+
static inline void apic_smt_update(void) { }
510512
#endif
511513

512514
extern void irq_enter(void);

arch/x86/kernel/apic/ipi.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#include "local.h"
77

8+
DEFINE_STATIC_KEY_FALSE(apic_use_ipi_shorthand);
9+
810
#ifdef CONFIG_SMP
911
#ifdef CONFIG_HOTPLUG_CPU
1012
#define DEFAULT_SEND_IPI (1)
@@ -28,7 +30,27 @@ static int __init print_ipi_mode(void)
2830
return 0;
2931
}
3032
late_initcall(print_ipi_mode);
31-
#endif
33+
34+
void apic_smt_update(void)
35+
{
36+
/*
37+
* Do not switch to broadcast mode if:
38+
* - Disabled on the command line
39+
* - Only a single CPU is online
40+
* - Not all present CPUs have been at least booted once
41+
*
42+
* The latter is important as the local APIC might be in some
43+
* random state and a broadcast might cause havoc. That's
44+
* especially true for NMI broadcasting.
45+
*/
46+
if (apic_ipi_shorthand_off || num_online_cpus() == 1 ||
47+
!cpumask_equal(cpu_present_mask, &cpus_booted_once_mask)) {
48+
static_branch_disable(&apic_use_ipi_shorthand);
49+
} else {
50+
static_branch_enable(&apic_use_ipi_shorthand);
51+
}
52+
}
53+
#endif /* CONFIG_SMP */
3254

3355
static inline int __prepare_ICR2(unsigned int mask)
3456
{

arch/x86/kernel/apic/local.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* (c) 1998-99, 2000 Ingo Molnar <[email protected]>
88
* (c) 2002,2003 Andi Kleen, SuSE Labs.
99
*/
10+
11+
#include <linux/jump_label.h>
12+
1013
#include <asm/apic.h>
1114

1215
/* APIC flat 64 */
@@ -22,6 +25,9 @@ int x2apic_phys_pkg_id(int initial_apicid, int index_msb);
2225
void x2apic_send_IPI_self(int vector);
2326

2427
/* IPI */
28+
29+
DECLARE_STATIC_KEY_FALSE(apic_use_ipi_shorthand);
30+
2531
static inline unsigned int __prepare_ICR(unsigned int shortcut, int vector,
2632
unsigned int dest)
2733
{

arch/x86/kernel/cpu/common.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,4 +1953,6 @@ void arch_smt_update(void)
19531953
{
19541954
/* Handle the speculative execution misfeatures */
19551955
cpu_bugs_smt_update();
1956+
/* Check whether IPI broadcasting can be enabled */
1957+
apic_smt_update();
19561958
}

0 commit comments

Comments
 (0)