17e300dabSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 22a05180fSIngo Molnar /* 32a05180fSIngo Molnar * Default generic APIC driver. This handles up to 8 CPUs. 42a05180fSIngo Molnar * 52a05180fSIngo Molnar * Copyright 2003 Andi Kleen, SuSE Labs. 62a05180fSIngo Molnar * 72a05180fSIngo Molnar * Generic x86 APIC driver probe layer. 82a05180fSIngo Molnar */ 9186f4360SPaul Gortmaker #include <linux/export.h> 102a05180fSIngo Molnar #include <linux/errno.h> 112a05180fSIngo Molnar #include <linux/smp.h> 122a05180fSIngo Molnar 1313c01139SIngo Molnar #include <asm/io_apic.h> 142a05180fSIngo Molnar #include <asm/apic.h> 152a05180fSIngo Molnar #include <asm/acpi.h> 162a05180fSIngo Molnar 17c94f0718SThomas Gleixner #include "local.h" 182a05180fSIngo Molnar 193f6f6798STejun Heo static int default_x86_32_early_logical_apicid(int cpu) 203f6f6798STejun Heo { 213f6f6798STejun Heo return 1 << cpu; 223f6f6798STejun Heo } 233f6f6798STejun Heo 24681ee44dSSuresh Siddha static void setup_apic_flat_routing(void) 252a05180fSIngo Molnar { 262a05180fSIngo Molnar #ifdef CONFIG_X86_IO_APIC 272a05180fSIngo Molnar printk(KERN_INFO 282a05180fSIngo Molnar "Enabling APIC mode: Flat. Using %d I/O APICs\n", 292a05180fSIngo Molnar nr_ioapics); 302a05180fSIngo Molnar #endif 312a05180fSIngo Molnar } 322a05180fSIngo Molnar 330801bbaaSThomas Gleixner static int default_apic_id_registered(void) 340801bbaaSThomas Gleixner { 350801bbaaSThomas Gleixner return physid_isset(read_apic_id(), phys_cpu_present_map); 360801bbaaSThomas Gleixner } 370801bbaaSThomas Gleixner 380801bbaaSThomas Gleixner /* 390801bbaaSThomas Gleixner * Set up the logical destination ID. Intel recommends to set DFR, LDR and 400801bbaaSThomas Gleixner * TPR before enabling an APIC. See e.g. "AP-388 82489DX User's Manual" 410801bbaaSThomas Gleixner * (Intel document number 292116). 420801bbaaSThomas Gleixner */ 430801bbaaSThomas Gleixner static void default_init_apic_ldr(void) 440801bbaaSThomas Gleixner { 450801bbaaSThomas Gleixner unsigned long val; 460801bbaaSThomas Gleixner 470801bbaaSThomas Gleixner apic_write(APIC_DFR, APIC_DFR_VALUE); 480801bbaaSThomas Gleixner val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; 490801bbaaSThomas Gleixner val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); 500801bbaaSThomas Gleixner apic_write(APIC_LDR, val); 510801bbaaSThomas Gleixner } 520801bbaaSThomas Gleixner 530801bbaaSThomas Gleixner static int default_phys_pkg_id(int cpuid_apic, int index_msb) 540801bbaaSThomas Gleixner { 550801bbaaSThomas Gleixner return cpuid_apic >> index_msb; 560801bbaaSThomas Gleixner } 570801bbaaSThomas Gleixner 582a05180fSIngo Molnar /* should be called last. */ 592a05180fSIngo Molnar static int probe_default(void) 602a05180fSIngo Molnar { 612a05180fSIngo Molnar return 1; 622a05180fSIngo Molnar } 632a05180fSIngo Molnar 64404f6aacSKees Cook static struct apic apic_default __ro_after_init = { 652a05180fSIngo Molnar 662a05180fSIngo Molnar .name = "default", 672a05180fSIngo Molnar .probe = probe_default, 682a05180fSIngo Molnar .acpi_madt_oem_check = NULL, 69fa63030eSDaniel J Blueman .apic_id_valid = default_apic_id_valid, 702a05180fSIngo Molnar .apic_id_registered = default_apic_id_registered, 712a05180fSIngo Molnar 72a31e58e1SThomas Gleixner .irq_delivery_mode = dest_Fixed, 732a05180fSIngo Molnar /* logical delivery broadcast to all CPUs: */ 742a05180fSIngo Molnar .irq_dest_mode = 1, 752a05180fSIngo Molnar 762a05180fSIngo Molnar .disable_esr = 0, 772a05180fSIngo Molnar .dest_logical = APIC_DEST_LOGICAL, 782a05180fSIngo Molnar .check_apicid_used = default_check_apicid_used, 792a05180fSIngo Molnar 802a05180fSIngo Molnar .init_apic_ldr = default_init_apic_ldr, 812a05180fSIngo Molnar 822a05180fSIngo Molnar .ioapic_phys_id_map = default_ioapic_phys_id_map, 83681ee44dSSuresh Siddha .setup_apic_routing = setup_apic_flat_routing, 842a05180fSIngo Molnar .cpu_present_to_apicid = default_cpu_present_to_apicid, 857abc0753SCyrill Gorcunov .apicid_to_cpu_present = physid_set_mask_of_physid, 862a05180fSIngo Molnar .check_phys_apicid_present = default_check_phys_apicid_present, 872a05180fSIngo Molnar .phys_pkg_id = default_phys_pkg_id, 882a05180fSIngo Molnar 892a05180fSIngo Molnar .get_apic_id = default_get_apic_id, 902a05180fSIngo Molnar .set_apic_id = NULL, 912a05180fSIngo Molnar 929f9e3bb1SThomas Gleixner .calc_dest_apicid = apic_flat_calc_apicid, 932a05180fSIngo Molnar 946153058aSThomas Gleixner .send_IPI = default_send_IPI_single, 952a05180fSIngo Molnar .send_IPI_mask = default_send_IPI_mask_logical, 962a05180fSIngo Molnar .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical, 972a05180fSIngo Molnar .send_IPI_allbutself = default_send_IPI_allbutself, 982a05180fSIngo Molnar .send_IPI_all = default_send_IPI_all, 992a05180fSIngo Molnar .send_IPI_self = default_send_IPI_self, 1002a05180fSIngo Molnar 1012a05180fSIngo Molnar .inquire_remote_apic = default_inquire_remote_apic, 1022a05180fSIngo Molnar 1032a05180fSIngo Molnar .read = native_apic_mem_read, 1042a05180fSIngo Molnar .write = native_apic_mem_write, 1052a43195dSMichael S. Tsirkin .eoi_write = native_apic_mem_write, 1062a05180fSIngo Molnar .icr_read = native_apic_icr_read, 1072a05180fSIngo Molnar .icr_write = native_apic_icr_write, 1082a05180fSIngo Molnar .wait_icr_idle = native_apic_wait_icr_idle, 1092a05180fSIngo Molnar .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, 110acb8bc09STejun Heo 1113f6f6798STejun Heo .x86_32_early_logical_apicid = default_x86_32_early_logical_apicid, 1122a05180fSIngo Molnar }; 1132a05180fSIngo Molnar 114107e0e0cSSuresh Siddha apic_driver(apic_default); 115107e0e0cSSuresh Siddha 116404f6aacSKees Cook struct apic *apic __ro_after_init = &apic_default; 1172a05180fSIngo Molnar EXPORT_SYMBOL_GPL(apic); 1182a05180fSIngo Molnar 1192a05180fSIngo Molnar static int cmdline_apic __initdata; 1202a05180fSIngo Molnar static int __init parse_apic(char *arg) 1212a05180fSIngo Molnar { 1228b37e880SSuresh Siddha struct apic **drv; 1232a05180fSIngo Molnar 1242a05180fSIngo Molnar if (!arg) 1252a05180fSIngo Molnar return -EINVAL; 1262a05180fSIngo Molnar 1278b37e880SSuresh Siddha for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 1288b37e880SSuresh Siddha if (!strcmp((*drv)->name, arg)) { 1298b37e880SSuresh Siddha apic = *drv; 1302a05180fSIngo Molnar cmdline_apic = 1; 1312a05180fSIngo Molnar return 0; 1322a05180fSIngo Molnar } 1332a05180fSIngo Molnar } 1342a05180fSIngo Molnar 1352a05180fSIngo Molnar /* Parsed again by __setup for debug/verbose */ 1362a05180fSIngo Molnar return 0; 1372a05180fSIngo Molnar } 1382a05180fSIngo Molnar early_param("apic", parse_apic); 1392a05180fSIngo Molnar 14069c252ffSSuresh Siddha void __init default_setup_apic_routing(void) 1412a05180fSIngo Molnar { 142cff9ab2bSDenys Vlasenko int version = boot_cpu_apic_version; 14369c252ffSSuresh Siddha 14469c252ffSSuresh Siddha if (num_possible_cpus() > 8) { 14569c252ffSSuresh Siddha switch (boot_cpu_data.x86_vendor) { 14669c252ffSSuresh Siddha case X86_VENDOR_INTEL: 14769c252ffSSuresh Siddha if (!APIC_XAPIC(version)) { 14869c252ffSSuresh Siddha def_to_bigsmp = 0; 14969c252ffSSuresh Siddha break; 15069c252ffSSuresh Siddha } 1515785675dSBorislav Petkov /* P4 and above */ 152df561f66SGustavo A. R. Silva fallthrough; 153da33dfefSPu Wen case X86_VENDOR_HYGON: 15469c252ffSSuresh Siddha case X86_VENDOR_AMD: 15569c252ffSSuresh Siddha def_to_bigsmp = 1; 15669c252ffSSuresh Siddha } 15769c252ffSSuresh Siddha } 15869c252ffSSuresh Siddha 1592a05180fSIngo Molnar #ifdef CONFIG_X86_BIGSMP 1602a05180fSIngo Molnar /* 16169c252ffSSuresh Siddha * This is used to switch to bigsmp mode when 1622a05180fSIngo Molnar * - There is no apic= option specified by the user 1632a05180fSIngo Molnar * - generic_apic_probe() has chosen apic_default as the sub_arch 1642a05180fSIngo Molnar * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support 1652a05180fSIngo Molnar */ 1662a05180fSIngo Molnar 167838312beSJan Beulich if (!cmdline_apic && apic == &apic_default) 168838312beSJan Beulich generic_bigsmp_probe(); 1692a05180fSIngo Molnar #endif 17069c252ffSSuresh Siddha 17169c252ffSSuresh Siddha if (apic->setup_apic_routing) 17269c252ffSSuresh Siddha apic->setup_apic_routing(); 1737db971b2SIdo Yariv 1747db971b2SIdo Yariv if (x86_platform.apic_post_init) 1757db971b2SIdo Yariv x86_platform.apic_post_init(); 1762a05180fSIngo Molnar } 1772a05180fSIngo Molnar 1782a05180fSIngo Molnar void __init generic_apic_probe(void) 1792a05180fSIngo Molnar { 1802a05180fSIngo Molnar if (!cmdline_apic) { 1818b37e880SSuresh Siddha struct apic **drv; 1828b37e880SSuresh Siddha 1838b37e880SSuresh Siddha for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 1848b37e880SSuresh Siddha if ((*drv)->probe()) { 1858b37e880SSuresh Siddha apic = *drv; 1862a05180fSIngo Molnar break; 1872a05180fSIngo Molnar } 1882a05180fSIngo Molnar } 1892a05180fSIngo Molnar /* Not visible without early console */ 1908b37e880SSuresh Siddha if (drv == __apicdrivers_end) 1912a05180fSIngo Molnar panic("Didn't find an APIC driver"); 1922a05180fSIngo Molnar } 1932a05180fSIngo Molnar printk(KERN_INFO "Using APIC driver %s\n", apic->name); 1942a05180fSIngo Molnar } 1952a05180fSIngo Molnar 196c460b5d3SDavid Rientjes /* This function can switch the APIC even after the initial ->probe() */ 1972a05180fSIngo Molnar int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id) 1982a05180fSIngo Molnar { 1998b37e880SSuresh Siddha struct apic **drv; 2002a05180fSIngo Molnar 2018b37e880SSuresh Siddha for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 2028b37e880SSuresh Siddha if (!(*drv)->acpi_madt_oem_check) 2032a05180fSIngo Molnar continue; 2048b37e880SSuresh Siddha if (!(*drv)->acpi_madt_oem_check(oem_id, oem_table_id)) 2052a05180fSIngo Molnar continue; 2062a05180fSIngo Molnar 2072a05180fSIngo Molnar if (!cmdline_apic) { 2088b37e880SSuresh Siddha apic = *drv; 2092a05180fSIngo Molnar printk(KERN_INFO "Switched to APIC driver `%s'.\n", 2102a05180fSIngo Molnar apic->name); 2112a05180fSIngo Molnar } 2122a05180fSIngo Molnar return 1; 2132a05180fSIngo Molnar } 2142a05180fSIngo Molnar return 0; 2152a05180fSIngo Molnar } 216