diff options
author | Lukasz Anaczkowski <lukasz.anaczkowski@intel.com> | 2015-09-09 09:47:28 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-10-14 19:29:39 -0400 |
commit | 9b3fedde27d3d63055c43c05e8254e252e58ba48 (patch) | |
tree | 0ce3f5e0b33bc55ecb395fd4644058086c17da97 | |
parent | 6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff) |
ACPI / tables: Add acpi_subtable_proc to ACPI table parsers
ACPI subtable parsing needs to be extended to allow two or more
handlers to be run in the same ACPI table walk, thus adding
acpi_subtable_proc structure which stores
() ACPI table id
() handler that processes table
() counter how many items has been processed
and passing it to acpi_parse_entries_array() and
acpi_table_parse_entries_array().
This is needed to fix CPU enumeration when APIC/X2APIC entries
are interleaved.
Signed-off-by: Lukasz Anaczkowski <lukasz.anaczkowski@intel.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Tested-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/tables.c | 93 | ||||
-rw-r--r-- | include/linux/acpi.h | 19 |
2 files changed, 91 insertions, 21 deletions
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 17a6fa01a338..c1ff58de99e9 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c | |||
@@ -210,20 +210,39 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) | |||
210 | } | 210 | } |
211 | } | 211 | } |
212 | 212 | ||
213 | int __init | 213 | /** |
214 | acpi_parse_entries(char *id, unsigned long table_size, | 214 | * acpi_parse_entries_array - for each proc_num find a suitable subtable |
215 | acpi_tbl_entry_handler handler, | 215 | * |
216 | * @id: table id (for debugging purposes) | ||
217 | * @table_size: single entry size | ||
218 | * @table_header: where does the table start? | ||
219 | * @proc: array of acpi_subtable_proc struct containing entry id | ||
220 | * and associated handler with it | ||
221 | * @proc_num: how big proc is? | ||
222 | * @max_entries: how many entries can we process? | ||
223 | * | ||
224 | * For each proc_num find a subtable with proc->id and run proc->handler | ||
225 | * on it. Assumption is that there's only single handler for particular | ||
226 | * entry id. | ||
227 | * | ||
228 | * On success returns sum of all matching entries for all proc handlers. | ||
229 | * Otherwise, -ENODEV or -EINVAL is returned. | ||
230 | */ | ||
231 | static int __init | ||
232 | acpi_parse_entries_array(char *id, unsigned long table_size, | ||
216 | struct acpi_table_header *table_header, | 233 | struct acpi_table_header *table_header, |
217 | int entry_id, unsigned int max_entries) | 234 | struct acpi_subtable_proc *proc, int proc_num, |
235 | unsigned int max_entries) | ||
218 | { | 236 | { |
219 | struct acpi_subtable_header *entry; | 237 | struct acpi_subtable_header *entry; |
220 | int count = 0; | ||
221 | unsigned long table_end; | 238 | unsigned long table_end; |
239 | int count = 0; | ||
240 | int i; | ||
222 | 241 | ||
223 | if (acpi_disabled) | 242 | if (acpi_disabled) |
224 | return -ENODEV; | 243 | return -ENODEV; |
225 | 244 | ||
226 | if (!id || !handler) | 245 | if (!id) |
227 | return -EINVAL; | 246 | return -EINVAL; |
228 | 247 | ||
229 | if (!table_size) | 248 | if (!table_size) |
@@ -243,20 +262,27 @@ acpi_parse_entries(char *id, unsigned long table_size, | |||
243 | 262 | ||
244 | while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < | 263 | while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < |
245 | table_end) { | 264 | table_end) { |
246 | if (entry->type == entry_id | 265 | if (max_entries && count >= max_entries) |
247 | && (!max_entries || count < max_entries)) { | 266 | break; |
248 | if (handler(entry, table_end)) | 267 | |
268 | for (i = 0; i < proc_num; i++) { | ||
269 | if (entry->type != proc[i].id) | ||
270 | continue; | ||
271 | if (!proc->handler || proc[i].handler(entry, table_end)) | ||
249 | return -EINVAL; | 272 | return -EINVAL; |
250 | 273 | ||
251 | count++; | 274 | proc->count++; |
275 | break; | ||
252 | } | 276 | } |
277 | if (i != proc_num) | ||
278 | count++; | ||
253 | 279 | ||
254 | /* | 280 | /* |
255 | * If entry->length is 0, break from this loop to avoid | 281 | * If entry->length is 0, break from this loop to avoid |
256 | * infinite loop. | 282 | * infinite loop. |
257 | */ | 283 | */ |
258 | if (entry->length == 0) { | 284 | if (entry->length == 0) { |
259 | pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id); | 285 | pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id); |
260 | return -EINVAL; | 286 | return -EINVAL; |
261 | } | 287 | } |
262 | 288 | ||
@@ -266,17 +292,32 @@ acpi_parse_entries(char *id, unsigned long table_size, | |||
266 | 292 | ||
267 | if (max_entries && count > max_entries) { | 293 | if (max_entries && count > max_entries) { |
268 | pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n", | 294 | pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n", |
269 | id, entry_id, count - max_entries, count); | 295 | id, proc->id, count - max_entries, count); |
270 | } | 296 | } |
271 | 297 | ||
272 | return count; | 298 | return count; |
273 | } | 299 | } |
274 | 300 | ||
275 | int __init | 301 | int __init |
276 | acpi_table_parse_entries(char *id, | 302 | acpi_parse_entries(char *id, |
303 | unsigned long table_size, | ||
304 | acpi_tbl_entry_handler handler, | ||
305 | struct acpi_table_header *table_header, | ||
306 | int entry_id, unsigned int max_entries) | ||
307 | { | ||
308 | struct acpi_subtable_proc proc = { | ||
309 | .id = entry_id, | ||
310 | .handler = handler, | ||
311 | }; | ||
312 | |||
313 | return acpi_parse_entries_array(id, table_size, table_header, | ||
314 | &proc, 1, max_entries); | ||
315 | } | ||
316 | |||
317 | int __init | ||
318 | acpi_table_parse_entries_array(char *id, | ||
277 | unsigned long table_size, | 319 | unsigned long table_size, |
278 | int entry_id, | 320 | struct acpi_subtable_proc *proc, int proc_num, |
279 | acpi_tbl_entry_handler handler, | ||
280 | unsigned int max_entries) | 321 | unsigned int max_entries) |
281 | { | 322 | { |
282 | struct acpi_table_header *table_header = NULL; | 323 | struct acpi_table_header *table_header = NULL; |
@@ -287,7 +328,7 @@ acpi_table_parse_entries(char *id, | |||
287 | if (acpi_disabled) | 328 | if (acpi_disabled) |
288 | return -ENODEV; | 329 | return -ENODEV; |
289 | 330 | ||
290 | if (!id || !handler) | 331 | if (!id) |
291 | return -EINVAL; | 332 | return -EINVAL; |
292 | 333 | ||
293 | if (!strncmp(id, ACPI_SIG_MADT, 4)) | 334 | if (!strncmp(id, ACPI_SIG_MADT, 4)) |
@@ -299,14 +340,30 @@ acpi_table_parse_entries(char *id, | |||
299 | return -ENODEV; | 340 | return -ENODEV; |
300 | } | 341 | } |
301 | 342 | ||
302 | count = acpi_parse_entries(id, table_size, handler, table_header, | 343 | count = acpi_parse_entries_array(id, table_size, table_header, |
303 | entry_id, max_entries); | 344 | proc, proc_num, max_entries); |
304 | 345 | ||
305 | early_acpi_os_unmap_memory((char *)table_header, tbl_size); | 346 | early_acpi_os_unmap_memory((char *)table_header, tbl_size); |
306 | return count; | 347 | return count; |
307 | } | 348 | } |
308 | 349 | ||
309 | int __init | 350 | int __init |
351 | acpi_table_parse_entries(char *id, | ||
352 | unsigned long table_size, | ||
353 | int entry_id, | ||
354 | acpi_tbl_entry_handler handler, | ||
355 | unsigned int max_entries) | ||
356 | { | ||
357 | struct acpi_subtable_proc proc = { | ||
358 | .id = entry_id, | ||
359 | .handler = handler, | ||
360 | }; | ||
361 | |||
362 | return acpi_table_parse_entries_array(id, table_size, &proc, 1, | ||
363 | max_entries); | ||
364 | } | ||
365 | |||
366 | int __init | ||
310 | acpi_table_parse_madt(enum acpi_madt_type id, | 367 | acpi_table_parse_madt(enum acpi_madt_type id, |
311 | acpi_tbl_entry_handler handler, unsigned int max_entries) | 368 | acpi_tbl_entry_handler handler, unsigned int max_entries) |
312 | { | 369 | { |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 7235c4851460..b0299f8db660 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -131,6 +131,12 @@ static inline void acpi_initrd_override(void *data, size_t size) | |||
131 | (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ | 131 | (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ |
132 | ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) | 132 | ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) |
133 | 133 | ||
134 | struct acpi_subtable_proc { | ||
135 | int id; | ||
136 | acpi_tbl_entry_handler handler; | ||
137 | int count; | ||
138 | }; | ||
139 | |||
134 | char * __acpi_map_table (unsigned long phys_addr, unsigned long size); | 140 | char * __acpi_map_table (unsigned long phys_addr, unsigned long size); |
135 | void __acpi_unmap_table(char *map, unsigned long size); | 141 | void __acpi_unmap_table(char *map, unsigned long size); |
136 | int early_acpi_boot_init(void); | 142 | int early_acpi_boot_init(void); |
@@ -146,9 +152,16 @@ int __init acpi_parse_entries(char *id, unsigned long table_size, | |||
146 | struct acpi_table_header *table_header, | 152 | struct acpi_table_header *table_header, |
147 | int entry_id, unsigned int max_entries); | 153 | int entry_id, unsigned int max_entries); |
148 | int __init acpi_table_parse_entries(char *id, unsigned long table_size, | 154 | int __init acpi_table_parse_entries(char *id, unsigned long table_size, |
149 | int entry_id, | 155 | int entry_id, |
150 | acpi_tbl_entry_handler handler, | 156 | acpi_tbl_entry_handler handler, |
151 | unsigned int max_entries); | 157 | unsigned int max_entries); |
158 | int __init acpi_table_parse_entries(char *id, unsigned long table_size, | ||
159 | int entry_id, | ||
160 | acpi_tbl_entry_handler handler, | ||
161 | unsigned int max_entries); | ||
162 | int __init acpi_table_parse_entries_array(char *id, unsigned long table_size, | ||
163 | struct acpi_subtable_proc *proc, int proc_num, | ||
164 | unsigned int max_entries); | ||
152 | int acpi_table_parse_madt(enum acpi_madt_type id, | 165 | int acpi_table_parse_madt(enum acpi_madt_type id, |
153 | acpi_tbl_entry_handler handler, | 166 | acpi_tbl_entry_handler handler, |
154 | unsigned int max_entries); | 167 | unsigned int max_entries); |