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