1/* Copyright 2003 Andi Kleen, SuSE Labs. 2 * Subject to the GNU Public License, v.2 3 * 4 * Generic x86 APIC driver probe layer. 5 */ 6#include <linux/threads.h> 7#include <linux/cpumask.h> 8#include <linux/string.h> 9#include <linux/kernel.h> 10#include <linux/ctype.h> 11#include <linux/init.h> 12#include <linux/errno.h> 13#include <asm/fixmap.h> 14#include <asm/mpspec.h> 15#include <asm/apicdef.h> 16#include <asm/genapic.h> 17 18extern struct genapic apic_summit; 19extern struct genapic apic_bigsmp; 20extern struct genapic apic_es7000; 21extern struct genapic apic_default; 22 23struct genapic *genapic = &apic_default; 24 25struct genapic *apic_probe[] __initdata = { 26 &apic_summit, 27 &apic_bigsmp, 28 &apic_es7000, 29 &apic_default, /* must be last */ 30 NULL, 31}; 32 33static int cmdline_apic __initdata; 34static int __init parse_apic(char *arg) 35{ 36 int i; 37 38 if (!arg) 39 return -EINVAL; 40 41 for (i = 0; apic_probe[i]; i++) { 42 if (!strcmp(apic_probe[i]->name, arg)) { 43 genapic = apic_probe[i]; 44 cmdline_apic = 1; 45 return 0; 46 } 47 } 48 49 /* Parsed again by __setup for debug/verbose */ 50 return 0; 51} 52early_param("apic", parse_apic); 53 54void __init generic_bigsmp_probe(void) 55{ 56 /* 57 * This routine is used to switch to bigsmp mode when 58 * - There is no apic= option specified by the user 59 * - generic_apic_probe() has choosen apic_default as the sub_arch 60 * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support 61 */ 62 63 if (!cmdline_apic && genapic == &apic_default) 64 if (apic_bigsmp.probe()) { 65 genapic = &apic_bigsmp; 66 printk(KERN_INFO "Overriding APIC driver with %s\n", 67 genapic->name); 68 } 69} 70 71void __init generic_apic_probe(void) 72{ 73 if (!cmdline_apic) { 74 int i; 75 for (i = 0; apic_probe[i]; i++) { 76 if (apic_probe[i]->probe()) { 77 genapic = apic_probe[i]; 78 break; 79 } 80 } 81 /* Not visible without early console */ 82 if (!apic_probe[i]) 83 panic("Didn't find an APIC driver"); 84 } 85 printk(KERN_INFO "Using APIC driver %s\n", genapic->name); 86} 87 88/* These functions can switch the APIC even after the initial ->probe() */ 89 90int __init mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) 91{ 92 int i; 93 for (i = 0; apic_probe[i]; ++i) { 94 if (apic_probe[i]->mps_oem_check(mpc,oem,productid)) { 95 if (!cmdline_apic) { 96 genapic = apic_probe[i]; 97 printk(KERN_INFO "Switched to APIC driver `%s'.\n", 98 genapic->name); 99 } 100 return 1; 101 } 102 } 103 return 0; 104} 105 106int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) 107{ 108 int i; 109 for (i = 0; apic_probe[i]; ++i) { 110 if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) { 111 if (!cmdline_apic) { 112 genapic = apic_probe[i]; 113 printk(KERN_INFO "Switched to APIC driver `%s'.\n", 114 genapic->name); 115 } 116 return 1; 117 } 118 } 119 return 0; 120} 121 122int hard_smp_processor_id(void) 123{ 124 return genapic->get_apic_id(*(unsigned long *)(APIC_BASE+APIC_ID)); 125} 126