diff options
-rw-r--r-- | arch/x86/include/asm/apic.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/apic/ipi.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/apic/local.h | 6 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 2 |
4 files changed, 33 insertions, 1 deletions
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index cae7e0d02476..4a0d349ab44d 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -505,8 +505,10 @@ extern int default_check_phys_apicid_present(int phys_apicid); #ifdef CONFIG_SMP bool apic_id_is_primary_thread(unsigned int id); +void apic_smt_update(void); #else static inline bool apic_id_is_primary_thread(unsigned int id) { return false; } +static inline void apic_smt_update(void) { } #endif extern void irq_enter(void); diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c index ca3bcdb7c4a8..5bd8a001a887 100644 --- a/arch/x86/kernel/apic/ipi.c +++ b/arch/x86/kernel/apic/ipi.c @@ -5,6 +5,8 @@ #include "local.h" +DEFINE_STATIC_KEY_FALSE(apic_use_ipi_shorthand); + #ifdef CONFIG_SMP #ifdef CONFIG_HOTPLUG_CPU #define DEFAULT_SEND_IPI (1) @@ -28,7 +30,27 @@ static int __init print_ipi_mode(void) return 0; } late_initcall(print_ipi_mode); -#endif + +void apic_smt_update(void) +{ + /* + * Do not switch to broadcast mode if: + * - Disabled on the command line + * - Only a single CPU is online + * - Not all present CPUs have been at least booted once + * + * The latter is important as the local APIC might be in some + * random state and a broadcast might cause havoc. That's + * especially true for NMI broadcasting. + */ + if (apic_ipi_shorthand_off || num_online_cpus() == 1 || + !cpumask_equal(cpu_present_mask, &cpus_booted_once_mask)) { + static_branch_disable(&apic_use_ipi_shorthand); + } else { + static_branch_enable(&apic_use_ipi_shorthand); + } +} +#endif /* CONFIG_SMP */ static inline int __prepare_ICR2(unsigned int mask) { diff --git a/arch/x86/kernel/apic/local.h b/arch/x86/kernel/apic/local.h index bd074e5997b0..391594cd5ca9 100644 --- a/arch/x86/kernel/apic/local.h +++ b/arch/x86/kernel/apic/local.h @@ -7,6 +7,9 @@ * (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com> * (c) 2002,2003 Andi Kleen, SuSE Labs. */ + +#include <linux/jump_label.h> + #include <asm/apic.h> /* APIC flat 64 */ @@ -22,6 +25,9 @@ int x2apic_phys_pkg_id(int initial_apicid, int index_msb); void x2apic_send_IPI_self(int vector); /* IPI */ + +DECLARE_STATIC_KEY_FALSE(apic_use_ipi_shorthand); + static inline unsigned int __prepare_ICR(unsigned int shortcut, int vector, unsigned int dest) { diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 1ee6598c5d83..e0489d2860d3 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1953,4 +1953,6 @@ void arch_smt_update(void) { /* Handle the speculative execution misfeatures */ cpu_bugs_smt_update(); + /* Check whether IPI broadcasting can be enabled */ + apic_smt_update(); } |