Commit a1fdcc0d2714b6622e3fd5c00db1635213d6c41a

Authored by Len Brown
1 parent be521466fe

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);