#ifdef CONFIG_NUMA_EMU /* * Take max_nid - 1 fake-numa nodes into account in both * pxm_to_node_map()/node_to_pxm_map[] tables.
*/ int __init fix_pxm_node_maps(int max_nid)
{ staticint pxm_to_node_map_copy[MAX_PXM_DOMAINS] __initdata
= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE }; staticint node_to_pxm_map_copy[MAX_NUMNODES] __initdata
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; int i, j, index = -1, count = 0;
nodemask_t nodes_to_enable;
if (numa_off) return -1;
/* no or incomplete node/PXM mapping set, nothing to do */ if (srat_disabled()) return 0;
/* find fake nodes PXM mapping */ for (i = 0; i < MAX_NUMNODES; i++) { if (node_to_pxm_map[i] != PXM_INVAL) { for (j = 0; j <= max_nid; j++) { if ((emu_nid_to_phys[j] == i) &&
WARN(node_to_pxm_map_copy[j] != PXM_INVAL, "Node %d is already binded to PXM %d\n",
j, node_to_pxm_map_copy[j])) return -1; if (emu_nid_to_phys[j] == i) {
node_to_pxm_map_copy[j] =
node_to_pxm_map[i]; if (j > index)
index = j;
count++;
}
}
}
} if (index == -1) {
pr_debug("No node/PXM mapping has been set\n"); /* nothing more to be done */ return 0;
} if (WARN(index != max_nid, "%d max nid when expected %d\n",
index, max_nid)) return -1;
nodes_clear(nodes_to_enable);
/* map phys nodes not used for fake nodes */ for (i = 0; i < MAX_NUMNODES; i++) { if (node_to_pxm_map[i] != PXM_INVAL) { for (j = 0; j <= max_nid; j++) if (emu_nid_to_phys[j] == i) break; /* fake nodes PXM mapping has been done */ if (j <= max_nid) continue; /* find first hole */ for (j = 0;
j < MAX_NUMNODES &&
node_to_pxm_map_copy[j] != PXM_INVAL;
j++)
; if (WARN(j == MAX_NUMNODES, "Number of nodes exceeds MAX_NUMNODES\n")) return -1;
node_to_pxm_map_copy[j] = node_to_pxm_map[i];
node_set(j, nodes_to_enable);
count++;
}
}
/* creating reverse mapping in pxm_to_node_map[] */ for (i = 0; i < MAX_NUMNODES; i++) if (node_to_pxm_map_copy[i] != PXM_INVAL &&
pxm_to_node_map_copy[node_to_pxm_map_copy[i]] == NUMA_NO_NODE)
pxm_to_node_map_copy[node_to_pxm_map_copy[i]] = i;
/* overwrite with new mapping */ for (i = 0; i < MAX_NUMNODES; i++) {
node_to_pxm_map[i] = node_to_pxm_map_copy[i];
pxm_to_node_map[i] = pxm_to_node_map_copy[i];
}
/* enable other nodes found in PXM for hotplug */
nodes_or(numa_nodes_parsed, nodes_to_enable, numa_nodes_parsed);
pr_debug("found %d total number of nodes\n", count); return 0;
} #endif
case ACPI_SRAT_TYPE_GENERIC_AFFINITY:
{ struct acpi_srat_generic_affinity *p =
(struct acpi_srat_generic_affinity *)header;
if (p->device_handle_type == 1) { /* * For pci devices this may be the only place they * are assigned a proximity domain
*/
pr_debug("SRAT Generic Initiator(Seg:%u BDF:%u) in proximity domain %d %s\n",
*(u16 *)(&p->device_handle[0]),
*(u16 *)(&p->device_handle[2]),
p->proximity_domain,
str_enabled_disabled(p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED));
} else { /* * In this case we can rely on the device having a * proximity domain reference
*/
pr_debug("SRAT Generic Initiator(HID=%.8s UID=%.4s) in proximity domain %d %s\n",
(char *)(&p->device_handle[0]),
(char *)(&p->device_handle[8]),
p->proximity_domain,
str_enabled_disabled(p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED));
}
} break;
/* * A lot of BIOS fill in 10 (= no distance) everywhere. This messes * up the NUMA heuristics which wants the local node to have a smaller * distance than the others. * Do some quick checks here and only use the SLIT if it passes.
*/ staticint __init slit_valid(struct acpi_table_slit *slit)
{ int i, j; int d = slit->locality_count; for (i = 0; i < d; i++) { for (j = 0; j < d; j++) {
u8 val = slit->entry[d*i + j]; if (i == j) { if (val != LOCAL_DISTANCE) return 0;
} elseif (val <= LOCAL_DISTANCE) return 0;
}
} return 1;
}
void __init bad_srat(void)
{
pr_err("SRAT: SRAT not used.\n");
disable_srat();
}
int __init srat_disabled(void)
{ return acpi_numa < 0;
}
/* * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for * I/O localities since SRAT does not list them. I/O localities are * not supported at this point.
*/ staticint __init acpi_parse_slit(struct acpi_table_header *table)
{ struct acpi_table_slit *slit = (struct acpi_table_slit *)table; int i, j;
if (!slit_valid(slit)) {
pr_info("SLIT table looks invalid. Not used.\n"); return -EINVAL;
}
for (i = 0; i < slit->locality_count; i++) { constint from_node = pxm_to_node(i);
/* Mark hotplug range in memblock. */ if (hotpluggable && memblock_mark_hotplug(start, ma->length))
pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n",
(unsignedlonglong)start, (unsignedlonglong)end - 1);
/* Align memblock size to CFMW regions if possible */
align = 1UL << __ffs(start | end); if (align >= SZ_256M) {
err = memory_block_advise_max_size(align); if (err)
pr_warn("CFMWS: memblock size advise failed (%d)\n", err);
} else
pr_err("CFMWS: [BIOS BUG] base/size alignment violates spec\n");
/* * The SRAT may have already described NUMA details for all, * or a portion of, this CFMWS HPA range. Extend the memblks * found for any portion of the window to cover the entire * window.
*/ if (!numa_fill_memblks(start, end)) return 0;
/* No SRAT description. Create a new node. */
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_reserved_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);
}
node_set(node, numa_nodes_parsed);
/* Set the next available fake_pxm value */
(*fake_pxm)++; return 0;
}
int __init acpi_numa_init(void)
{ int i, fake_pxm, cnt = 0;
if (acpi_disabled) return -EINVAL;
/* * Should not limit number with cpu num that is from NR_CPUS or nr_cpus= * SRAT cpu entries could have different order with that in MADT. * So go over all cpu entries in SRAT to get apicid to node mapping.
*/
/* SRAT: System Resource Affinity Table */ if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { struct acpi_subtable_proc srat_proc[5];
/* 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; i++) { if (node_to_pxm_map[i] > fake_pxm)
fake_pxm = node_to_pxm_map[i];
}
last_real_pxm = fake_pxm;
fake_pxm++;
acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, acpi_parse_cfmws,
&fake_pxm);
do {
handle = phandle;
status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm); if (ACPI_SUCCESS(status)) return pxm;
status = acpi_get_parent(handle, &phandle);
} while (ACPI_SUCCESS(status)); return -1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.