Skip to content

Commit 9cab5fb

Browse files
KAGA-KOKObp3tk0v
authored andcommitted
x86/apic: Provide apic_force_nmi_on_cpu()
When SMT siblings are soft-offlined and parked in one of the play_dead() variants they still react on NMI, which is problematic on affected Intel CPUs. The default play_dead() variant uses MWAIT on modern CPUs, which is not guaranteed to be safe when updated concurrently. Right now late loading is prevented when not all SMT siblings are online, but as they still react on NMI, it is possible to bring them out of their park position into a trivial rendezvous handler. Provide a function which allows to do that. I does sanity checks whether the target is in the cpus_booted_once_mask and whether the APIC driver supports it. Mark X2APIC and XAPIC as capable, but exclude 32bit and the UV and NUMACHIP variants as that needs feedback from the relevant experts. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 1582c0f commit 9cab5fb

File tree

5 files changed

+16
-1
lines changed

5 files changed

+16
-1
lines changed

arch/x86/include/asm/apic.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,8 @@ struct apic {
276276

277277
u32 disable_esr : 1,
278278
dest_mode_logical : 1,
279-
x2apic_set_max_apicid : 1;
279+
x2apic_set_max_apicid : 1,
280+
nmi_to_offline_cpu : 1;
280281

281282
u32 (*calc_dest_apicid)(unsigned int cpu);
282283

@@ -542,6 +543,8 @@ extern bool default_check_apicid_used(physid_mask_t *map, int apicid);
542543
extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
543544
extern int default_cpu_present_to_apicid(int mps_cpu);
544545

546+
void apic_send_nmi_to_offline_cpu(unsigned int cpu);
547+
545548
#else /* CONFIG_X86_LOCAL_APIC */
546549

547550
static inline unsigned int read_apic_id(void) { return 0; }

arch/x86/kernel/apic/apic_flat_64.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ static struct apic apic_flat __ro_after_init = {
103103
.send_IPI_allbutself = default_send_IPI_allbutself,
104104
.send_IPI_all = default_send_IPI_all,
105105
.send_IPI_self = default_send_IPI_self,
106+
.nmi_to_offline_cpu = true,
106107

107108
.read = native_apic_mem_read,
108109
.write = native_apic_mem_write,
@@ -175,6 +176,7 @@ static struct apic apic_physflat __ro_after_init = {
175176
.send_IPI_allbutself = default_send_IPI_allbutself,
176177
.send_IPI_all = default_send_IPI_all,
177178
.send_IPI_self = default_send_IPI_self,
179+
.nmi_to_offline_cpu = true,
178180

179181
.read = native_apic_mem_read,
180182
.write = native_apic_mem_write,

arch/x86/kernel/apic/ipi.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,14 @@ void native_send_call_func_ipi(const struct cpumask *mask)
9797
__apic_send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
9898
}
9999

100+
void apic_send_nmi_to_offline_cpu(unsigned int cpu)
101+
{
102+
if (WARN_ON_ONCE(!apic->nmi_to_offline_cpu))
103+
return;
104+
if (WARN_ON_ONCE(!cpumask_test_cpu(cpu, &cpus_booted_once_mask)))
105+
return;
106+
apic->send_IPI(cpu, NMI_VECTOR);
107+
}
100108
#endif /* CONFIG_SMP */
101109

102110
static inline int __prepare_ICR2(unsigned int mask)

arch/x86/kernel/apic/x2apic_cluster.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ static struct apic apic_x2apic_cluster __ro_after_init = {
251251
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
252252
.send_IPI_all = x2apic_send_IPI_all,
253253
.send_IPI_self = x2apic_send_IPI_self,
254+
.nmi_to_offline_cpu = true,
254255

255256
.read = native_apic_msr_read,
256257
.write = native_apic_msr_write,

arch/x86/kernel/apic/x2apic_phys.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ static struct apic apic_x2apic_phys __ro_after_init = {
166166
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
167167
.send_IPI_all = x2apic_send_IPI_all,
168168
.send_IPI_self = x2apic_send_IPI_self,
169+
.nmi_to_offline_cpu = true,
169170

170171
.read = native_apic_msr_read,
171172
.write = native_apic_msr_write,

0 commit comments

Comments
 (0)