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:
parent
6ff33f3902
commit
9b3fedde27
@ -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_parse_entries_array - for each proc_num find a suitable subtable
|
||||||
acpi_tbl_entry_handler handler,
|
*
|
||||||
|
* @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,
|
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;
|
struct acpi_subtable_header *entry;
|
||||||
int count = 0;
|
|
||||||
unsigned long table_end;
|
unsigned long table_end;
|
||||||
|
int count = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (acpi_disabled)
|
if (acpi_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!id || !handler)
|
if (!id)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!table_size)
|
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) <
|
while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
|
||||||
table_end) {
|
table_end) {
|
||||||
if (entry->type == entry_id
|
if (max_entries && count >= max_entries)
|
||||||
&& (!max_entries || count < max_entries)) {
|
break;
|
||||||
if (handler(entry, table_end))
|
|
||||||
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
count++;
|
proc->count++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (i != proc_num)
|
||||||
|
count++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If entry->length is 0, break from this loop to avoid
|
* If entry->length is 0, break from this loop to avoid
|
||||||
* infinite loop.
|
* infinite loop.
|
||||||
*/
|
*/
|
||||||
if (entry->length == 0) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,17 +292,32 @@ acpi_parse_entries(char *id, unsigned long table_size,
|
|||||||
|
|
||||||
if (max_entries && count > max_entries) {
|
if (max_entries && count > max_entries) {
|
||||||
pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __init
|
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,
|
unsigned long table_size,
|
||||||
int entry_id,
|
struct acpi_subtable_proc *proc, int proc_num,
|
||||||
acpi_tbl_entry_handler handler,
|
|
||||||
unsigned int max_entries)
|
unsigned int max_entries)
|
||||||
{
|
{
|
||||||
struct acpi_table_header *table_header = NULL;
|
struct acpi_table_header *table_header = NULL;
|
||||||
@ -287,7 +328,7 @@ acpi_table_parse_entries(char *id,
|
|||||||
if (acpi_disabled)
|
if (acpi_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!id || !handler)
|
if (!id)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!strncmp(id, ACPI_SIG_MADT, 4))
|
if (!strncmp(id, ACPI_SIG_MADT, 4))
|
||||||
@ -299,13 +340,29 @@ acpi_table_parse_entries(char *id,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = acpi_parse_entries(id, table_size, handler, table_header,
|
count = acpi_parse_entries_array(id, table_size, table_header,
|
||||||
entry_id, max_entries);
|
proc, proc_num, max_entries);
|
||||||
|
|
||||||
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
|
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
|
||||||
return count;
|
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
|
int __init
|
||||||
acpi_table_parse_madt(enum acpi_madt_type id,
|
acpi_table_parse_madt(enum acpi_madt_type id,
|
||||||
acpi_tbl_entry_handler handler, unsigned int max_entries)
|
acpi_tbl_entry_handler handler, unsigned int max_entries)
|
||||||
|
@ -131,6 +131,12 @@ static inline void acpi_initrd_override(void *data, size_t size)
|
|||||||
(!entry) || (unsigned long)entry + sizeof(*entry) > end || \
|
(!entry) || (unsigned long)entry + sizeof(*entry) > end || \
|
||||||
((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
|
((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);
|
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
|
||||||
void __acpi_unmap_table(char *map, unsigned long size);
|
void __acpi_unmap_table(char *map, unsigned long size);
|
||||||
int early_acpi_boot_init(void);
|
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,
|
struct acpi_table_header *table_header,
|
||||||
int entry_id, unsigned int max_entries);
|
int entry_id, unsigned int max_entries);
|
||||||
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
|
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
|
||||||
int entry_id,
|
int entry_id,
|
||||||
acpi_tbl_entry_handler handler,
|
acpi_tbl_entry_handler handler,
|
||||||
unsigned int max_entries);
|
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,
|
int acpi_table_parse_madt(enum acpi_madt_type id,
|
||||||
acpi_tbl_entry_handler handler,
|
acpi_tbl_entry_handler handler,
|
||||||
unsigned int max_entries);
|
unsigned int max_entries);
|
||||||
|
Loading…
Reference in New Issue
Block a user