162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/cpumask.h> 462306a36Sopenharmony_ci#include <linux/delay.h> 562306a36Sopenharmony_ci#include <linux/smp.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <asm/io_apic.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "local.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(apic_use_ipi_shorthand); 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#ifdef CONFIG_SMP 1462306a36Sopenharmony_cistatic int apic_ipi_shorthand_off __ro_after_init; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic __init int apic_ipi_shorthand(char *str) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci get_option(&str, &apic_ipi_shorthand_off); 1962306a36Sopenharmony_ci return 1; 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci__setup("no_ipi_broadcast=", apic_ipi_shorthand); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic int __init print_ipi_mode(void) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci pr_info("IPI shorthand broadcast: %s\n", 2662306a36Sopenharmony_ci apic_ipi_shorthand_off ? "disabled" : "enabled"); 2762306a36Sopenharmony_ci return 0; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_cilate_initcall(print_ipi_mode); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_civoid apic_smt_update(void) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci /* 3462306a36Sopenharmony_ci * Do not switch to broadcast mode if: 3562306a36Sopenharmony_ci * - Disabled on the command line 3662306a36Sopenharmony_ci * - Only a single CPU is online 3762306a36Sopenharmony_ci * - Not all present CPUs have been at least booted once 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * The latter is important as the local APIC might be in some 4062306a36Sopenharmony_ci * random state and a broadcast might cause havoc. That's 4162306a36Sopenharmony_ci * especially true for NMI broadcasting. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci if (apic_ipi_shorthand_off || num_online_cpus() == 1 || 4462306a36Sopenharmony_ci !cpumask_equal(cpu_present_mask, &cpus_booted_once_mask)) { 4562306a36Sopenharmony_ci static_branch_disable(&apic_use_ipi_shorthand); 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci static_branch_enable(&apic_use_ipi_shorthand); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid apic_send_IPI_allbutself(unsigned int vector) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci if (num_online_cpus() < 2) 5462306a36Sopenharmony_ci return; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (static_branch_likely(&apic_use_ipi_shorthand)) 5762306a36Sopenharmony_ci __apic_send_IPI_allbutself(vector); 5862306a36Sopenharmony_ci else 5962306a36Sopenharmony_ci __apic_send_IPI_mask_allbutself(cpu_online_mask, vector); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * Send a 'reschedule' IPI to another CPU. It goes straight through and 6462306a36Sopenharmony_ci * wastes no time serializing anything. Worst case is that we lose a 6562306a36Sopenharmony_ci * reschedule ... 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_civoid native_smp_send_reschedule(int cpu) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci if (unlikely(cpu_is_offline(cpu))) { 7062306a36Sopenharmony_ci WARN(1, "sched: Unexpected reschedule of offline CPU#%d!\n", cpu); 7162306a36Sopenharmony_ci return; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci __apic_send_IPI(cpu, RESCHEDULE_VECTOR); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_civoid native_send_call_func_single_ipi(int cpu) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci __apic_send_IPI(cpu, CALL_FUNCTION_SINGLE_VECTOR); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_civoid native_send_call_func_ipi(const struct cpumask *mask) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci if (static_branch_likely(&apic_use_ipi_shorthand)) { 8462306a36Sopenharmony_ci unsigned int cpu = smp_processor_id(); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!cpumask_or_equal(mask, cpumask_of(cpu), cpu_online_mask)) 8762306a36Sopenharmony_ci goto sendmask; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (cpumask_test_cpu(cpu, mask)) 9062306a36Sopenharmony_ci __apic_send_IPI_all(CALL_FUNCTION_VECTOR); 9162306a36Sopenharmony_ci else if (num_online_cpus() > 1) 9262306a36Sopenharmony_ci __apic_send_IPI_allbutself(CALL_FUNCTION_VECTOR); 9362306a36Sopenharmony_ci return; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cisendmask: 9762306a36Sopenharmony_ci __apic_send_IPI_mask(mask, CALL_FUNCTION_VECTOR); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#endif /* CONFIG_SMP */ 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline int __prepare_ICR2(unsigned int mask) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return SET_XAPIC_DEST_FIELD(mask); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciu32 apic_mem_wait_icr_idle_timeout(void) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci int cnt; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci for (cnt = 0; cnt < 1000; cnt++) { 11262306a36Sopenharmony_ci if (!(apic_read(APIC_ICR) & APIC_ICR_BUSY)) 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci inc_irq_stat(icr_read_retry_count); 11562306a36Sopenharmony_ci udelay(100); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci return APIC_ICR_BUSY; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_civoid apic_mem_wait_icr_idle(void) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci while (native_apic_mem_read(APIC_ICR) & APIC_ICR_BUSY) 12362306a36Sopenharmony_ci cpu_relax(); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * This is safe against interruption because it only writes the lower 32 12862306a36Sopenharmony_ci * bits of the APIC_ICR register. The destination field is ignored for 12962306a36Sopenharmony_ci * short hand IPIs. 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * wait_icr_idle() 13262306a36Sopenharmony_ci * write(ICR2, dest) 13362306a36Sopenharmony_ci * NMI 13462306a36Sopenharmony_ci * wait_icr_idle() 13562306a36Sopenharmony_ci * write(ICR) 13662306a36Sopenharmony_ci * wait_icr_idle() 13762306a36Sopenharmony_ci * write(ICR) 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * This function does not need to disable interrupts as there is no ICR2 14062306a36Sopenharmony_ci * interaction. The memory write is direct except when the machine is 14162306a36Sopenharmony_ci * affected by the 11AP Pentium erratum, which turns the plain write into 14262306a36Sopenharmony_ci * an XCHG operation. 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_cistatic void __default_send_IPI_shortcut(unsigned int shortcut, int vector) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Wait for the previous ICR command to complete. Use 14862306a36Sopenharmony_ci * safe_apic_wait_icr_idle() for the NMI vector as there have been 14962306a36Sopenharmony_ci * issues where otherwise the system hangs when the panic CPU tries 15062306a36Sopenharmony_ci * to stop the others before launching the kdump kernel. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci if (unlikely(vector == NMI_VECTOR)) 15362306a36Sopenharmony_ci apic_mem_wait_icr_idle_timeout(); 15462306a36Sopenharmony_ci else 15562306a36Sopenharmony_ci apic_mem_wait_icr_idle(); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Destination field (ICR2) and the destination mode are ignored */ 15862306a36Sopenharmony_ci native_apic_mem_write(APIC_ICR, __prepare_ICR(shortcut, vector, 0)); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * This is used to send an IPI with no shorthand notation (the destination is 16362306a36Sopenharmony_ci * specified in bits 56 to 63 of the ICR). 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_civoid __default_send_IPI_dest_field(unsigned int dest_mask, int vector, 16662306a36Sopenharmony_ci unsigned int dest_mode) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci /* See comment in __default_send_IPI_shortcut() */ 16962306a36Sopenharmony_ci if (unlikely(vector == NMI_VECTOR)) 17062306a36Sopenharmony_ci apic_mem_wait_icr_idle_timeout(); 17162306a36Sopenharmony_ci else 17262306a36Sopenharmony_ci apic_mem_wait_icr_idle(); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Set the IPI destination field in the ICR */ 17562306a36Sopenharmony_ci native_apic_mem_write(APIC_ICR2, __prepare_ICR2(dest_mask)); 17662306a36Sopenharmony_ci /* Send it with the proper destination mode */ 17762306a36Sopenharmony_ci native_apic_mem_write(APIC_ICR, __prepare_ICR(0, vector, dest_mode)); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_civoid default_send_IPI_single_phys(int cpu, int vector) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci unsigned long flags; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci local_irq_save(flags); 18562306a36Sopenharmony_ci __default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, cpu), 18662306a36Sopenharmony_ci vector, APIC_DEST_PHYSICAL); 18762306a36Sopenharmony_ci local_irq_restore(flags); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_civoid default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci unsigned long flags; 19362306a36Sopenharmony_ci unsigned long cpu; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci local_irq_save(flags); 19662306a36Sopenharmony_ci for_each_cpu(cpu, mask) { 19762306a36Sopenharmony_ci __default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, 19862306a36Sopenharmony_ci cpu), vector, APIC_DEST_PHYSICAL); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci local_irq_restore(flags); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_civoid default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, 20462306a36Sopenharmony_ci int vector) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci unsigned int cpu, this_cpu = smp_processor_id(); 20762306a36Sopenharmony_ci unsigned long flags; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci local_irq_save(flags); 21062306a36Sopenharmony_ci for_each_cpu(cpu, mask) { 21162306a36Sopenharmony_ci if (cpu == this_cpu) 21262306a36Sopenharmony_ci continue; 21362306a36Sopenharmony_ci __default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, 21462306a36Sopenharmony_ci cpu), vector, APIC_DEST_PHYSICAL); 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci local_irq_restore(flags); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/* 22062306a36Sopenharmony_ci * Helper function for APICs which insist on cpumasks 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_civoid default_send_IPI_single(int cpu, int vector) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci __apic_send_IPI_mask(cpumask_of(cpu), vector); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_civoid default_send_IPI_allbutself(int vector) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci __default_send_IPI_shortcut(APIC_DEST_ALLBUT, vector); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_civoid default_send_IPI_all(int vector) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci __default_send_IPI_shortcut(APIC_DEST_ALLINC, vector); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_civoid default_send_IPI_self(int vector) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci __default_send_IPI_shortcut(APIC_DEST_SELF, vector); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci#ifdef CONFIG_X86_32 24362306a36Sopenharmony_civoid default_send_IPI_mask_sequence_logical(const struct cpumask *mask, int vector) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci unsigned long flags; 24662306a36Sopenharmony_ci unsigned int cpu; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci local_irq_save(flags); 24962306a36Sopenharmony_ci for_each_cpu(cpu, mask) 25062306a36Sopenharmony_ci __default_send_IPI_dest_field(1U << cpu, vector, APIC_DEST_LOGICAL); 25162306a36Sopenharmony_ci local_irq_restore(flags); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_civoid default_send_IPI_mask_allbutself_logical(const struct cpumask *mask, 25562306a36Sopenharmony_ci int vector) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci unsigned int cpu, this_cpu = smp_processor_id(); 25862306a36Sopenharmony_ci unsigned long flags; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci local_irq_save(flags); 26162306a36Sopenharmony_ci for_each_cpu(cpu, mask) { 26262306a36Sopenharmony_ci if (cpu == this_cpu) 26362306a36Sopenharmony_ci continue; 26462306a36Sopenharmony_ci __default_send_IPI_dest_field(1U << cpu, vector, APIC_DEST_LOGICAL); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci local_irq_restore(flags); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_civoid default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci unsigned long mask = cpumask_bits(cpumask)[0]; 27262306a36Sopenharmony_ci unsigned long flags; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!mask) 27562306a36Sopenharmony_ci return; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci local_irq_save(flags); 27862306a36Sopenharmony_ci WARN_ON(mask & ~cpumask_bits(cpu_online_mask)[0]); 27962306a36Sopenharmony_ci __default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL); 28062306a36Sopenharmony_ci local_irq_restore(flags); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci#ifdef CONFIG_SMP 28462306a36Sopenharmony_cistatic int convert_apicid_to_cpu(int apic_id) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int i; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci for_each_possible_cpu(i) { 28962306a36Sopenharmony_ci if (per_cpu(x86_cpu_to_apicid, i) == apic_id) 29062306a36Sopenharmony_ci return i; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci return -1; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciint safe_smp_processor_id(void) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci int apicid, cpuid; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_APIC)) 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci apicid = read_apic_id(); 30362306a36Sopenharmony_ci if (apicid == BAD_APICID) 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci cpuid = convert_apicid_to_cpu(apicid); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return cpuid >= 0 ? cpuid : 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci#endif 31162306a36Sopenharmony_ci#endif 312