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