Blame view
drivers/acpi/tables.c
20.8 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 |
acpi_table_parse_entries_array(char *id, |
f08bb472b ACPI / table: Add... |
309 |
unsigned long table_size, |
9b3fedde2 ACPI / tables: Ad... |
310 |
struct acpi_subtable_proc *proc, int proc_num, |
f08bb472b ACPI / table: Add... |
311 312 313 |
unsigned int max_entries) { struct acpi_table_header *table_header = NULL; |
f08bb472b ACPI / table: Add... |
314 315 316 317 318 |
int count; u32 instance = 0; if (acpi_disabled) return -ENODEV; |
9b3fedde2 ACPI / tables: Ad... |
319 |
if (!id) |
f08bb472b ACPI / table: Add... |
320 321 322 323 |
return -EINVAL; if (!strncmp(id, ACPI_SIG_MADT, 4)) instance = acpi_apic_instance; |
6b11d1d67 ACPI / osl: Remov... |
324 |
acpi_get_table(id, instance, &table_header); |
f08bb472b ACPI / table: Add... |
325 326 327 328 329 |
if (!table_header) { pr_warn("%4.4s not present ", id); return -ENODEV; } |
9b3fedde2 ACPI / tables: Ad... |
330 331 |
count = acpi_parse_entries_array(id, table_size, table_header, proc, proc_num, max_entries); |
f08bb472b ACPI / table: Add... |
332 |
|
6b11d1d67 ACPI / osl: Remov... |
333 |
acpi_put_table(table_header); |
f08bb472b ACPI / table: Add... |
334 |
return count; |
1da177e4c Linux-2.6.12-rc2 |
335 |
} |
1da177e4c Linux-2.6.12-rc2 |
336 |
int __init |
9b3fedde2 ACPI / tables: Ad... |
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
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... |
353 |
acpi_table_parse_madt(enum acpi_madt_type id, |
b43e1065c ACPICA: Cleanup t... |
354 |
acpi_tbl_entry_handler handler, unsigned int max_entries) |
1da177e4c Linux-2.6.12-rc2 |
355 |
{ |
6eb87fed5 ACPI: acpi_table_... |
356 |
return acpi_table_parse_entries(ACPI_SIG_MADT, |
4be44fcd3 [ACPI] Lindent al... |
357 358 |
sizeof(struct acpi_table_madt), id, handler, max_entries); |
1da177e4c Linux-2.6.12-rc2 |
359 |
} |
7f8f97c3c ACPI: acpi_table_... |
360 361 |
/** * acpi_table_parse - find table with @id, run @handler on it |
7f8f97c3c ACPI: acpi_table_... |
362 363 364 365 |
* @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... |
366 367 368 |
* run @handler on it. * * Return 0 if table found, -errno if not. |
7f8f97c3c ACPI: acpi_table_... |
369 |
*/ |
b43e1065c ACPICA: Cleanup t... |
370 |
int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) |
1da177e4c Linux-2.6.12-rc2 |
371 |
{ |
ceb6c4683 ACPICA: Remove du... |
372 |
struct acpi_table_header *table = NULL; |
a1fdcc0d2 ACPI: Add support... |
373 |
|
68ca40693 ACPI: delete the ... |
374 |
if (acpi_disabled) |
e5b8fc6ac ACPI: check acpi_... |
375 |
return -ENODEV; |
de2d1a7e9 ACPI / tables: Ch... |
376 |
if (!id || !handler) |
1da177e4c Linux-2.6.12-rc2 |
377 |
return -EINVAL; |
a1fdcc0d2 ACPI: Add support... |
378 |
if (strncmp(id, ACPI_SIG_MADT, 4) == 0) |
6b11d1d67 ACPI / osl: Remov... |
379 |
acpi_get_table(id, acpi_apic_instance, &table); |
a1fdcc0d2 ACPI: Add support... |
380 |
else |
6b11d1d67 ACPI / osl: Remov... |
381 |
acpi_get_table(id, 0, &table); |
a1fdcc0d2 ACPI: Add support... |
382 |
|
ceb6c4683 ACPICA: Remove du... |
383 384 |
if (table) { handler(table); |
6b11d1d67 ACPI / osl: Remov... |
385 |
acpi_put_table(table); |
ceb6c4683 ACPICA: Remove du... |
386 |
return 0; |
7f8f97c3c ACPI: acpi_table_... |
387 |
} else |
95df812db ACPI / table: Rep... |
388 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
389 |
} |
a1fdcc0d2 ACPI: Add support... |
390 391 392 393 394 395 396 397 |
/* * 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; |
6b11d1d67 ACPI / osl: Remov... |
398 |
acpi_get_table(ACPI_SIG_MADT, 2, &table); |
a1fdcc0d2 ACPI: Add support... |
399 |
if (table) { |
730bf5ebb ACPI / tables: Re... |
400 401 402 403 404 405 406 |
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); |
6b11d1d67 ACPI / osl: Remov... |
407 |
acpi_put_table(table); |
a1fdcc0d2 ACPI: Add support... |
408 409 410 411 412 413 |
} else acpi_apic_instance = 0; return; } |
5ae74f2cc ACPI / tables: Mo... |
414 415 416 417 418 419 420 |
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... |
421 |
#ifdef CONFIG_ACPI_TABLE_UPGRADE |
5ae74f2cc ACPI / tables: Mo... |
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
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... |
449 450 451 |
#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... |
452 453 |
#define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) |
da3d3f98d ACPI / tables: ta... |
454 |
void __init acpi_table_upgrade(void) |
5ae74f2cc ACPI / tables: Mo... |
455 |
{ |
da3d3f98d ACPI / tables: ta... |
456 457 |
void *data = (void *)initrd_start; size_t size = initrd_end - initrd_start; |
5ae74f2cc ACPI / tables: Mo... |
458 459 460 461 462 463 464 465 |
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... |
466 |
for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) { |
5ae74f2cc ACPI / tables: Mo... |
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 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 |
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... |
519 |
memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS, |
5ae74f2cc ACPI / tables: Mo... |
520 521 522 523 524 525 526 527 528 529 530 531 |
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". |
ab6bc04cf x86/boot/e820: Cr... |
532 |
* Both memblock_reserve and e820__range_add (via arch_reserve_mem_area) |
5ae74f2cc ACPI / tables: Mo... |
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
* 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... |
557 558 |
dest_p = early_memremap(dest_addr & PAGE_MASK, clen + slop); |
5ae74f2cc ACPI / tables: Mo... |
559 |
memcpy(dest_p + slop, src_p, clen); |
ce0c1fcc7 ACPI / tables: ta... |
560 |
early_memunmap(dest_p, clen + slop); |
5ae74f2cc ACPI / tables: Mo... |
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
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... |
594 595 596 |
if (memcmp(existing_table->signature, table->signature, 4) || memcmp(table->oem_id, existing_table->oem_id, ACPI_OEM_ID_SIZE) || |
5ae74f2cc ACPI / tables: Mo... |
597 598 599 600 601 |
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... |
602 603 604 605 606 607 608 609 610 |
/* * 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... |
611 612 613 |
*length = table_length; *address = acpi_tables_addr + table_offset; |
5d8813271 ACPI / tables: Co... |
614 615 616 617 |
pr_info("Table Upgrade: override [%4.4s-%6.6s-%8.8s] ", table->signature, table->oem_id, table->oem_table_id); |
5ae74f2cc ACPI / tables: Mo... |
618 |
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); |
5ae74f2cc ACPI / tables: Mo... |
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 |
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... |
650 |
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) || |
5ae74f2cc ACPI / tables: Mo... |
651 652 653 654 |
ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) { acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); goto next_table; } |
5d8813271 ACPI / tables: Co... |
655 656 657 658 659 660 661 662 663 |
/* * 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... |
664 |
|
5d8813271 ACPI / tables: Co... |
665 666 667 668 |
pr_info("Table Upgrade: install [%4.4s-%6.6s-%8.8s] ", table->signature, table->oem_id, table->oem_table_id); |
5ae74f2cc ACPI / tables: Mo... |
669 670 |
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); acpi_install_table(acpi_tables_addr + table_offset, TRUE); |
5ae74f2cc ACPI / tables: Mo... |
671 672 673 674 675 676 |
next_table: table_offset += table_length; table_index++; } } #else |
5ae74f2cc ACPI / tables: Mo... |
677 678 679 680 681 682 683 684 685 686 687 688 689 |
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... |
690 |
#endif /* CONFIG_ACPI_TABLE_UPGRADE */ |
5ae74f2cc ACPI / tables: Mo... |
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 |
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 |
718 719 720 721 722 |
/* * acpi_table_init() * * find RSDP, find and checksum SDT/XSDT. * checksum all tables, print SDT/XSDT |
5f3b1a8b6 ACPICA: Remove du... |
723 |
* |
1da177e4c Linux-2.6.12-rc2 |
724 725 |
* result: sdt_entry[] is initialized */ |
4be44fcd3 [ACPI] Lindent al... |
726 |
int __init acpi_table_init(void) |
1da177e4c Linux-2.6.12-rc2 |
727 |
{ |
9e3a9d1ed ACPI: disable ACP... |
728 |
acpi_status status; |
4fc0a7e88 ACPI: Fix x86 reg... |
729 730 731 |
if (acpi_verify_table_checksum) { pr_info("Early table checksum verification enabled "); |
023e2ee16 ACPICA: Tables: C... |
732 |
acpi_gbl_enable_table_validation = TRUE; |
4fc0a7e88 ACPI: Fix x86 reg... |
733 734 735 |
} else { pr_info("Early table checksum verification disabled "); |
023e2ee16 ACPICA: Tables: C... |
736 |
acpi_gbl_enable_table_validation = FALSE; |
4fc0a7e88 ACPI: Fix x86 reg... |
737 |
} |
9e3a9d1ed ACPI: disable ACP... |
738 739 |
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); if (ACPI_FAILURE(status)) |
95df812db ACPI / table: Rep... |
740 |
return -EINVAL; |
5ae74f2cc ACPI / tables: Mo... |
741 |
acpi_table_initrd_scan(); |
9e3a9d1ed ACPI: disable ACP... |
742 |
|
a1fdcc0d2 ACPI: Add support... |
743 744 745 746 747 748 |
check_multiple_madt(); return 0; } static int __init acpi_parse_apic_instance(char *str) { |
f0df2d6b5 acpi: add checkin... |
749 750 |
if (!str) return -EINVAL; |
a1fdcc0d2 ACPI: Add support... |
751 |
|
3d915894f ACPI: use kstrto*... |
752 753 |
if (kstrtoint(str, 0, &acpi_apic_instance)) return -EINVAL; |
a1fdcc0d2 ACPI: Add support... |
754 |
|
730bf5ebb ACPI / tables: Re... |
755 756 |
pr_notice("Shall use APIC/MADT table %d ", acpi_apic_instance); |
a1fdcc0d2 ACPI: Add support... |
757 |
|
1da177e4c Linux-2.6.12-rc2 |
758 759 |
return 0; } |
a1fdcc0d2 ACPI: Add support... |
760 761 |
early_param("acpi_apic_instance", acpi_parse_apic_instance); |
4fc0a7e88 ACPI: Fix x86 reg... |
762 763 764 765 766 767 768 769 770 |
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... |
771 772 773 774 775 776 777 778 779 780 781 |
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); |