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>
This commit is contained in:
Lukasz Anaczkowski 2015-09-09 15:47:28 +02:00 committed by Rafael J. Wysocki
parent 6ff33f3902
commit 9b3fedde27
2 changed files with 91 additions and 21 deletions

View File

@ -210,20 +210,39 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
}
}
int __init
acpi_parse_entries(char *id, unsigned long table_size,
acpi_tbl_entry_handler handler,
/**
* 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,
struct acpi_table_header *table_header,
int entry_id, unsigned int max_entries)
struct acpi_subtable_proc *proc, int proc_num,
unsigned int max_entries)
{
struct acpi_subtable_header *entry;
int count = 0;
unsigned long table_end;
int count = 0;
int i;
if (acpi_disabled)
return -ENODEV;
if (!id || !handler)
if (!id)
return -EINVAL;
if (!table_size)
@ -243,20 +262,27 @@ acpi_parse_entries(char *id, unsigned long table_size,
while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
table_end) {
if (entry->type == entry_id
&& (!max_entries || count < max_entries)) {
if (handler(entry, table_end))
if (max_entries && count >= max_entries)
break;
for (i = 0; i < proc_num; i++) {
if (entry->type != proc[i].id)
continue;
if (!proc->handler || proc[i].handler(entry, table_end))
return -EINVAL;
count++;
proc->count++;
break;
}
if (i != proc_num)
count++;
/*
* If entry->length is 0, break from this loop to avoid
* infinite loop.
*/
if (entry->length == 0) {
pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id);
return -EINVAL;
}
@ -266,17 +292,32 @@ acpi_parse_entries(char *id, unsigned long table_size,
if (max_entries && count > max_entries) {
pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
id, entry_id, count - max_entries, count);
id, proc->id, count - max_entries, count);
}
return count;
}
int __init
acpi_table_parse_entries(char *id,
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,
unsigned long table_size,
int entry_id,
acpi_tbl_entry_handler handler,
struct acpi_subtable_proc *proc, int proc_num,
unsigned int max_entries)
{
struct acpi_table_header *table_header = NULL;
@ -287,7 +328,7 @@ acpi_table_parse_entries(char *id,
if (acpi_disabled)
return -ENODEV;
if (!id || !handler)
if (!id)
return -EINVAL;
if (!strncmp(id, ACPI_SIG_MADT, 4))
@ -299,13 +340,29 @@ acpi_table_parse_entries(char *id,
return -ENODEV;
}
count = acpi_parse_entries(id, table_size, handler, table_header,
entry_id, max_entries);
count = acpi_parse_entries_array(id, table_size, table_header,
proc, proc_num, max_entries);
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
return count;
}
int __init
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
acpi_table_parse_madt(enum acpi_madt_type id,
acpi_tbl_entry_handler handler, unsigned int max_entries)

View File

@ -131,6 +131,12 @@ static inline void acpi_initrd_override(void *data, size_t size)
(!entry) || (unsigned long)entry + sizeof(*entry) > end || \
((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
struct acpi_subtable_proc {
int id;
acpi_tbl_entry_handler handler;
int count;
};
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
void __acpi_unmap_table(char *map, unsigned long size);
int early_acpi_boot_init(void);
@ -146,9 +152,16 @@ int __init acpi_parse_entries(char *id, unsigned long table_size,
struct acpi_table_header *table_header,
int entry_id, unsigned int max_entries);
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
int entry_id,
acpi_tbl_entry_handler handler,
unsigned int max_entries);
int entry_id,
acpi_tbl_entry_handler handler,
unsigned int max_entries);
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
int entry_id,
acpi_tbl_entry_handler handler,
unsigned int max_entries);
int __init acpi_table_parse_entries_array(char *id, unsigned long table_size,
struct acpi_subtable_proc *proc, int proc_num,
unsigned int max_entries);
int acpi_table_parse_madt(enum acpi_madt_type id,
acpi_tbl_entry_handler handler,
unsigned int max_entries);