Commit a1fdcc0d2714b6622e3fd5c00db1635213d6c41a
1 parent
be521466fe
Exists in
master
and in
4 other branches
ACPI: Add support to parse 2nd MADT
When a BIOS bug presents multiple APIC/MADTs, Linux currently uses the 1st and ignores the 2nd. But some machines work better if we use the 2nd. http://bugzilla.kernel.org/show_bug.cgi?id=7465 Add a warning and boot parameter "acpi_apic_instance=2" to allow parsing the 2nd. No change to default behaviour in this patch. Signed-off-by: Len Brown <len.brown@intel.com>
Showing 2 changed files with 58 additions and 5 deletions Side-by-side Diff
Documentation/kernel-parameters.txt
... | ... | @@ -138,6 +138,12 @@ |
138 | 138 | |
139 | 139 | See also Documentation/pm.txt, pci=noacpi |
140 | 140 | |
141 | + acpi_apic_instance= [ACPI, IOAPIC] | |
142 | + Format: <int> | |
143 | + 2: use 2nd APIC table, if available | |
144 | + 1,0: use 1st APIC table | |
145 | + default: 0 | |
146 | + | |
141 | 147 | acpi_sleep= [HW,ACPI] Sleep options |
142 | 148 | Format: { s3_bios, s3_mode } |
143 | 149 | See Documentation/power/video.txt |
drivers/acpi/tables.c
... | ... | @@ -42,7 +42,9 @@ |
42 | 42 | |
43 | 43 | static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; |
44 | 44 | |
45 | -void acpi_table_print_madt_entry(struct acpi_subtable_header * header) | |
45 | +static int acpi_apic_instance __initdata; | |
46 | + | |
47 | +void acpi_table_print_madt_entry(struct acpi_subtable_header *header) | |
46 | 48 | { |
47 | 49 | if (!header) |
48 | 50 | return; |
... | ... | @@ -183,8 +185,10 @@ |
183 | 185 | if (!handler) |
184 | 186 | return -EINVAL; |
185 | 187 | |
186 | - /* Locate the table (if exists). There should only be one. */ | |
187 | - acpi_get_table(id, 0, &table_header); | |
188 | + if (strncmp(id, ACPI_SIG_MADT, 4) == 0) | |
189 | + acpi_get_table(id, acpi_apic_instance, &table_header); | |
190 | + else | |
191 | + acpi_get_table(id, 0, &table_header); | |
188 | 192 | |
189 | 193 | if (!table_header) { |
190 | 194 | printk(KERN_WARNING PREFIX "%4.4s not present\n", id); |
191 | 195 | |
... | ... | @@ -237,10 +241,15 @@ |
237 | 241 | int __init acpi_table_parse(char *id, acpi_table_handler handler) |
238 | 242 | { |
239 | 243 | struct acpi_table_header *table = NULL; |
244 | + | |
240 | 245 | if (!handler) |
241 | 246 | return -EINVAL; |
242 | 247 | |
243 | - acpi_get_table(id, 0, &table); | |
248 | + if (strncmp(id, ACPI_SIG_MADT, 4) == 0) | |
249 | + acpi_get_table(id, acpi_apic_instance, &table); | |
250 | + else | |
251 | + acpi_get_table(id, 0, &table); | |
252 | + | |
244 | 253 | if (table) { |
245 | 254 | handler(table); |
246 | 255 | return 0; |
... | ... | @@ -248,6 +257,31 @@ |
248 | 257 | return 1; |
249 | 258 | } |
250 | 259 | |
260 | +/* | |
261 | + * The BIOS is supposed to supply a single APIC/MADT, | |
262 | + * but some report two. Provide a knob to use either. | |
263 | + * (don't you wish instance 0 and 1 were not the same?) | |
264 | + */ | |
265 | +static void __init check_multiple_madt(void) | |
266 | +{ | |
267 | + struct acpi_table_header *table = NULL; | |
268 | + | |
269 | + acpi_get_table(ACPI_SIG_MADT, 2, &table); | |
270 | + if (table) { | |
271 | + printk(KERN_WARNING PREFIX | |
272 | + "BIOS bug: multiple APIC/MADT found," | |
273 | + " using %d\n", acpi_apic_instance); | |
274 | + printk(KERN_WARNING PREFIX | |
275 | + "If \"acpi_apic_instance=%d\" works better, " | |
276 | + "notify linux-acpi@vger.kernel.org\n", | |
277 | + acpi_apic_instance ? 0 : 2); | |
278 | + | |
279 | + } else | |
280 | + acpi_apic_instance = 0; | |
281 | + | |
282 | + return; | |
283 | +} | |
284 | + | |
251 | 285 | /* |
252 | 286 | * acpi_table_init() |
253 | 287 | * |
254 | 288 | |
255 | 289 | |
... | ... | @@ -257,10 +291,23 @@ |
257 | 291 | * result: sdt_entry[] is initialized |
258 | 292 | */ |
259 | 293 | |
260 | - | |
261 | 294 | int __init acpi_table_init(void) |
262 | 295 | { |
263 | 296 | acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); |
297 | + check_multiple_madt(); | |
264 | 298 | return 0; |
265 | 299 | } |
300 | + | |
301 | +static int __init acpi_parse_apic_instance(char *str) | |
302 | +{ | |
303 | + | |
304 | + acpi_apic_instance = simple_strtoul(str, NULL, 0); | |
305 | + | |
306 | + printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n", | |
307 | + acpi_apic_instance); | |
308 | + | |
309 | + return 0; | |
310 | +} | |
311 | + | |
312 | +early_param("acpi_apic_instance", acpi_parse_apic_instance); |