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> 112a05180fSIngo Molnar #include <linux/module.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> 282a05180fSIngo Molnar #include <asm/e820.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 552a05180fSIngo Molnar void default_setup_apic_routing(void) 562a05180fSIngo Molnar { 572a05180fSIngo Molnar #ifdef CONFIG_X86_IO_APIC 582a05180fSIngo Molnar printk(KERN_INFO 592a05180fSIngo Molnar "Enabling APIC mode: Flat. Using %d I/O APICs\n", 602a05180fSIngo Molnar nr_ioapics); 612a05180fSIngo Molnar #endif 622a05180fSIngo Molnar } 632a05180fSIngo Molnar 642a05180fSIngo Molnar static void default_vector_allocation_domain(int cpu, struct cpumask *retmask) 652a05180fSIngo Molnar { 662a05180fSIngo Molnar /* 672a05180fSIngo Molnar * Careful. Some cpus do not strictly honor the set of cpus 682a05180fSIngo Molnar * specified in the interrupt destination when using lowest 692a05180fSIngo Molnar * priority interrupt delivery mode. 702a05180fSIngo Molnar * 712a05180fSIngo Molnar * In particular there was a hyperthreading cpu observed to 722a05180fSIngo Molnar * deliver interrupts to the wrong hyperthread when only one 732a05180fSIngo Molnar * hyperthread was specified in the interrupt desitination. 742a05180fSIngo Molnar */ 755c6cb5e2SRusty Russell cpumask_clear(retmask); 765c6cb5e2SRusty Russell cpumask_bits(retmask)[0] = APIC_ALL_CPUS; 772a05180fSIngo Molnar } 782a05180fSIngo Molnar 792a05180fSIngo Molnar /* should be called last. */ 802a05180fSIngo Molnar static int probe_default(void) 812a05180fSIngo Molnar { 822a05180fSIngo Molnar return 1; 832a05180fSIngo Molnar } 842a05180fSIngo Molnar 852a05180fSIngo Molnar struct apic apic_default = { 862a05180fSIngo Molnar 872a05180fSIngo Molnar .name = "default", 882a05180fSIngo Molnar .probe = probe_default, 892a05180fSIngo Molnar .acpi_madt_oem_check = NULL, 902a05180fSIngo Molnar .apic_id_registered = default_apic_id_registered, 912a05180fSIngo Molnar 922a05180fSIngo Molnar .irq_delivery_mode = dest_LowestPrio, 932a05180fSIngo Molnar /* logical delivery broadcast to all CPUs: */ 942a05180fSIngo Molnar .irq_dest_mode = 1, 952a05180fSIngo Molnar 962a05180fSIngo Molnar .target_cpus = default_target_cpus, 972a05180fSIngo Molnar .disable_esr = 0, 982a05180fSIngo Molnar .dest_logical = APIC_DEST_LOGICAL, 992a05180fSIngo Molnar .check_apicid_used = default_check_apicid_used, 1002a05180fSIngo Molnar .check_apicid_present = default_check_apicid_present, 1012a05180fSIngo Molnar 1022a05180fSIngo Molnar .vector_allocation_domain = default_vector_allocation_domain, 1032a05180fSIngo Molnar .init_apic_ldr = default_init_apic_ldr, 1042a05180fSIngo Molnar 1052a05180fSIngo Molnar .ioapic_phys_id_map = default_ioapic_phys_id_map, 1062a05180fSIngo Molnar .setup_apic_routing = default_setup_apic_routing, 1072a05180fSIngo Molnar .multi_timer_check = NULL, 1082a05180fSIngo Molnar .apicid_to_node = default_apicid_to_node, 1092a05180fSIngo Molnar .cpu_to_logical_apicid = default_cpu_to_logical_apicid, 1102a05180fSIngo Molnar .cpu_present_to_apicid = default_cpu_present_to_apicid, 1117abc0753SCyrill Gorcunov .apicid_to_cpu_present = physid_set_mask_of_physid, 1122a05180fSIngo Molnar .setup_portio_remap = NULL, 1132a05180fSIngo Molnar .check_phys_apicid_present = default_check_phys_apicid_present, 1142a05180fSIngo Molnar .enable_apic_mode = NULL, 1152a05180fSIngo Molnar .phys_pkg_id = default_phys_pkg_id, 1162a05180fSIngo Molnar .mps_oem_check = NULL, 1172a05180fSIngo Molnar 1182a05180fSIngo Molnar .get_apic_id = default_get_apic_id, 1192a05180fSIngo Molnar .set_apic_id = NULL, 1202a05180fSIngo Molnar .apic_id_mask = 0x0F << 24, 1212a05180fSIngo Molnar 1222a05180fSIngo Molnar .cpu_mask_to_apicid = default_cpu_mask_to_apicid, 1232a05180fSIngo Molnar .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, 1242a05180fSIngo Molnar 1252a05180fSIngo Molnar .send_IPI_mask = default_send_IPI_mask_logical, 1262a05180fSIngo Molnar .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical, 1272a05180fSIngo Molnar .send_IPI_allbutself = default_send_IPI_allbutself, 1282a05180fSIngo Molnar .send_IPI_all = default_send_IPI_all, 1292a05180fSIngo Molnar .send_IPI_self = default_send_IPI_self, 1302a05180fSIngo Molnar 1312a05180fSIngo Molnar .trampoline_phys_low = DEFAULT_TRAMPOLINE_PHYS_LOW, 1322a05180fSIngo Molnar .trampoline_phys_high = DEFAULT_TRAMPOLINE_PHYS_HIGH, 1332a05180fSIngo Molnar 1342a05180fSIngo Molnar .wait_for_init_deassert = default_wait_for_init_deassert, 1352a05180fSIngo Molnar 1362a05180fSIngo Molnar .smp_callin_clear_local_apic = NULL, 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, 1412a05180fSIngo Molnar .icr_read = native_apic_icr_read, 1422a05180fSIngo Molnar .icr_write = native_apic_icr_write, 1432a05180fSIngo Molnar .wait_icr_idle = native_apic_wait_icr_idle, 1442a05180fSIngo Molnar .safe_wait_icr_idle = native_safe_apic_wait_icr_idle, 1452a05180fSIngo Molnar }; 1462a05180fSIngo Molnar 1472a05180fSIngo Molnar extern struct apic apic_numaq; 1482a05180fSIngo Molnar extern struct apic apic_summit; 1492a05180fSIngo Molnar extern struct apic apic_bigsmp; 1502a05180fSIngo Molnar extern struct apic apic_es7000; 1512b6163bfSYinghai Lu extern struct apic apic_es7000_cluster; 1522a05180fSIngo Molnar 1532a05180fSIngo Molnar struct apic *apic = &apic_default; 1542a05180fSIngo Molnar EXPORT_SYMBOL_GPL(apic); 1552a05180fSIngo Molnar 1562a05180fSIngo Molnar static struct apic *apic_probe[] __initdata = { 1572a05180fSIngo Molnar #ifdef CONFIG_X86_NUMAQ 1582a05180fSIngo Molnar &apic_numaq, 1592a05180fSIngo Molnar #endif 1602a05180fSIngo Molnar #ifdef CONFIG_X86_SUMMIT 1612a05180fSIngo Molnar &apic_summit, 1622a05180fSIngo Molnar #endif 1632a05180fSIngo Molnar #ifdef CONFIG_X86_BIGSMP 1642a05180fSIngo Molnar &apic_bigsmp, 1652a05180fSIngo Molnar #endif 1662a05180fSIngo Molnar #ifdef CONFIG_X86_ES7000 1672a05180fSIngo Molnar &apic_es7000, 1682b6163bfSYinghai Lu &apic_es7000_cluster, 1692a05180fSIngo Molnar #endif 1702a05180fSIngo Molnar &apic_default, /* must be last */ 1712a05180fSIngo Molnar NULL, 1722a05180fSIngo Molnar }; 1732a05180fSIngo Molnar 1742a05180fSIngo Molnar static int cmdline_apic __initdata; 1752a05180fSIngo Molnar static int __init parse_apic(char *arg) 1762a05180fSIngo Molnar { 1772a05180fSIngo Molnar int i; 1782a05180fSIngo Molnar 1792a05180fSIngo Molnar if (!arg) 1802a05180fSIngo Molnar return -EINVAL; 1812a05180fSIngo Molnar 1822a05180fSIngo Molnar for (i = 0; apic_probe[i]; i++) { 1832a05180fSIngo Molnar if (!strcmp(apic_probe[i]->name, arg)) { 1842a05180fSIngo Molnar apic = apic_probe[i]; 1852a05180fSIngo Molnar cmdline_apic = 1; 1862a05180fSIngo Molnar return 0; 1872a05180fSIngo Molnar } 1882a05180fSIngo Molnar } 1892a05180fSIngo Molnar 1902a05180fSIngo Molnar /* Parsed again by __setup for debug/verbose */ 1912a05180fSIngo Molnar return 0; 1922a05180fSIngo Molnar } 1932a05180fSIngo Molnar early_param("apic", parse_apic); 1942a05180fSIngo Molnar 1952a05180fSIngo Molnar void __init generic_bigsmp_probe(void) 1962a05180fSIngo Molnar { 1972a05180fSIngo Molnar #ifdef CONFIG_X86_BIGSMP 1982a05180fSIngo Molnar /* 1992a05180fSIngo Molnar * This routine is used to switch to bigsmp mode when 2002a05180fSIngo Molnar * - There is no apic= option specified by the user 2012a05180fSIngo Molnar * - generic_apic_probe() has chosen apic_default as the sub_arch 2022a05180fSIngo Molnar * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support 2032a05180fSIngo Molnar */ 2042a05180fSIngo Molnar 2052a05180fSIngo Molnar if (!cmdline_apic && apic == &apic_default) { 2062a05180fSIngo Molnar if (apic_bigsmp.probe()) { 2072a05180fSIngo Molnar apic = &apic_bigsmp; 2082a05180fSIngo Molnar printk(KERN_INFO "Overriding APIC driver with %s\n", 2092a05180fSIngo Molnar apic->name); 2102a05180fSIngo Molnar } 2112a05180fSIngo Molnar } 2122a05180fSIngo Molnar #endif 2132a05180fSIngo Molnar } 2142a05180fSIngo Molnar 2152a05180fSIngo Molnar void __init generic_apic_probe(void) 2162a05180fSIngo Molnar { 2172a05180fSIngo Molnar if (!cmdline_apic) { 2182a05180fSIngo Molnar int i; 2192a05180fSIngo Molnar for (i = 0; apic_probe[i]; i++) { 2202a05180fSIngo Molnar if (apic_probe[i]->probe()) { 2212a05180fSIngo Molnar apic = apic_probe[i]; 2222a05180fSIngo Molnar break; 2232a05180fSIngo Molnar } 2242a05180fSIngo Molnar } 2252a05180fSIngo Molnar /* Not visible without early console */ 2262a05180fSIngo Molnar if (!apic_probe[i]) 2272a05180fSIngo Molnar panic("Didn't find an APIC driver"); 2282a05180fSIngo Molnar } 2292a05180fSIngo Molnar printk(KERN_INFO "Using APIC driver %s\n", apic->name); 2302a05180fSIngo Molnar } 2312a05180fSIngo Molnar 2322a05180fSIngo Molnar /* These functions can switch the APIC even after the initial ->probe() */ 2332a05180fSIngo Molnar 2342a05180fSIngo Molnar int __init 2352a05180fSIngo Molnar generic_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid) 2362a05180fSIngo Molnar { 2372a05180fSIngo Molnar int i; 2382a05180fSIngo Molnar 2392a05180fSIngo Molnar for (i = 0; apic_probe[i]; ++i) { 2402a05180fSIngo Molnar if (!apic_probe[i]->mps_oem_check) 2412a05180fSIngo Molnar continue; 2422a05180fSIngo Molnar if (!apic_probe[i]->mps_oem_check(mpc, oem, productid)) 2432a05180fSIngo Molnar continue; 2442a05180fSIngo Molnar 2452a05180fSIngo Molnar if (!cmdline_apic) { 2462a05180fSIngo Molnar apic = apic_probe[i]; 2472a05180fSIngo Molnar printk(KERN_INFO "Switched to APIC driver `%s'.\n", 2482a05180fSIngo Molnar apic->name); 2492a05180fSIngo Molnar } 2502a05180fSIngo Molnar return 1; 2512a05180fSIngo Molnar } 2522a05180fSIngo Molnar return 0; 2532a05180fSIngo Molnar } 2542a05180fSIngo Molnar 2552a05180fSIngo Molnar int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id) 2562a05180fSIngo Molnar { 2572a05180fSIngo Molnar int i; 2582a05180fSIngo Molnar 2592a05180fSIngo Molnar for (i = 0; apic_probe[i]; ++i) { 2602a05180fSIngo Molnar if (!apic_probe[i]->acpi_madt_oem_check) 2612a05180fSIngo Molnar continue; 2622a05180fSIngo Molnar if (!apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) 2632a05180fSIngo Molnar continue; 2642a05180fSIngo Molnar 2652a05180fSIngo Molnar if (!cmdline_apic) { 2662a05180fSIngo Molnar apic = apic_probe[i]; 2672a05180fSIngo Molnar printk(KERN_INFO "Switched to APIC driver `%s'.\n", 2682a05180fSIngo Molnar apic->name); 2692a05180fSIngo Molnar } 2702a05180fSIngo Molnar return 1; 2712a05180fSIngo Molnar } 2722a05180fSIngo Molnar return 0; 2732a05180fSIngo Molnar } 274