xref: /openbmc/linux/arch/x86/kernel/apic/ipi.c (revision 0f9b4c3ca5fdf3e177266ef994071b1a03f07318)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2521b82feSThomas Gleixner 
3f62bae50SIngo Molnar #include <linux/cpumask.h>
4e7b6a023SThomas Gleixner #include <linux/delay.h>
5c94f0718SThomas Gleixner #include <linux/smp.h>
6e7b6a023SThomas Gleixner 
713c01139SIngo Molnar #include <asm/io_apic.h>
8f62bae50SIngo Molnar 
9c94f0718SThomas Gleixner #include "local.h"
108b542da3SThomas Gleixner 
116a1cb5f5SThomas Gleixner DEFINE_STATIC_KEY_FALSE(apic_use_ipi_shorthand);
126a1cb5f5SThomas Gleixner 
13bdda3b93SThomas Gleixner #ifdef CONFIG_SMP
141f0ad660SThomas Gleixner static int apic_ipi_shorthand_off __ro_after_init;
15bdda3b93SThomas Gleixner 
apic_ipi_shorthand(char * str)16bdda3b93SThomas Gleixner static __init int apic_ipi_shorthand(char *str)
17bdda3b93SThomas Gleixner {
18bdda3b93SThomas Gleixner 	get_option(&str, &apic_ipi_shorthand_off);
19bdda3b93SThomas Gleixner 	return 1;
20bdda3b93SThomas Gleixner }
21bdda3b93SThomas Gleixner __setup("no_ipi_broadcast=", apic_ipi_shorthand);
22bdda3b93SThomas Gleixner 
print_ipi_mode(void)23bdda3b93SThomas Gleixner static int __init print_ipi_mode(void)
24bdda3b93SThomas Gleixner {
25bdda3b93SThomas Gleixner 	pr_info("IPI shorthand broadcast: %s\n",
26bdda3b93SThomas Gleixner 		apic_ipi_shorthand_off ? "disabled" : "enabled");
27bdda3b93SThomas Gleixner 	return 0;
28bdda3b93SThomas Gleixner }
29bdda3b93SThomas Gleixner late_initcall(print_ipi_mode);
306a1cb5f5SThomas Gleixner 
apic_smt_update(void)316a1cb5f5SThomas Gleixner void apic_smt_update(void)
326a1cb5f5SThomas Gleixner {
336a1cb5f5SThomas Gleixner 	/*
346a1cb5f5SThomas Gleixner 	 * Do not switch to broadcast mode if:
356a1cb5f5SThomas Gleixner 	 * - Disabled on the command line
366a1cb5f5SThomas Gleixner 	 * - Only a single CPU is online
376a1cb5f5SThomas Gleixner 	 * - Not all present CPUs have been at least booted once
386a1cb5f5SThomas Gleixner 	 *
396a1cb5f5SThomas Gleixner 	 * The latter is important as the local APIC might be in some
406a1cb5f5SThomas Gleixner 	 * random state and a broadcast might cause havoc. That's
416a1cb5f5SThomas Gleixner 	 * especially true for NMI broadcasting.
426a1cb5f5SThomas Gleixner 	 */
436a1cb5f5SThomas Gleixner 	if (apic_ipi_shorthand_off || num_online_cpus() == 1 ||
446a1cb5f5SThomas Gleixner 	    !cpumask_equal(cpu_present_mask, &cpus_booted_once_mask)) {
456a1cb5f5SThomas Gleixner 		static_branch_disable(&apic_use_ipi_shorthand);
466a1cb5f5SThomas Gleixner 	} else {
476a1cb5f5SThomas Gleixner 		static_branch_enable(&apic_use_ipi_shorthand);
486a1cb5f5SThomas Gleixner 	}
496a1cb5f5SThomas Gleixner }
5022ca7ee9SThomas Gleixner 
apic_send_IPI_allbutself(unsigned int vector)5122ca7ee9SThomas Gleixner void apic_send_IPI_allbutself(unsigned int vector)
5222ca7ee9SThomas Gleixner {
5322ca7ee9SThomas Gleixner 	if (num_online_cpus() < 2)
5422ca7ee9SThomas Gleixner 		return;
5522ca7ee9SThomas Gleixner 
5622ca7ee9SThomas Gleixner 	if (static_branch_likely(&apic_use_ipi_shorthand))
5728b82352SDave Hansen 		__apic_send_IPI_allbutself(vector);
5822ca7ee9SThomas Gleixner 	else
5928b82352SDave Hansen 		__apic_send_IPI_mask_allbutself(cpu_online_mask, vector);
6022ca7ee9SThomas Gleixner }
6122ca7ee9SThomas Gleixner 
62d0a7166bSThomas Gleixner /*
63d0a7166bSThomas Gleixner  * Send a 'reschedule' IPI to another CPU. It goes straight through and
64d0a7166bSThomas Gleixner  * wastes no time serializing anything. Worst case is that we lose a
65d0a7166bSThomas Gleixner  * reschedule ...
66d0a7166bSThomas Gleixner  */
native_smp_send_reschedule(int cpu)67d0a7166bSThomas Gleixner void native_smp_send_reschedule(int cpu)
68d0a7166bSThomas Gleixner {
69d0a7166bSThomas Gleixner 	if (unlikely(cpu_is_offline(cpu))) {
70d0a7166bSThomas Gleixner 		WARN(1, "sched: Unexpected reschedule of offline CPU#%d!\n", cpu);
71d0a7166bSThomas Gleixner 		return;
72d0a7166bSThomas Gleixner 	}
7328b82352SDave Hansen 	__apic_send_IPI(cpu, RESCHEDULE_VECTOR);
74d0a7166bSThomas Gleixner }
75d0a7166bSThomas Gleixner 
native_send_call_func_single_ipi(int cpu)76d0a7166bSThomas Gleixner void native_send_call_func_single_ipi(int cpu)
77d0a7166bSThomas Gleixner {
7828b82352SDave Hansen 	__apic_send_IPI(cpu, CALL_FUNCTION_SINGLE_VECTOR);
79d0a7166bSThomas Gleixner }
80d0a7166bSThomas Gleixner 
native_send_call_func_ipi(const struct cpumask * mask)81d0a7166bSThomas Gleixner void native_send_call_func_ipi(const struct cpumask *mask)
82d0a7166bSThomas Gleixner {
83832df3d4SThomas Gleixner 	if (static_branch_likely(&apic_use_ipi_shorthand)) {
84832df3d4SThomas Gleixner 		unsigned int cpu = smp_processor_id();
85d0a7166bSThomas Gleixner 
86832df3d4SThomas Gleixner 		if (!cpumask_or_equal(mask, cpumask_of(cpu), cpu_online_mask))
87832df3d4SThomas Gleixner 			goto sendmask;
88832df3d4SThomas Gleixner 
89832df3d4SThomas Gleixner 		if (cpumask_test_cpu(cpu, mask))
9028b82352SDave Hansen 			__apic_send_IPI_all(CALL_FUNCTION_VECTOR);
91832df3d4SThomas Gleixner 		else if (num_online_cpus() > 1)
9228b82352SDave Hansen 			__apic_send_IPI_allbutself(CALL_FUNCTION_VECTOR);
93d0a7166bSThomas Gleixner 		return;
94d0a7166bSThomas Gleixner 	}
95d0a7166bSThomas Gleixner 
96832df3d4SThomas Gleixner sendmask:
9728b82352SDave Hansen 	__apic_send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
98d0a7166bSThomas Gleixner }
99d0a7166bSThomas Gleixner 
apic_send_nmi_to_offline_cpu(unsigned int cpu)100*8390133dSThomas Gleixner void apic_send_nmi_to_offline_cpu(unsigned int cpu)
101*8390133dSThomas Gleixner {
102*8390133dSThomas Gleixner 	if (WARN_ON_ONCE(!apic->nmi_to_offline_cpu))
103*8390133dSThomas Gleixner 		return;
104*8390133dSThomas Gleixner 	if (WARN_ON_ONCE(!cpumask_test_cpu(cpu, &cpus_booted_once_mask)))
105*8390133dSThomas Gleixner 		return;
106*8390133dSThomas Gleixner 	apic->send_IPI(cpu, NMI_VECTOR);
107*8390133dSThomas Gleixner }
1086a1cb5f5SThomas Gleixner #endif /* CONFIG_SMP */
109bdda3b93SThomas Gleixner 
__prepare_ICR2(unsigned int mask)110c94f0718SThomas Gleixner static inline int __prepare_ICR2(unsigned int mask)
111c94f0718SThomas Gleixner {
112bf348f66SSuravee Suthikulpanit 	return SET_XAPIC_DEST_FIELD(mask);
113c94f0718SThomas Gleixner }
114c94f0718SThomas Gleixner 
apic_mem_wait_icr_idle_timeout(void)115e7b6a023SThomas Gleixner u32 apic_mem_wait_icr_idle_timeout(void)
116e7b6a023SThomas Gleixner {
117e7b6a023SThomas Gleixner 	int cnt;
118e7b6a023SThomas Gleixner 
119e7b6a023SThomas Gleixner 	for (cnt = 0; cnt < 1000; cnt++) {
120e7b6a023SThomas Gleixner 		if (!(apic_read(APIC_ICR) & APIC_ICR_BUSY))
121e7b6a023SThomas Gleixner 			return 0;
122e7b6a023SThomas Gleixner 		inc_irq_stat(icr_read_retry_count);
123e7b6a023SThomas Gleixner 		udelay(100);
124e7b6a023SThomas Gleixner 	}
125e7b6a023SThomas Gleixner 	return APIC_ICR_BUSY;
126e7b6a023SThomas Gleixner }
127e7b6a023SThomas Gleixner 
apic_mem_wait_icr_idle(void)128cfebd007SThomas Gleixner void apic_mem_wait_icr_idle(void)
129c94f0718SThomas Gleixner {
130c94f0718SThomas Gleixner 	while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY)
131c94f0718SThomas Gleixner 		cpu_relax();
132c94f0718SThomas Gleixner }
133f62bae50SIngo Molnar 
13401363d4fSThomas Gleixner /*
13501363d4fSThomas Gleixner  * This is safe against interruption because it only writes the lower 32
13601363d4fSThomas Gleixner  * bits of the APIC_ICR register. The destination field is ignored for
13701363d4fSThomas Gleixner  * short hand IPIs.
13801363d4fSThomas Gleixner  *
13901363d4fSThomas Gleixner  *  wait_icr_idle()
14001363d4fSThomas Gleixner  *  write(ICR2, dest)
14101363d4fSThomas Gleixner  *  NMI
14201363d4fSThomas Gleixner  *	wait_icr_idle()
14301363d4fSThomas Gleixner  *	write(ICR)
14401363d4fSThomas Gleixner  *	wait_icr_idle()
14501363d4fSThomas Gleixner  *  write(ICR)
14601363d4fSThomas Gleixner  *
14701363d4fSThomas Gleixner  * This function does not need to disable interrupts as there is no ICR2
14801363d4fSThomas Gleixner  * interaction. The memory write is direct except when the machine is
14901363d4fSThomas Gleixner  * affected by the 11AP Pentium erratum, which turns the plain write into
15001363d4fSThomas Gleixner  * an XCHG operation.
15101363d4fSThomas Gleixner  */
__default_send_IPI_shortcut(unsigned int shortcut,int vector)15201363d4fSThomas Gleixner static void __default_send_IPI_shortcut(unsigned int shortcut, int vector)
1531a8aa8acSDenys Vlasenko {
1541a8aa8acSDenys Vlasenko 	/*
15501363d4fSThomas Gleixner 	 * Wait for the previous ICR command to complete.  Use
15601363d4fSThomas Gleixner 	 * safe_apic_wait_icr_idle() for the NMI vector as there have been
15701363d4fSThomas Gleixner 	 * issues where otherwise the system hangs when the panic CPU tries
15801363d4fSThomas Gleixner 	 * to stop the others before launching the kdump kernel.
1591a8aa8acSDenys Vlasenko 	 */
160bd82dba2SThomas Gleixner 	if (unlikely(vector == NMI_VECTOR))
161e7b6a023SThomas Gleixner 		apic_mem_wait_icr_idle_timeout();
162bd82dba2SThomas Gleixner 	else
163cfebd007SThomas Gleixner 		apic_mem_wait_icr_idle();
1641a8aa8acSDenys Vlasenko 
16501363d4fSThomas Gleixner 	/* Destination field (ICR2) and the destination mode are ignored */
16601363d4fSThomas Gleixner 	native_apic_mem_write(APIC_ICR, __prepare_ICR(shortcut, vector, 0));
1671a8aa8acSDenys Vlasenko }
1681a8aa8acSDenys Vlasenko 
1691a8aa8acSDenys Vlasenko /*
1701a8aa8acSDenys Vlasenko  * This is used to send an IPI with no shorthand notation (the destination is
1711a8aa8acSDenys Vlasenko  * specified in bits 56 to 63 of the ICR).
1721a8aa8acSDenys Vlasenko  */
__default_send_IPI_dest_field(unsigned int dest_mask,int vector,unsigned int dest_mode)17301363d4fSThomas Gleixner void __default_send_IPI_dest_field(unsigned int dest_mask, int vector,
17401363d4fSThomas Gleixner 				   unsigned int dest_mode)
1751a8aa8acSDenys Vlasenko {
17601363d4fSThomas Gleixner 	/* See comment in __default_send_IPI_shortcut() */
1771a8aa8acSDenys Vlasenko 	if (unlikely(vector == NMI_VECTOR))
178e7b6a023SThomas Gleixner 		apic_mem_wait_icr_idle_timeout();
1791a8aa8acSDenys Vlasenko 	else
180cfebd007SThomas Gleixner 		apic_mem_wait_icr_idle();
1811a8aa8acSDenys Vlasenko 
18201363d4fSThomas Gleixner 	/* Set the IPI destination field in the ICR */
18301363d4fSThomas Gleixner 	native_apic_mem_write(APIC_ICR2, __prepare_ICR2(dest_mask));
18401363d4fSThomas Gleixner 	/* Send it with the proper destination mode */
18501363d4fSThomas Gleixner 	native_apic_mem_write(APIC_ICR, __prepare_ICR(0, vector, dest_mode));
1861a8aa8acSDenys Vlasenko }
1871a8aa8acSDenys Vlasenko 
default_send_IPI_single_phys(int cpu,int vector)18853be0facSThomas Gleixner void default_send_IPI_single_phys(int cpu, int vector)
18953be0facSThomas Gleixner {
19053be0facSThomas Gleixner 	unsigned long flags;
19153be0facSThomas Gleixner 
19253be0facSThomas Gleixner 	local_irq_save(flags);
19353be0facSThomas Gleixner 	__default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, cpu),
19453be0facSThomas Gleixner 				      vector, APIC_DEST_PHYSICAL);
19553be0facSThomas Gleixner 	local_irq_restore(flags);
19653be0facSThomas Gleixner }
19753be0facSThomas Gleixner 
default_send_IPI_mask_sequence_phys(const struct cpumask * mask,int vector)198f62bae50SIngo Molnar void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector)
199f62bae50SIngo Molnar {
200f62bae50SIngo Molnar 	unsigned long flags;
201ec9fb3c5SThomas Gleixner 	unsigned long cpu;
202f62bae50SIngo Molnar 
203f62bae50SIngo Molnar 	local_irq_save(flags);
204ec9fb3c5SThomas Gleixner 	for_each_cpu(cpu, mask) {
205f62bae50SIngo Molnar 		__default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid,
206ec9fb3c5SThomas Gleixner 				cpu), vector, APIC_DEST_PHYSICAL);
207f62bae50SIngo Molnar 	}
208f62bae50SIngo Molnar 	local_irq_restore(flags);
209f62bae50SIngo Molnar }
210f62bae50SIngo Molnar 
default_send_IPI_mask_allbutself_phys(const struct cpumask * mask,int vector)211f62bae50SIngo Molnar void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
212f62bae50SIngo Molnar 						 int vector)
213f62bae50SIngo Molnar {
214ec9fb3c5SThomas Gleixner 	unsigned int cpu, this_cpu = smp_processor_id();
215f62bae50SIngo Molnar 	unsigned long flags;
216f62bae50SIngo Molnar 
217f62bae50SIngo Molnar 	local_irq_save(flags);
218ec9fb3c5SThomas Gleixner 	for_each_cpu(cpu, mask) {
219ec9fb3c5SThomas Gleixner 		if (cpu == this_cpu)
220f62bae50SIngo Molnar 			continue;
221f62bae50SIngo Molnar 		__default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid,
222ec9fb3c5SThomas Gleixner 				 cpu), vector, APIC_DEST_PHYSICAL);
223f62bae50SIngo Molnar 	}
224f62bae50SIngo Molnar 	local_irq_restore(flags);
225f62bae50SIngo Molnar }
226f62bae50SIngo Molnar 
2277e29393bSThomas Gleixner /*
2287e29393bSThomas Gleixner  * Helper function for APICs which insist on cpumasks
2297e29393bSThomas Gleixner  */
default_send_IPI_single(int cpu,int vector)2307e29393bSThomas Gleixner void default_send_IPI_single(int cpu, int vector)
2317e29393bSThomas Gleixner {
23228b82352SDave Hansen 	__apic_send_IPI_mask(cpumask_of(cpu), vector);
2337e29393bSThomas Gleixner }
2347e29393bSThomas Gleixner 
default_send_IPI_allbutself(int vector)235dea97863SThomas Gleixner void default_send_IPI_allbutself(int vector)
236dea97863SThomas Gleixner {
237dea97863SThomas Gleixner 	__default_send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
238dea97863SThomas Gleixner }
239dea97863SThomas Gleixner 
default_send_IPI_all(int vector)240dea97863SThomas Gleixner void default_send_IPI_all(int vector)
241dea97863SThomas Gleixner {
242dea97863SThomas Gleixner 	__default_send_IPI_shortcut(APIC_DEST_ALLINC, vector);
243dea97863SThomas Gleixner }
244dea97863SThomas Gleixner 
default_send_IPI_self(int vector)245dea97863SThomas Gleixner void default_send_IPI_self(int vector)
246dea97863SThomas Gleixner {
247dea97863SThomas Gleixner 	__default_send_IPI_shortcut(APIC_DEST_SELF, vector);
248dea97863SThomas Gleixner }
249dea97863SThomas Gleixner 
2501245e166STejun Heo #ifdef CONFIG_X86_32
default_send_IPI_mask_sequence_logical(const struct cpumask * mask,int vector)251f2bb0b4fSThomas Gleixner void default_send_IPI_mask_sequence_logical(const struct cpumask *mask, int vector)
252f62bae50SIngo Molnar {
253f62bae50SIngo Molnar 	unsigned long flags;
254f2bb0b4fSThomas Gleixner 	unsigned int cpu;
255f62bae50SIngo Molnar 
256f62bae50SIngo Molnar 	local_irq_save(flags);
257f2bb0b4fSThomas Gleixner 	for_each_cpu(cpu, mask)
258f2bb0b4fSThomas Gleixner 		__default_send_IPI_dest_field(1U << cpu, vector, APIC_DEST_LOGICAL);
259f62bae50SIngo Molnar 	local_irq_restore(flags);
260f62bae50SIngo Molnar }
261f62bae50SIngo Molnar 
default_send_IPI_mask_allbutself_logical(const struct cpumask * mask,int vector)262f62bae50SIngo Molnar void default_send_IPI_mask_allbutself_logical(const struct cpumask *mask,
263f62bae50SIngo Molnar 						 int vector)
264f62bae50SIngo Molnar {
265f2bb0b4fSThomas Gleixner 	unsigned int cpu, this_cpu = smp_processor_id();
266f62bae50SIngo Molnar 	unsigned long flags;
267f62bae50SIngo Molnar 
268f62bae50SIngo Molnar 	local_irq_save(flags);
269f2bb0b4fSThomas Gleixner 	for_each_cpu(cpu, mask) {
270f2bb0b4fSThomas Gleixner 		if (cpu == this_cpu)
271f62bae50SIngo Molnar 			continue;
272f2bb0b4fSThomas Gleixner 		__default_send_IPI_dest_field(1U << cpu, vector, APIC_DEST_LOGICAL);
273f62bae50SIngo Molnar 	}
274f62bae50SIngo Molnar 	local_irq_restore(flags);
275f62bae50SIngo Molnar }
276f62bae50SIngo Molnar 
default_send_IPI_mask_logical(const struct cpumask * cpumask,int vector)277f62bae50SIngo Molnar void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector)
278f62bae50SIngo Molnar {
279f62bae50SIngo Molnar 	unsigned long mask = cpumask_bits(cpumask)[0];
280f62bae50SIngo Molnar 	unsigned long flags;
281f62bae50SIngo Molnar 
282e3f0f36dSDave Jones 	if (!mask)
28383d349f3SLinus Torvalds 		return;
28483d349f3SLinus Torvalds 
285f62bae50SIngo Molnar 	local_irq_save(flags);
286f62bae50SIngo Molnar 	WARN_ON(mask & ~cpumask_bits(cpu_online_mask)[0]);
28722e0db42SThomas Gleixner 	__default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
288f62bae50SIngo Molnar 	local_irq_restore(flags);
289f62bae50SIngo Molnar }
290f62bae50SIngo Molnar 
291ac1c6283SArnd Bergmann #ifdef CONFIG_SMP
convert_apicid_to_cpu(int apic_id)292f62bae50SIngo Molnar static int convert_apicid_to_cpu(int apic_id)
293f62bae50SIngo Molnar {
294f62bae50SIngo Molnar 	int i;
295f62bae50SIngo Molnar 
296f62bae50SIngo Molnar 	for_each_possible_cpu(i) {
297f62bae50SIngo Molnar 		if (per_cpu(x86_cpu_to_apicid, i) == apic_id)
298f62bae50SIngo Molnar 			return i;
299f62bae50SIngo Molnar 	}
300f62bae50SIngo Molnar 	return -1;
301f62bae50SIngo Molnar }
302f62bae50SIngo Molnar 
safe_smp_processor_id(void)303f62bae50SIngo Molnar int safe_smp_processor_id(void)
304f62bae50SIngo Molnar {
305f62bae50SIngo Molnar 	int apicid, cpuid;
306f62bae50SIngo Molnar 
30793984fbdSBorislav Petkov 	if (!boot_cpu_has(X86_FEATURE_APIC))
308f62bae50SIngo Molnar 		return 0;
309f62bae50SIngo Molnar 
310a6625b47SThomas Gleixner 	apicid = read_apic_id();
311f62bae50SIngo Molnar 	if (apicid == BAD_APICID)
312f62bae50SIngo Molnar 		return 0;
313f62bae50SIngo Molnar 
314f62bae50SIngo Molnar 	cpuid = convert_apicid_to_cpu(apicid);
315f62bae50SIngo Molnar 
316f62bae50SIngo Molnar 	return cpuid >= 0 ? cpuid : 0;
317f62bae50SIngo Molnar }
318f62bae50SIngo Molnar #endif
319ac1c6283SArnd Bergmann #endif
320