12a05180fSIngo Molnar /* 22a05180fSIngo Molnar * Default generic APIC driver. This handles up to 8 CPUs. 32a05180fSIngo Molnar * 42a05180fSIngo Molnar * Copyright 2003 Andi Kleen, SuSE Labs. 52a05180fSIngo Molnar * Subject to the GNU Public License, v.2 62a05180fSIngo Molnar * 72a05180fSIngo Molnar * Generic x86 APIC driver probe layer. 82a05180fSIngo Molnar */ 92a05180fSIngo Molnar #include <linux/threads.h> 102a05180fSIngo Molnar #include <linux/cpumask.h> 11186f4360SPaul Gortmaker #include <linux/export.h> 122a05180fSIngo Molnar #include <linux/string.h> 132a05180fSIngo Molnar #include <linux/kernel.h> 142a05180fSIngo Molnar #include <linux/ctype.h> 152a05180fSIngo Molnar #include <linux/init.h> 162a05180fSIngo Molnar #include <linux/errno.h> 172a05180fSIngo Molnar #include <asm/fixmap.h> 182a05180fSIngo Molnar #include <asm/mpspec.h> 192a05180fSIngo Molnar #include <asm/apicdef.h> 202a05180fSIngo Molnar #include <asm/apic.h> 212a05180fSIngo Molnar #include <asm/setup.h> 222a05180fSIngo Molnar 232a05180fSIngo Molnar #include <linux/smp.h> 242a05180fSIngo Molnar #include <asm/ipi.h> 252a05180fSIngo Molnar 262a05180fSIngo Molnar #include <linux/interrupt.h> 272a05180fSIngo Molnar #include <asm/acpi.h> 2866441bd3SIngo Molnar #include <asm/e820/api.h> 292a05180fSIngo Molnar 302a05180fSIngo Molnar #ifdef CONFIG_HOTPLUG_CPU 312a05180fSIngo Molnar #define DEFAULT_SEND_IPI (1) 322a05180fSIngo Molnar #else 332a05180fSIngo Molnar #define DEFAULT_SEND_IPI (0) 342a05180fSIngo Molnar #endif 352a05180fSIngo Molnar 362a05180fSIngo Molnar int no_broadcast = DEFAULT_SEND_IPI; 372a05180fSIngo Molnar 389be1b56aSIngo Molnar static __init int no_ipi_broadcast(char *str) 399be1b56aSIngo Molnar { 409be1b56aSIngo Molnar get_option(&str, &no_broadcast); 419be1b56aSIngo Molnar pr_info("Using %s mode\n", 429be1b56aSIngo Molnar no_broadcast ? "No IPI Broadcast" : "IPI Broadcast"); 439be1b56aSIngo Molnar return 1; 449be1b56aSIngo Molnar } 459be1b56aSIngo Molnar __setup("no_ipi_broadcast=", no_ipi_broadcast); 469be1b56aSIngo Molnar 479be1b56aSIngo Molnar static int __init print_ipi_mode(void) 489be1b56aSIngo Molnar { 499be1b56aSIngo Molnar pr_info("Using IPI %s mode\n", 509be1b56aSIngo Molnar no_broadcast ? "No-Shortcut" : "Shortcut"); 519be1b56aSIngo Molnar return 0; 529be1b56aSIngo Molnar } 539be1b56aSIngo Molnar late_initcall(print_ipi_mode); 542a05180fSIngo Molnar 553f6f6798STejun Heo static int default_x86_32_early_logical_apicid(int cpu) 563f6f6798STejun Heo { 573f6f6798STejun Heo return 1 << cpu; 583f6f6798STejun Heo } 593f6f6798STejun Heo 60681ee44dSSuresh Siddha static void setup_apic_flat_routing(void) 612a05180fSIngo Molnar { 622a05180fSIngo Molnar #ifdef CONFIG_X86_IO_APIC 632a05180fSIngo Molnar printk(KERN_INFO 642a05180fSIngo Molnar "Enabling APIC mode: Flat. Using %d I/O APICs\n", 652a05180fSIngo Molnar nr_ioapics); 662a05180fSIngo Molnar #endif 672a05180fSIngo Molnar } 682a05180fSIngo Molnar 690801bbaaSThomas Gleixner static int default_apic_id_registered(void) 700801bbaaSThomas Gleixner { 710801bbaaSThomas Gleixner return physid_isset(read_apic_id(), phys_cpu_present_map); 720801bbaaSThomas Gleixner } 730801bbaaSThomas Gleixner 740801bbaaSThomas Gleixner /* 750801bbaaSThomas Gleixner * Set up the logical destination ID. Intel recommends to set DFR, LDR and 760801bbaaSThomas Gleixner * TPR before enabling an APIC. See e.g. "AP-388 82489DX User's Manual" 770801bbaaSThomas Gleixner * (Intel document number 292116). 780801bbaaSThomas Gleixner */ 790801bbaaSThomas Gleixner static void default_init_apic_ldr(void) 800801bbaaSThomas Gleixner { 810801bbaaSThomas Gleixner unsigned long val; 820801bbaaSThomas Gleixner 830801bbaaSThomas Gleixner apic_write(APIC_DFR, APIC_DFR_VALUE); 840801bbaaSThomas Gleixner val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; 850801bbaaSThomas Gleixner val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); 860801bbaaSThomas Gleixner apic_write(APIC_LDR, val); 870801bbaaSThomas Gleixner } 880801bbaaSThomas Gleixner 890801bbaaSThomas Gleixner static int default_phys_pkg_id(int cpuid_apic, int index_msb) 900801bbaaSThomas Gleixner { 910801bbaaSThomas Gleixner return cpuid_apic >> index_msb; 920801bbaaSThomas Gleixner } 930801bbaaSThomas Gleixner 942a05180fSIngo Molnar /* should be called last. */ 952a05180fSIngo Molnar static int probe_default(void) 962a05180fSIngo Molnar { 972a05180fSIngo Molnar return 1; 982a05180fSIngo Molnar } 992a05180fSIngo Molnar 100404f6aacSKees Cook static struct apic apic_default __ro_after_init = { 1012a05180fSIngo Molnar 1022a05180fSIngo Molnar .name = "default", 1032a05180fSIngo Molnar .probe = probe_default, 1042a05180fSIngo Molnar .acpi_madt_oem_check = NULL, 105fa63030eSDaniel J Blueman .apic_id_valid = default_apic_id_valid, 1062a05180fSIngo Molnar .apic_id_registered = default_apic_id_registered, 1072a05180fSIngo Molnar 108a31e58e1SThomas Gleixner .irq_delivery_mode = dest_Fixed, 1092a05180fSIngo Molnar /* logical delivery broadcast to all CPUs: */ 1102a05180fSIngo Molnar .irq_dest_mode = 1, 1112a05180fSIngo Molnar 1122a05180fSIngo Molnar .disable_esr = 0, 1132a05180fSIngo Molnar .dest_logical = APIC_DEST_LOGICAL, 1142a05180fSIngo Molnar .check_apicid_used = default_check_apicid_used, 1152a05180fSIngo Molnar 1162a05180fSIngo Molnar .init_apic_ldr = default_init_apic_ldr, 1172a05180fSIngo Molnar 1182a05180fSIngo Molnar .ioapic_phys_id_map = default_ioapic_phys_id_map, 119681ee44dSSuresh Siddha .setup_apic_routing = setup_apic_flat_routing, 1202a05180fSIngo Molnar .cpu_present_to_apicid = default_cpu_present_to_apicid, 1217abc0753SCyrill Gorcunov .apicid_to_cpu_present = physid_set_mask_of_physid, 1222a05180fSIngo Molnar .check_phys_apicid_present = default_check_phys_apicid_present, 1232a05180fSIngo Molnar .phys_pkg_id = default_phys_pkg_id, 1242a05180fSIngo Molnar 1252a05180fSIngo Molnar .get_apic_id = default_get_apic_id, 1262a05180fSIngo Molnar .set_apic_id = NULL, 1272a05180fSIngo Molnar 1289f9e3bb1SThomas Gleixner .calc_dest_apicid = apic_flat_calc_apicid, 1292a05180fSIngo Molnar 1306153058aSThomas Gleixner .send_IPI = default_send_IPI_single, 1312a05180fSIngo Molnar .send_IPI_mask = default_send_IPI_mask_logical, 1322a05180fSIngo Molnar .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical, 1332a05180fSIngo Molnar .send_IPI_allbutself = default_send_IPI_allbutself, 1342a05180fSIngo Molnar .send_IPI_all = default_send_IPI_all, 1352a05180fSIngo Molnar .send_IPI_self = default_send_IPI_self, 1362a05180fSIngo Molnar 1372a05180fSIngo Molnar .inquire_remote_apic = default_inquire_remote_apic, 1382a05180fSIngo Molnar 1392a05180fSIngo Molnar .read = native_apic_mem_read, 1402a05180fSIngo Molnar .write = native_apic_mem_write, 1412a43195dSMichael S. Tsirkin .eoi_write = native_apic_mem_write, 1422a05180fSIngo Molnar .icr_read = native_apic_icr_read, 1432a05180fSIngo Molnar .icr_write = native_apic_icr_write, 1442a05180fSIngo Molnar .wait_icr_idle = native_apic_wait_icr_idle, 1452a05180fSIngo Molnar .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, 146acb8bc09STejun Heo 1473f6f6798STejun Heo .x86_32_early_logical_apicid = default_x86_32_early_logical_apicid, 1482a05180fSIngo Molnar }; 1492a05180fSIngo Molnar 150107e0e0cSSuresh Siddha apic_driver(apic_default); 151107e0e0cSSuresh Siddha 152404f6aacSKees Cook struct apic *apic __ro_after_init = &apic_default; 1532a05180fSIngo Molnar EXPORT_SYMBOL_GPL(apic); 1542a05180fSIngo Molnar 1552a05180fSIngo Molnar static int cmdline_apic __initdata; 1562a05180fSIngo Molnar static int __init parse_apic(char *arg) 1572a05180fSIngo Molnar { 1588b37e880SSuresh Siddha struct apic **drv; 1592a05180fSIngo Molnar 1602a05180fSIngo Molnar if (!arg) 1612a05180fSIngo Molnar return -EINVAL; 1622a05180fSIngo Molnar 1638b37e880SSuresh Siddha for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 1648b37e880SSuresh Siddha if (!strcmp((*drv)->name, arg)) { 1658b37e880SSuresh Siddha apic = *drv; 1662a05180fSIngo Molnar cmdline_apic = 1; 1672a05180fSIngo Molnar return 0; 1682a05180fSIngo Molnar } 1692a05180fSIngo Molnar } 1702a05180fSIngo Molnar 1712a05180fSIngo Molnar /* Parsed again by __setup for debug/verbose */ 1722a05180fSIngo Molnar return 0; 1732a05180fSIngo Molnar } 1742a05180fSIngo Molnar early_param("apic", parse_apic); 1752a05180fSIngo Molnar 17669c252ffSSuresh Siddha void __init default_setup_apic_routing(void) 1772a05180fSIngo Molnar { 178cff9ab2bSDenys Vlasenko int version = boot_cpu_apic_version; 17969c252ffSSuresh Siddha 18069c252ffSSuresh Siddha if (num_possible_cpus() > 8) { 18169c252ffSSuresh Siddha switch (boot_cpu_data.x86_vendor) { 18269c252ffSSuresh Siddha case X86_VENDOR_INTEL: 18369c252ffSSuresh Siddha if (!APIC_XAPIC(version)) { 18469c252ffSSuresh Siddha def_to_bigsmp = 0; 18569c252ffSSuresh Siddha break; 18669c252ffSSuresh Siddha } 18769c252ffSSuresh Siddha /* If P4 and above fall through */ 18869c252ffSSuresh Siddha case X86_VENDOR_AMD: 18969c252ffSSuresh Siddha def_to_bigsmp = 1; 19069c252ffSSuresh Siddha } 19169c252ffSSuresh Siddha } 19269c252ffSSuresh Siddha 1932a05180fSIngo Molnar #ifdef CONFIG_X86_BIGSMP 1942a05180fSIngo Molnar /* 19569c252ffSSuresh Siddha * This is used to switch to bigsmp mode when 1962a05180fSIngo Molnar * - There is no apic= option specified by the user 1972a05180fSIngo Molnar * - generic_apic_probe() has chosen apic_default as the sub_arch 1982a05180fSIngo Molnar * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support 1992a05180fSIngo Molnar */ 2002a05180fSIngo Molnar 201838312beSJan Beulich if (!cmdline_apic && apic == &apic_default) 202838312beSJan Beulich generic_bigsmp_probe(); 2032a05180fSIngo Molnar #endif 20469c252ffSSuresh Siddha 20569c252ffSSuresh Siddha if (apic->setup_apic_routing) 20669c252ffSSuresh Siddha apic->setup_apic_routing(); 2077db971b2SIdo Yariv 2087db971b2SIdo Yariv if (x86_platform.apic_post_init) 2097db971b2SIdo Yariv x86_platform.apic_post_init(); 2102a05180fSIngo Molnar } 2112a05180fSIngo Molnar 2122a05180fSIngo Molnar void __init generic_apic_probe(void) 2132a05180fSIngo Molnar { 2142a05180fSIngo Molnar if (!cmdline_apic) { 2158b37e880SSuresh Siddha struct apic **drv; 2168b37e880SSuresh Siddha 2178b37e880SSuresh Siddha for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 2188b37e880SSuresh Siddha if ((*drv)->probe()) { 2198b37e880SSuresh Siddha apic = *drv; 2202a05180fSIngo Molnar break; 2212a05180fSIngo Molnar } 2222a05180fSIngo Molnar } 2232a05180fSIngo Molnar /* Not visible without early console */ 2248b37e880SSuresh Siddha if (drv == __apicdrivers_end) 2252a05180fSIngo Molnar panic("Didn't find an APIC driver"); 2262a05180fSIngo Molnar } 2272a05180fSIngo Molnar printk(KERN_INFO "Using APIC driver %s\n", apic->name); 2282a05180fSIngo Molnar } 2292a05180fSIngo Molnar 230c460b5d3SDavid Rientjes /* This function can switch the APIC even after the initial ->probe() */ 2312a05180fSIngo Molnar int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id) 2322a05180fSIngo Molnar { 2338b37e880SSuresh Siddha struct apic **drv; 2342a05180fSIngo Molnar 2358b37e880SSuresh Siddha for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) { 2368b37e880SSuresh Siddha if (!(*drv)->acpi_madt_oem_check) 2372a05180fSIngo Molnar continue; 2388b37e880SSuresh Siddha if (!(*drv)->acpi_madt_oem_check(oem_id, oem_table_id)) 2392a05180fSIngo Molnar continue; 2402a05180fSIngo Molnar 2412a05180fSIngo Molnar if (!cmdline_apic) { 2428b37e880SSuresh Siddha apic = *drv; 2432a05180fSIngo Molnar printk(KERN_INFO "Switched to APIC driver `%s'.\n", 2442a05180fSIngo Molnar apic->name); 2452a05180fSIngo Molnar } 2462a05180fSIngo Molnar return 1; 2472a05180fSIngo Molnar } 2482a05180fSIngo Molnar return 0; 2492a05180fSIngo Molnar } 250