Blame view
drivers/acpi/tables.c
21.4 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * acpi_tables.c - ACPI Boot-Time Table Parsing * * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * |
1da177e4c Linux-2.6.12-rc2 |
18 19 20 |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ |
07f438df2 ACPI / table: Use... |
21 22 |
/* Uncomment next line to get verbose printout */ /* #define DEBUG */ |
730bf5ebb ACPI / tables: Re... |
23 |
#define pr_fmt(fmt) "ACPI: " fmt |
1da177e4c Linux-2.6.12-rc2 |
24 25 |
#include <linux/init.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
26 27 28 29 30 31 32 |
#include <linux/smp.h> #include <linux/string.h> #include <linux/types.h> #include <linux/irq.h> #include <linux/errno.h> #include <linux/acpi.h> #include <linux/bootmem.h> |
5ae74f2cc ACPI / tables: Mo... |
33 34 |
#include <linux/earlycpio.h> #include <linux/memblock.h> |
da3d3f98d ACPI / tables: ta... |
35 |
#include <linux/initrd.h> |
c85cc817e ACPI / OSL: Add s... |
36 |
#include "internal.h" |
1da177e4c Linux-2.6.12-rc2 |
37 |
|
74216699d ACPI / tables: Fi... |
38 39 40 |
#ifdef CONFIG_ACPI_CUSTOM_DSDT #include CONFIG_ACPI_CUSTOM_DSDT_FILE #endif |
04348e69e [ACPI] reduce ker... |
41 |
#define ACPI_MAX_TABLES 128 |
1da177e4c Linux-2.6.12-rc2 |
42 |
|
1da177e4c Linux-2.6.12-rc2 |
43 44 |
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" }; |
ad71860a1 ACPICA: minimal p... |
45 |
static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; |
1da177e4c Linux-2.6.12-rc2 |
46 |
|
4e381a4f0 Revert "ACPI: par... |
47 |
static int acpi_apic_instance __initdata; |
a1fdcc0d2 ACPI: Add support... |
48 |
|
4fc0a7e88 ACPI: Fix x86 reg... |
49 50 51 52 53 |
/* * Disable table checksum verification for the early stage due to the size * limitation of the current x86 early mapping implementation. */ static bool acpi_verify_table_checksum __initdata = false; |
a1fdcc0d2 ACPI: Add support... |
54 |
void acpi_table_print_madt_entry(struct acpi_subtable_header *header) |
1da177e4c Linux-2.6.12-rc2 |
55 56 57 58 59 |
{ if (!header) return; switch (header->type) { |
5f3b1a8b6 ACPICA: Remove du... |
60 |
case ACPI_MADT_TYPE_LOCAL_APIC: |
4be44fcd3 [ACPI] Lindent al... |
61 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
62 63 |
struct acpi_madt_local_apic *p = (struct acpi_madt_local_apic *)header; |
07f438df2 ACPI / table: Use... |
64 65 66 67 |
pr_debug("LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s) ", p->processor_id, p->id, (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); |
4be44fcd3 [ACPI] Lindent al... |
68 |
} |
1da177e4c Linux-2.6.12-rc2 |
69 |
break; |
7237d3de7 x86, ACPI: add su... |
70 71 72 73 |
case ACPI_MADT_TYPE_LOCAL_X2APIC: { struct acpi_madt_local_x2apic *p = (struct acpi_madt_local_x2apic *)header; |
07f438df2 ACPI / table: Use... |
74 75 76 77 |
pr_debug("X2APIC (apic_id[0x%02x] uid[0x%02x] %s) ", p->local_apic_id, p->uid, (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); |
7237d3de7 x86, ACPI: add su... |
78 79 |
} break; |
5f3b1a8b6 ACPICA: Remove du... |
80 |
case ACPI_MADT_TYPE_IO_APIC: |
4be44fcd3 [ACPI] Lindent al... |
81 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
82 83 |
struct acpi_madt_io_apic *p = (struct acpi_madt_io_apic *)header; |
07f438df2 ACPI / table: Use... |
84 85 86 |
pr_debug("IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d]) ", p->id, p->address, p->global_irq_base); |
4be44fcd3 [ACPI] Lindent al... |
87 |
} |
1da177e4c Linux-2.6.12-rc2 |
88 |
break; |
5f3b1a8b6 ACPICA: Remove du... |
89 |
case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: |
4be44fcd3 [ACPI] Lindent al... |
90 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
91 92 |
struct acpi_madt_interrupt_override *p = (struct acpi_madt_interrupt_override *)header; |
730bf5ebb ACPI / tables: Re... |
93 94 95 96 97 |
pr_info("INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s) ", p->bus, p->source_irq, p->global_irq, mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); |
5f3b1a8b6 ACPICA: Remove du... |
98 99 |
if (p->inti_flags & ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)) |
730bf5ebb ACPI / tables: Re... |
100 101 102 |
pr_info("INT_SRC_OVR unexpected reserved flags: 0x%x ", p->inti_flags & |
5f3b1a8b6 ACPICA: Remove du... |
103 |
~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)); |
4be44fcd3 [ACPI] Lindent al... |
104 |
} |
1da177e4c Linux-2.6.12-rc2 |
105 |
break; |
5f3b1a8b6 ACPICA: Remove du... |
106 |
case ACPI_MADT_TYPE_NMI_SOURCE: |
4be44fcd3 [ACPI] Lindent al... |
107 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
108 109 |
struct acpi_madt_nmi_source *p = (struct acpi_madt_nmi_source *)header; |
730bf5ebb ACPI / tables: Re... |
110 111 112 113 114 |
pr_info("NMI_SRC (%s %s global_irq %d) ", mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], p->global_irq); |
4be44fcd3 [ACPI] Lindent al... |
115 |
} |
1da177e4c Linux-2.6.12-rc2 |
116 |
break; |
5f3b1a8b6 ACPICA: Remove du... |
117 |
case ACPI_MADT_TYPE_LOCAL_APIC_NMI: |
4be44fcd3 [ACPI] Lindent al... |
118 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
119 120 |
struct acpi_madt_local_apic_nmi *p = (struct acpi_madt_local_apic_nmi *)header; |
730bf5ebb ACPI / tables: Re... |
121 122 123 124 125 126 |
pr_info("LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x]) ", p->processor_id, mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ], mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], p->lint); |
7237d3de7 x86, ACPI: add su... |
127 128 129 130 131 132 133 134 135 136 137 |
} break; case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: { u16 polarity, trigger; struct acpi_madt_local_x2apic_nmi *p = (struct acpi_madt_local_x2apic_nmi *)header; polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK; trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2; |
730bf5ebb ACPI / tables: Re... |
138 139 140 141 142 143 |
pr_info("X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x]) ", p->uid, mps_inti_flags_polarity[polarity], mps_inti_flags_trigger[trigger], p->lint); |
4be44fcd3 [ACPI] Lindent al... |
144 |
} |
1da177e4c Linux-2.6.12-rc2 |
145 |
break; |
5f3b1a8b6 ACPICA: Remove du... |
146 |
case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: |
4be44fcd3 [ACPI] Lindent al... |
147 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
148 149 |
struct acpi_madt_local_apic_override *p = (struct acpi_madt_local_apic_override *)header; |
730bf5ebb ACPI / tables: Re... |
150 151 152 |
pr_info("LAPIC_ADDR_OVR (address[%p]) ", (void *)(unsigned long)p->address); |
4be44fcd3 [ACPI] Lindent al... |
153 |
} |
1da177e4c Linux-2.6.12-rc2 |
154 |
break; |
5f3b1a8b6 ACPICA: Remove du... |
155 |
case ACPI_MADT_TYPE_IO_SAPIC: |
4be44fcd3 [ACPI] Lindent al... |
156 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
157 158 |
struct acpi_madt_io_sapic *p = (struct acpi_madt_io_sapic *)header; |
07f438df2 ACPI / table: Use... |
159 160 161 162 |
pr_debug("IOSAPIC (id[0x%x] address[%p] gsi_base[%d]) ", p->id, (void *)(unsigned long)p->address, p->global_irq_base); |
4be44fcd3 [ACPI] Lindent al... |
163 |
} |
1da177e4c Linux-2.6.12-rc2 |
164 |
break; |
5f3b1a8b6 ACPICA: Remove du... |
165 |
case ACPI_MADT_TYPE_LOCAL_SAPIC: |
4be44fcd3 [ACPI] Lindent al... |
166 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
167 168 |
struct acpi_madt_local_sapic *p = (struct acpi_madt_local_sapic *)header; |
07f438df2 ACPI / table: Use... |
169 170 171 172 |
pr_debug("LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s) ", p->processor_id, p->id, p->eid, (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); |
4be44fcd3 [ACPI] Lindent al... |
173 |
} |
1da177e4c Linux-2.6.12-rc2 |
174 |
break; |
5f3b1a8b6 ACPICA: Remove du... |
175 |
case ACPI_MADT_TYPE_INTERRUPT_SOURCE: |
4be44fcd3 [ACPI] Lindent al... |
176 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
177 178 |
struct acpi_madt_interrupt_source *p = (struct acpi_madt_interrupt_source *)header; |
730bf5ebb ACPI / tables: Re... |
179 180 181 182 183 184 |
pr_info("PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x] ", mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], p->type, p->id, p->eid, p->io_sapic_vector, p->global_irq); |
4be44fcd3 [ACPI] Lindent al... |
185 |
} |
1da177e4c Linux-2.6.12-rc2 |
186 |
break; |
4c1c8d7a7 ACPI / table: Pri... |
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
case ACPI_MADT_TYPE_GENERIC_INTERRUPT: { struct acpi_madt_generic_interrupt *p = (struct acpi_madt_generic_interrupt *)header; pr_debug("GICC (acpi_id[0x%04x] address[%llx] MPIDR[0x%llx] %s) ", p->uid, p->base_address, p->arm_mpidr, (p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: { struct acpi_madt_generic_distributor *p = (struct acpi_madt_generic_distributor *)header; pr_debug("GIC Distributor (gic_id[0x%04x] address[%llx] gsi_base[%d]) ", p->gic_id, p->base_address, p->global_irq_base); } break; |
1da177e4c Linux-2.6.12-rc2 |
210 |
default: |
730bf5ebb ACPI / tables: Re... |
211 212 213 |
pr_warn("Found unsupported MADT entry (type = 0x%x) ", header->type); |
1da177e4c Linux-2.6.12-rc2 |
214 215 216 |
break; } } |
9b3fedde2 ACPI / tables: Ad... |
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
/** * acpi_parse_entries_array - for each proc_num find a suitable subtable * * @id: table id (for debugging purposes) * @table_size: single entry size * @table_header: where does the table start? * @proc: array of acpi_subtable_proc struct containing entry id * and associated handler with it * @proc_num: how big proc is? * @max_entries: how many entries can we process? * * For each proc_num find a subtable with proc->id and run proc->handler * on it. Assumption is that there's only single handler for particular * entry id. * * On success returns sum of all matching entries for all proc handlers. * Otherwise, -ENODEV or -EINVAL is returned. */ static int __init acpi_parse_entries_array(char *id, unsigned long table_size, |
f08bb472b ACPI / table: Add... |
237 |
struct acpi_table_header *table_header, |
9b3fedde2 ACPI / tables: Ad... |
238 239 |
struct acpi_subtable_proc *proc, int proc_num, unsigned int max_entries) |
1da177e4c Linux-2.6.12-rc2 |
240 |
{ |
5f3b1a8b6 ACPICA: Remove du... |
241 |
struct acpi_subtable_header *entry; |
6eb87fed5 ACPI: acpi_table_... |
242 |
unsigned long table_end; |
9b3fedde2 ACPI / tables: Ad... |
243 |
int count = 0; |
8726d4f44 ACPI / tables: fi... |
244 |
int errs = 0; |
9b3fedde2 ACPI / tables: Ad... |
245 |
int i; |
1da177e4c Linux-2.6.12-rc2 |
246 |
|
68ca40693 ACPI: delete the ... |
247 |
if (acpi_disabled) |
e5b8fc6ac ACPI: check acpi_... |
248 |
return -ENODEV; |
9b3fedde2 ACPI / tables: Ad... |
249 |
if (!id) |
1da177e4c Linux-2.6.12-rc2 |
250 |
return -EINVAL; |
f08bb472b ACPI / table: Add... |
251 252 |
if (!table_size) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
253 |
|
6eb87fed5 ACPI: acpi_table_... |
254 |
if (!table_header) { |
730bf5ebb ACPI / tables: Re... |
255 256 |
pr_warn("%4.4s not present ", id); |
1da177e4c Linux-2.6.12-rc2 |
257 258 |
return -ENODEV; } |
6eb87fed5 ACPI: acpi_table_... |
259 |
table_end = (unsigned long)table_header + table_header->length; |
1da177e4c Linux-2.6.12-rc2 |
260 261 |
/* Parse all entries looking for a match. */ |
5f3b1a8b6 ACPICA: Remove du... |
262 |
entry = (struct acpi_subtable_header *) |
6eb87fed5 ACPI: acpi_table_... |
263 |
((unsigned long)table_header + table_size); |
1da177e4c Linux-2.6.12-rc2 |
264 |
|
5f3b1a8b6 ACPICA: Remove du... |
265 |
while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < |
6eb87fed5 ACPI: acpi_table_... |
266 |
table_end) { |
9b3fedde2 ACPI / tables: Ad... |
267 268 269 270 271 272 |
if (max_entries && count >= max_entries) break; for (i = 0; i < proc_num; i++) { if (entry->type != proc[i].id) continue; |
362414d9d ACPI / tables: te... |
273 |
if (!proc[i].handler || |
8726d4f44 ACPI / tables: fi... |
274 275 276 277 |
(!errs && proc[i].handler(entry, table_end))) { errs++; continue; } |
369d913b2 ACPI: Harden acpi... |
278 |
|
fa162a05d ACPI / tables: fi... |
279 |
proc[i].count++; |
9b3fedde2 ACPI / tables: Ad... |
280 |
break; |
4ceacd02f ACPI / table: Alw... |
281 |
} |
9b3fedde2 ACPI / tables: Ad... |
282 283 |
if (i != proc_num) count++; |
4ceacd02f ACPI / table: Alw... |
284 |
|
369d913b2 ACPI: Harden acpi... |
285 286 287 288 289 |
/* * If entry->length is 0, break from this loop to avoid * infinite loop. */ if (entry->length == 0) { |
9b3fedde2 ACPI / tables: Ad... |
290 291 |
pr_err("[%4.4s:0x%02x] Invalid zero length ", id, proc->id); |
f08bb472b ACPI / table: Add... |
292 |
return -EINVAL; |
369d913b2 ACPI: Harden acpi... |
293 |
} |
1da177e4c Linux-2.6.12-rc2 |
294 |
|
5f3b1a8b6 ACPICA: Remove du... |
295 |
entry = (struct acpi_subtable_header *) |
4be44fcd3 [ACPI] Lindent al... |
296 |
((unsigned long)entry + entry->length); |
1da177e4c Linux-2.6.12-rc2 |
297 |
} |
f08bb472b ACPI / table: Add... |
298 |
|
1da177e4c Linux-2.6.12-rc2 |
299 |
if (max_entries && count > max_entries) { |
99b0efd7c ACPI / tables: do... |
300 301 302 |
pr_warn("[%4.4s:0x%02x] found the maximum %i entries ", id, proc->id, count); |
1da177e4c Linux-2.6.12-rc2 |
303 |
} |
8726d4f44 ACPI / tables: fi... |
304 |
return errs ? -EINVAL : count; |
f08bb472b ACPI / table: Add... |
305 306 307 |
} int __init |
9b3fedde2 ACPI / tables: Ad... |
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
acpi_parse_entries(char *id, unsigned long table_size, acpi_tbl_entry_handler handler, struct acpi_table_header *table_header, int entry_id, unsigned int max_entries) { struct acpi_subtable_proc proc = { .id = entry_id, .handler = handler, }; return acpi_parse_entries_array(id, table_size, table_header, &proc, 1, max_entries); } int __init acpi_table_parse_entries_array(char *id, |
f08bb472b ACPI / table: Add... |
325 |
unsigned long table_size, |
9b3fedde2 ACPI / tables: Ad... |
326 |
struct acpi_subtable_proc *proc, int proc_num, |
f08bb472b ACPI / table: Add... |
327 328 329 330 331 332 333 334 335 |
unsigned int max_entries) { struct acpi_table_header *table_header = NULL; acpi_size tbl_size; int count; u32 instance = 0; if (acpi_disabled) return -ENODEV; |
9b3fedde2 ACPI / tables: Ad... |
336 |
if (!id) |
f08bb472b ACPI / table: Add... |
337 338 339 340 341 342 343 344 345 346 347 |
return -EINVAL; if (!strncmp(id, ACPI_SIG_MADT, 4)) instance = acpi_apic_instance; acpi_get_table_with_size(id, instance, &table_header, &tbl_size); if (!table_header) { pr_warn("%4.4s not present ", id); return -ENODEV; } |
9b3fedde2 ACPI / tables: Ad... |
348 349 |
count = acpi_parse_entries_array(id, table_size, table_header, proc, proc_num, max_entries); |
f08bb472b ACPI / table: Add... |
350 |
|
369d913b2 ACPI: Harden acpi... |
351 |
early_acpi_os_unmap_memory((char *)table_header, tbl_size); |
f08bb472b ACPI / table: Add... |
352 |
return count; |
1da177e4c Linux-2.6.12-rc2 |
353 |
} |
1da177e4c Linux-2.6.12-rc2 |
354 |
int __init |
9b3fedde2 ACPI / tables: Ad... |
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
acpi_table_parse_entries(char *id, unsigned long table_size, int entry_id, acpi_tbl_entry_handler handler, unsigned int max_entries) { struct acpi_subtable_proc proc = { .id = entry_id, .handler = handler, }; return acpi_table_parse_entries_array(id, table_size, &proc, 1, max_entries); } int __init |
5f3b1a8b6 ACPICA: Remove du... |
371 |
acpi_table_parse_madt(enum acpi_madt_type id, |
b43e1065c ACPICA: Cleanup t... |
372 |
acpi_tbl_entry_handler handler, unsigned int max_entries) |
1da177e4c Linux-2.6.12-rc2 |
373 |
{ |
6eb87fed5 ACPI: acpi_table_... |
374 |
return acpi_table_parse_entries(ACPI_SIG_MADT, |
4be44fcd3 [ACPI] Lindent al... |
375 376 |
sizeof(struct acpi_table_madt), id, handler, max_entries); |
1da177e4c Linux-2.6.12-rc2 |
377 |
} |
7f8f97c3c ACPI: acpi_table_... |
378 379 |
/** * acpi_table_parse - find table with @id, run @handler on it |
7f8f97c3c ACPI: acpi_table_... |
380 381 382 383 |
* @id: table id to find * @handler: handler to run * * Scan the ACPI System Descriptor Table (STD) for a table matching @id, |
f8a571b2a ACPI / tables: Re... |
384 385 386 |
* run @handler on it. * * Return 0 if table found, -errno if not. |
7f8f97c3c ACPI: acpi_table_... |
387 |
*/ |
b43e1065c ACPICA: Cleanup t... |
388 |
int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) |
1da177e4c Linux-2.6.12-rc2 |
389 |
{ |
ceb6c4683 ACPICA: Remove du... |
390 |
struct acpi_table_header *table = NULL; |
7d97277b7 acpi/x86: introdu... |
391 |
acpi_size tbl_size; |
a1fdcc0d2 ACPI: Add support... |
392 |
|
68ca40693 ACPI: delete the ... |
393 |
if (acpi_disabled) |
e5b8fc6ac ACPI: check acpi_... |
394 |
return -ENODEV; |
de2d1a7e9 ACPI / tables: Ch... |
395 |
if (!id || !handler) |
1da177e4c Linux-2.6.12-rc2 |
396 |
return -EINVAL; |
a1fdcc0d2 ACPI: Add support... |
397 |
if (strncmp(id, ACPI_SIG_MADT, 4) == 0) |
7d97277b7 acpi/x86: introdu... |
398 |
acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); |
a1fdcc0d2 ACPI: Add support... |
399 |
else |
7d97277b7 acpi/x86: introdu... |
400 |
acpi_get_table_with_size(id, 0, &table, &tbl_size); |
a1fdcc0d2 ACPI: Add support... |
401 |
|
ceb6c4683 ACPICA: Remove du... |
402 403 |
if (table) { handler(table); |
7d97277b7 acpi/x86: introdu... |
404 |
early_acpi_os_unmap_memory(table, tbl_size); |
ceb6c4683 ACPICA: Remove du... |
405 |
return 0; |
7f8f97c3c ACPI: acpi_table_... |
406 |
} else |
95df812db ACPI / table: Rep... |
407 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
408 |
} |
a1fdcc0d2 ACPI: Add support... |
409 410 411 412 413 414 415 416 |
/* * The BIOS is supposed to supply a single APIC/MADT, * but some report two. Provide a knob to use either. * (don't you wish instance 0 and 1 were not the same?) */ static void __init check_multiple_madt(void) { struct acpi_table_header *table = NULL; |
7d97277b7 acpi/x86: introdu... |
417 |
acpi_size tbl_size; |
a1fdcc0d2 ACPI: Add support... |
418 |
|
7d97277b7 acpi/x86: introdu... |
419 |
acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); |
a1fdcc0d2 ACPI: Add support... |
420 |
if (table) { |
730bf5ebb ACPI / tables: Re... |
421 422 423 424 425 426 427 |
pr_warn("BIOS bug: multiple APIC/MADT found, using %d ", acpi_apic_instance); pr_warn("If \"acpi_apic_instance=%d\" works better, " "notify linux-acpi@vger.kernel.org ", acpi_apic_instance ? 0 : 2); |
7d97277b7 acpi/x86: introdu... |
428 |
early_acpi_os_unmap_memory(table, tbl_size); |
a1fdcc0d2 ACPI: Add support... |
429 430 431 432 433 434 |
} else acpi_apic_instance = 0; return; } |
5ae74f2cc ACPI / tables: Mo... |
435 436 437 438 439 440 441 |
static void acpi_table_taint(struct acpi_table_header *table) { pr_warn("Override [%4.4s-%8.8s], this is unsafe: tainting kernel ", table->signature, table->oem_table_id); add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); } |
5d8813271 ACPI / tables: Co... |
442 |
#ifdef CONFIG_ACPI_TABLE_UPGRADE |
5ae74f2cc ACPI / tables: Mo... |
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 |
static u64 acpi_tables_addr; static int all_tables_size; /* Copied from acpica/tbutils.c:acpi_tb_checksum() */ static u8 __init acpi_table_checksum(u8 *buffer, u32 length) { u8 sum = 0; u8 *end = buffer + length; while (buffer < end) sum = (u8) (sum + *(buffer++)); return sum; } /* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */ static const char * const table_sigs[] = { ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ, ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT, ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF, ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET, ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI, ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA, ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL }; #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) |
5d8813271 ACPI / tables: Co... |
470 471 472 |
#define NR_ACPI_INITRD_TABLES 64 static struct cpio_data __initdata acpi_initrd_files[NR_ACPI_INITRD_TABLES]; static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES); |
5ae74f2cc ACPI / tables: Mo... |
473 474 |
#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) |
da3d3f98d ACPI / tables: ta... |
475 |
void __init acpi_table_upgrade(void) |
5ae74f2cc ACPI / tables: Mo... |
476 |
{ |
da3d3f98d ACPI / tables: ta... |
477 478 |
void *data = (void *)initrd_start; size_t size = initrd_end - initrd_start; |
5ae74f2cc ACPI / tables: Mo... |
479 480 481 482 483 484 485 486 |
int sig, no, table_nr = 0, total_offset = 0; long offset = 0; struct acpi_table_header *table; char cpio_path[32] = "kernel/firmware/acpi/"; struct cpio_data file; if (data == NULL || size == 0) return; |
5d8813271 ACPI / tables: Co... |
487 |
for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) { |
5ae74f2cc ACPI / tables: Mo... |
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
file = find_cpio_data(cpio_path, data, size, &offset); if (!file.data) break; data += offset; size -= offset; if (file.size < sizeof(struct acpi_table_header)) { pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s] ", cpio_path, file.name); continue; } table = file.data; for (sig = 0; table_sigs[sig]; sig++) if (!memcmp(table->signature, table_sigs[sig], 4)) break; if (!table_sigs[sig]) { pr_err("ACPI OVERRIDE: Unknown signature [%s%s] ", cpio_path, file.name); continue; } if (file.size != table->length) { pr_err("ACPI OVERRIDE: File length does not match table length [%s%s] ", cpio_path, file.name); continue; } if (acpi_table_checksum(file.data, table->length)) { pr_err("ACPI OVERRIDE: Bad table checksum [%s%s] ", cpio_path, file.name); continue; } pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x] ", table->signature, cpio_path, file.name, table->length); all_tables_size += table->length; acpi_initrd_files[table_nr].data = file.data; acpi_initrd_files[table_nr].size = file.size; table_nr++; } if (table_nr == 0) return; acpi_tables_addr = |
84b06ca31 ACPI / tables: mo... |
540 |
memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS, |
5ae74f2cc ACPI / tables: Mo... |
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 |
all_tables_size, PAGE_SIZE); if (!acpi_tables_addr) { WARN_ON(1); return; } /* * Only calling e820_add_reserve does not work and the * tables are invalid (memory got used) later. * memblock_reserve works as expected and the tables won't get modified. * But it's not enough on X86 because ioremap will * complain later (used by acpi_os_map_memory) that the pages * that should get mapped are not marked "reserved". * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area) * works fine. */ memblock_reserve(acpi_tables_addr, all_tables_size); arch_reserve_mem_area(acpi_tables_addr, all_tables_size); /* * early_ioremap only can remap 256k one time. If we map all * tables one time, we will hit the limit. Need to map chunks * one by one during copying the same as that in relocate_initrd(). */ for (no = 0; no < table_nr; no++) { unsigned char *src_p = acpi_initrd_files[no].data; phys_addr_t size = acpi_initrd_files[no].size; phys_addr_t dest_addr = acpi_tables_addr + total_offset; phys_addr_t slop, clen; char *dest_p; total_offset += size; while (size) { slop = dest_addr & ~PAGE_MASK; clen = size; if (clen > MAP_CHUNK_SIZE - slop) clen = MAP_CHUNK_SIZE - slop; |
ce0c1fcc7 ACPI / tables: ta... |
578 579 |
dest_p = early_memremap(dest_addr & PAGE_MASK, clen + slop); |
5ae74f2cc ACPI / tables: Mo... |
580 |
memcpy(dest_p + slop, src_p, clen); |
ce0c1fcc7 ACPI / tables: ta... |
581 |
early_memunmap(dest_p, clen + slop); |
5ae74f2cc ACPI / tables: Mo... |
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
src_p += clen; dest_addr += clen; size -= clen; } } } static acpi_status acpi_table_initrd_override(struct acpi_table_header *existing_table, acpi_physical_address *address, u32 *length) { int table_offset = 0; int table_index = 0; struct acpi_table_header *table; u32 table_length; *length = 0; *address = 0; if (!acpi_tables_addr) return AE_OK; while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { table = acpi_os_map_memory(acpi_tables_addr + table_offset, ACPI_HEADER_SIZE); if (table_offset + table->length > all_tables_size) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); WARN_ON(1); return AE_OK; } table_length = table->length; /* Only override tables matched */ |
5d8813271 ACPI / tables: Co... |
615 616 617 |
if (memcmp(existing_table->signature, table->signature, 4) || memcmp(table->oem_id, existing_table->oem_id, ACPI_OEM_ID_SIZE) || |
5ae74f2cc ACPI / tables: Mo... |
618 619 620 621 622 |
memcmp(table->oem_table_id, existing_table->oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } |
5d8813271 ACPI / tables: Co... |
623 624 625 626 627 628 629 630 631 |
/* * Mark the table to avoid being used in * acpi_table_initrd_scan() and check the revision. */ if (test_and_set_bit(table_index, acpi_initrd_installed) || existing_table->oem_revision >= table->oem_revision) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } |
5ae74f2cc ACPI / tables: Mo... |
632 633 634 |
*length = table_length; *address = acpi_tables_addr + table_offset; |
5d8813271 ACPI / tables: Co... |
635 636 637 638 |
pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s] ", table->signature, table->oem_id, table->oem_table_id); |
5ae74f2cc ACPI / tables: Mo... |
639 |
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); |
5ae74f2cc ACPI / tables: Mo... |
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 |
break; next_table: table_offset += table_length; table_index++; } return AE_OK; } static void __init acpi_table_initrd_scan(void) { int table_offset = 0; int table_index = 0; u32 table_length; struct acpi_table_header *table; if (!acpi_tables_addr) return; while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { table = acpi_os_map_memory(acpi_tables_addr + table_offset, ACPI_HEADER_SIZE); if (table_offset + table->length > all_tables_size) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); WARN_ON(1); return; } table_length = table->length; /* Skip RSDT/XSDT which should only be used for override */ |
5d8813271 ACPI / tables: Co... |
671 |
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) || |
5ae74f2cc ACPI / tables: Mo... |
672 673 674 675 |
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } |
5d8813271 ACPI / tables: Co... |
676 677 678 679 680 681 682 683 684 |
/* * Mark the table to avoid being used in * acpi_table_initrd_override(). Though this is not possible * because override is disabled in acpi_install_table(). */ if (test_and_set_bit(table_index, acpi_initrd_installed)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } |
5ae74f2cc ACPI / tables: Mo... |
685 |
|
5d8813271 ACPI / tables: Co... |
686 687 688 689 |
pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s] ", table->signature, table->oem_id, table->oem_table_id); |
5ae74f2cc ACPI / tables: Mo... |
690 691 |
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); acpi_install_table(acpi_tables_addr + table_offset, TRUE); |
5ae74f2cc ACPI / tables: Mo... |
692 693 694 695 696 697 |
next_table: table_offset += table_length; table_index++; } } #else |
5ae74f2cc ACPI / tables: Mo... |
698 699 700 701 702 703 704 705 706 707 708 709 710 |
static acpi_status acpi_table_initrd_override(struct acpi_table_header *existing_table, acpi_physical_address *address, u32 *table_length) { *table_length = 0; *address = 0; return AE_OK; } static void __init acpi_table_initrd_scan(void) { } |
5d8813271 ACPI / tables: Co... |
711 |
#endif /* CONFIG_ACPI_TABLE_UPGRADE */ |
5ae74f2cc ACPI / tables: Mo... |
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 |
acpi_status acpi_os_physical_table_override(struct acpi_table_header *existing_table, acpi_physical_address *address, u32 *table_length) { return acpi_table_initrd_override(existing_table, address, table_length); } acpi_status acpi_os_table_override(struct acpi_table_header *existing_table, struct acpi_table_header **new_table) { if (!existing_table || !new_table) return AE_BAD_PARAMETER; *new_table = NULL; #ifdef CONFIG_ACPI_CUSTOM_DSDT if (strncmp(existing_table->signature, "DSDT", 4) == 0) *new_table = (struct acpi_table_header *)AmlCode; #endif if (*new_table != NULL) acpi_table_taint(existing_table); return AE_OK; } |
1da177e4c Linux-2.6.12-rc2 |
739 740 741 742 743 |
/* * acpi_table_init() * * find RSDP, find and checksum SDT/XSDT. * checksum all tables, print SDT/XSDT |
5f3b1a8b6 ACPICA: Remove du... |
744 |
* |
1da177e4c Linux-2.6.12-rc2 |
745 746 |
* result: sdt_entry[] is initialized */ |
4be44fcd3 [ACPI] Lindent al... |
747 |
int __init acpi_table_init(void) |
1da177e4c Linux-2.6.12-rc2 |
748 |
{ |
9e3a9d1ed ACPI: disable ACP... |
749 |
acpi_status status; |
4fc0a7e88 ACPI: Fix x86 reg... |
750 751 752 753 754 755 756 757 758 |
if (acpi_verify_table_checksum) { pr_info("Early table checksum verification enabled "); acpi_gbl_verify_table_checksum = TRUE; } else { pr_info("Early table checksum verification disabled "); acpi_gbl_verify_table_checksum = FALSE; } |
9e3a9d1ed ACPI: disable ACP... |
759 760 |
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); if (ACPI_FAILURE(status)) |
95df812db ACPI / table: Rep... |
761 |
return -EINVAL; |
5ae74f2cc ACPI / tables: Mo... |
762 |
acpi_table_initrd_scan(); |
9e3a9d1ed ACPI: disable ACP... |
763 |
|
a1fdcc0d2 ACPI: Add support... |
764 765 766 767 768 769 |
check_multiple_madt(); return 0; } static int __init acpi_parse_apic_instance(char *str) { |
f0df2d6b5 acpi: add checkin... |
770 771 |
if (!str) return -EINVAL; |
a1fdcc0d2 ACPI: Add support... |
772 |
|
3d915894f ACPI: use kstrto*... |
773 774 |
if (kstrtoint(str, 0, &acpi_apic_instance)) return -EINVAL; |
a1fdcc0d2 ACPI: Add support... |
775 |
|
730bf5ebb ACPI / tables: Re... |
776 777 |
pr_notice("Shall use APIC/MADT table %d ", acpi_apic_instance); |
a1fdcc0d2 ACPI: Add support... |
778 |
|
1da177e4c Linux-2.6.12-rc2 |
779 780 |
return 0; } |
a1fdcc0d2 ACPI: Add support... |
781 782 |
early_param("acpi_apic_instance", acpi_parse_apic_instance); |
4fc0a7e88 ACPI: Fix x86 reg... |
783 784 785 786 787 788 789 790 791 |
static int __init acpi_force_table_verification_setup(char *s) { acpi_verify_table_checksum = true; return 0; } early_param("acpi_force_table_verification", acpi_force_table_verification_setup); |
b2ca5dae3 ACPI: Add acpi_fo... |
792 793 794 795 796 797 798 799 800 801 802 |
static int __init acpi_force_32bit_fadt_addr(char *s) { pr_info("Forcing 32 Bit FADT addresses "); acpi_gbl_use32_bit_fadt_addresses = TRUE; return 0; } early_param("acpi_force_32bit_fadt_addr", acpi_force_32bit_fadt_addr); |