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