summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig3
-rw-r--r--drivers/acpi/numa/srat.c59
-rw-r--r--drivers/acpi/tables.c87
3 files changed, 127 insertions, 22 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 60b5424bd318..705331e3d87a 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -59,6 +59,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
config ACPI_CCA_REQUIRED
bool
+config ACPI_TABLE_LIB
+ bool
+
config ACPI_DEBUGGER
bool "AML debugger interface"
select ACPI_DEBUG
diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c
index 6c884f3e8332..3b818ab186be 100644
--- a/drivers/acpi/numa/srat.c
+++ b/drivers/acpi/numa/srat.c
@@ -297,6 +297,47 @@ out_err_bad_srat:
out_err:
return -EINVAL;
}
+
+static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
+ void *arg, const unsigned long table_end)
+{
+ struct acpi_cedt_cfmws *cfmws;
+ int *fake_pxm = arg;
+ u64 start, end;
+ int node;
+
+ cfmws = (struct acpi_cedt_cfmws *)header;
+ start = cfmws->base_hpa;
+ end = cfmws->base_hpa + cfmws->window_size;
+
+ /* Skip if the SRAT already described the NUMA details for this HPA */
+ node = phys_to_target_node(start);
+ if (node != NUMA_NO_NODE)
+ return 0;
+
+ node = acpi_map_pxm_to_node(*fake_pxm);
+
+ if (node == NUMA_NO_NODE) {
+ pr_err("ACPI NUMA: Too many proximity domains while processing CFMWS.\n");
+ return -EINVAL;
+ }
+
+ if (numa_add_memblk(node, start, end) < 0) {
+ /* CXL driver must handle the NUMA_NO_NODE case */
+ pr_warn("ACPI NUMA: Failed to add memblk for CFMWS node %d [mem %#llx-%#llx]\n",
+ node, start, end);
+ }
+
+ /* Set the next available fake_pxm value */
+ (*fake_pxm)++;
+ return 0;
+}
+#else
+static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
+ void *arg, const unsigned long table_end)
+{
+ return 0;
+}
#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */
static int __init acpi_parse_slit(struct acpi_table_header *table)
@@ -441,7 +482,7 @@ acpi_table_parse_srat(enum acpi_srat_type id,
int __init acpi_numa_init(void)
{
- int cnt = 0;
+ int i, fake_pxm, cnt = 0;
if (acpi_disabled)
return -EINVAL;
@@ -477,6 +518,22 @@ int __init acpi_numa_init(void)
/* SLIT: System Locality Information Table */
acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
+ /*
+ * CXL Fixed Memory Window Structures (CFMWS) must be parsed
+ * after the SRAT. Create NUMA Nodes for CXL memory ranges that
+ * are defined in the CFMWS and not already defined in the SRAT.
+ * Initialize a fake_pxm as the first available PXM to emulate.
+ */
+
+ /* fake_pxm is the next unused PXM value after SRAT parsing */
+ for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) {
+ if (node_to_pxm_map[i] > fake_pxm)
+ fake_pxm = node_to_pxm_map[i];
+ }
+ fake_pxm++;
+ acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, acpi_parse_cfmws,
+ &fake_pxm);
+
if (cnt < 0)
return cnt;
else if (!parsed_numa_memblks)
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 682a3ea9cb40..0741a4933f62 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -35,12 +35,13 @@ static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
-static int acpi_apic_instance __initdata;
+static int acpi_apic_instance __initdata_or_acpilib;
enum acpi_subtable_type {
ACPI_SUBTABLE_COMMON,
ACPI_SUBTABLE_HMAT,
ACPI_SUBTABLE_PRMT,
+ ACPI_SUBTABLE_CEDT,
};
struct acpi_subtable_entry {
@@ -52,7 +53,7 @@ struct acpi_subtable_entry {
* 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;
+static bool acpi_verify_table_checksum __initdata_or_acpilib = false;
void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
@@ -216,7 +217,7 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
}
}
-static unsigned long __init
+static unsigned long __init_or_acpilib
acpi_get_entry_type(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
@@ -226,11 +227,13 @@ acpi_get_entry_type(struct acpi_subtable_entry *entry)
return entry->hdr->hmat.type;
case ACPI_SUBTABLE_PRMT:
return 0;
+ case ACPI_SUBTABLE_CEDT:
+ return entry->hdr->cedt.type;
}
return 0;
}
-static unsigned long __init
+static unsigned long __init_or_acpilib
acpi_get_entry_length(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
@@ -240,11 +243,13 @@ acpi_get_entry_length(struct acpi_subtable_entry *entry)
return entry->hdr->hmat.length;
case ACPI_SUBTABLE_PRMT:
return entry->hdr->prmt.length;
+ case ACPI_SUBTABLE_CEDT:
+ return entry->hdr->cedt.length;
}
return 0;
}
-static unsigned long __init
+static unsigned long __init_or_acpilib
acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
@@ -254,20 +259,40 @@ acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
return sizeof(entry->hdr->hmat);
case ACPI_SUBTABLE_PRMT:
return sizeof(entry->hdr->prmt);
+ case ACPI_SUBTABLE_CEDT:
+ return sizeof(entry->hdr->cedt);
}
return 0;
}
-static enum acpi_subtable_type __init
+static enum acpi_subtable_type __init_or_acpilib
acpi_get_subtable_type(char *id)
{
if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
return ACPI_SUBTABLE_HMAT;
if (strncmp(id, ACPI_SIG_PRMT, 4) == 0)
return ACPI_SUBTABLE_PRMT;
+ if (strncmp(id, ACPI_SIG_CEDT, 4) == 0)
+ return ACPI_SUBTABLE_CEDT;
return ACPI_SUBTABLE_COMMON;
}
+static __init_or_acpilib bool has_handler(struct acpi_subtable_proc *proc)
+{
+ return proc->handler || proc->handler_arg;
+}
+
+static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc,
+ union acpi_subtable_headers *hdr,
+ unsigned long end)
+{
+ if (proc->handler)
+ return proc->handler(hdr, end);
+ if (proc->handler_arg)
+ return proc->handler_arg(hdr, proc->arg, end);
+ return -EINVAL;
+}
+
/**
* acpi_parse_entries_array - for each proc_num find a suitable subtable
*
@@ -291,10 +316,10 @@ acpi_get_subtable_type(char *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_subtable_proc *proc, int proc_num,
- unsigned int max_entries)
+static int __init_or_acpilib acpi_parse_entries_array(
+ char *id, unsigned long table_size,
+ struct acpi_table_header *table_header, struct acpi_subtable_proc *proc,
+ int proc_num, unsigned int max_entries)
{
struct acpi_subtable_entry entry;
unsigned long table_end, subtable_len, entry_len;
@@ -318,8 +343,9 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
for (i = 0; i < proc_num; i++) {
if (acpi_get_entry_type(&entry) != proc[i].id)
continue;
- if (!proc[i].handler ||
- (!errs && proc[i].handler(entry.hdr, table_end))) {
+ if (!has_handler(&proc[i]) ||
+ (!errs &&
+ call_handler(&proc[i], entry.hdr, table_end))) {
errs++;
continue;
}
@@ -352,10 +378,9 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
return errs ? -EINVAL : count;
}
-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 __init_or_acpilib acpi_table_parse_entries_array(
+ char *id, unsigned long table_size, struct acpi_subtable_proc *proc,
+ int proc_num, unsigned int max_entries)
{
struct acpi_table_header *table_header = NULL;
int count;
@@ -386,21 +411,41 @@ int __init acpi_table_parse_entries_array(char *id,
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)
+static int __init_or_acpilib __acpi_table_parse_entries(
+ char *id, unsigned long table_size, int entry_id,
+ acpi_tbl_entry_handler handler, acpi_tbl_entry_handler_arg handler_arg,
+ void *arg, unsigned int max_entries)
{
struct acpi_subtable_proc proc = {
.id = entry_id,
.handler = handler,
+ .handler_arg = handler_arg,
+ .arg = arg,
};
return acpi_table_parse_entries_array(id, table_size, &proc, 1,
max_entries);
}
+int __init_or_acpilib
+acpi_table_parse_cedt(enum acpi_cedt_type id,
+ acpi_tbl_entry_handler_arg handler_arg, void *arg)
+{
+ return __acpi_table_parse_entries(ACPI_SIG_CEDT,
+ sizeof(struct acpi_table_cedt), id,
+ NULL, handler_arg, arg, 0);
+}
+EXPORT_SYMBOL_ACPI_LIB(acpi_table_parse_cedt);
+
+int __init acpi_table_parse_entries(char *id, unsigned long table_size,
+ int entry_id,
+ acpi_tbl_entry_handler handler,
+ unsigned int max_entries)
+{
+ return __acpi_table_parse_entries(id, table_size, entry_id, handler,
+ NULL, NULL, max_entries);
+}
+
int __init acpi_table_parse_madt(enum acpi_madt_type id,
acpi_tbl_entry_handler handler, unsigned int max_entries)
{