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 <xen/cpumask.h>
7 #include <xen/string.h>
8 #include <xen/kernel.h>
9 #include <xen/ctype.h>
10 #include <xen/init.h>
11 #include <asm/cache.h>
12 #include <asm/fixmap.h>
13 #include <asm/mpspec.h>
14 #include <asm/apicdef.h>
15 #include <asm/mach-generic/mach_apic.h>
16 #include <asm/setup.h>
17
18 extern const struct genapic apic_bigsmp;
19
20 const struct genapic *__read_mostly genapic;
21
22 const struct genapic *apic_probe[] __initdata = {
23 &apic_bigsmp,
24 &apic_default, /* must be last */
25 NULL,
26 };
27
28 static bool_t __initdata cmdline_apic;
29
generic_bigsmp_probe(void)30 void __init generic_bigsmp_probe(void)
31 {
32 /*
33 * This routine is used to switch to bigsmp mode when
34 * - There is no apic= option specified by the user
35 * - generic_apic_probe() has choosen apic_default as the sub_arch
36 * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
37 */
38
39 if (!cmdline_apic && genapic == &apic_default)
40 if (apic_bigsmp.probe()) {
41 genapic = &apic_bigsmp;
42 printk(KERN_INFO "Overriding APIC driver with %s\n",
43 genapic->name);
44 }
45 }
46
genapic_apic_force(const char * str)47 static int __init genapic_apic_force(const char *str)
48 {
49 int i, rc = -EINVAL;
50
51 for (i = 0; apic_probe[i]; i++)
52 if (!strcmp(apic_probe[i]->name, str)) {
53 genapic = apic_probe[i];
54 rc = 0;
55 }
56
57 return rc;
58 }
59 custom_param("apic", genapic_apic_force);
60
generic_apic_probe(void)61 void __init generic_apic_probe(void)
62 {
63 bool changed;
64 int i;
65
66 record_boot_APIC_mode();
67
68 check_x2apic_preenabled();
69 cmdline_apic = changed = (genapic != NULL);
70
71 for (i = 0; !changed && apic_probe[i]; i++) {
72 if (apic_probe[i]->probe()) {
73 changed = 1;
74 genapic = apic_probe[i];
75 }
76 }
77 if (!changed)
78 genapic = &apic_default;
79
80 printk(KERN_INFO "Using APIC driver %s\n", genapic->name);
81 }
82
83 /* These functions can switch the APIC even after the initial ->probe() */
84
mps_oem_check(struct mp_config_table * mpc,char * oem,char * productid)85 int __init mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid)
86 {
87 int i;
88 for (i = 0; apic_probe[i]; ++i) {
89 if (apic_probe[i]->mps_oem_check(mpc,oem,productid)) {
90 if (!cmdline_apic) {
91 genapic = apic_probe[i];
92 printk(KERN_INFO "Switched to APIC driver `%s'.\n",
93 genapic->name);
94 }
95 return 1;
96 }
97 }
98 return 0;
99 }
100
acpi_madt_oem_check(char * oem_id,char * oem_table_id)101 int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
102 {
103 int i;
104 for (i = 0; apic_probe[i]; ++i) {
105 if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) {
106 if (!cmdline_apic) {
107 genapic = apic_probe[i];
108 printk(KERN_INFO "Switched to APIC driver `%s'.\n",
109 genapic->name);
110 }
111 return 1;
112 }
113 }
114 return 0;
115 }
116