^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ACPI 3.0 based NUMA setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2004 Andi Kleen, SuSE Labs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Called from acpi_numa_init while reading the SRAT and SLIT tables.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Assumes all memory regions belonging to a single proximity domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * are in one chunk. Holes between them will be included in the node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mmzone.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/bitmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/topology.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/proto.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/numa.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/e820/api.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/apic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/uv/uv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Callback for Proximity Domain -> x2APIC mapping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) void __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int pxm, node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int apic_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (srat_disabled())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) bad_srat();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) pxm = pa->proximity_domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) apic_id = pa->apic_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (!apic->apic_id_valid(apic_id)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) pxm, apic_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) node = acpi_map_pxm_to_node(pxm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (node < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) bad_srat();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (apic_id >= MAX_LOCAL_APIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) set_apicid_to_node(apic_id, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) node_set(node, numa_nodes_parsed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) pxm, apic_id, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* Callback for Proximity Domain -> LAPIC mapping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) void __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int pxm, node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int apic_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (srat_disabled())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) bad_srat();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) pxm = pa->proximity_domain_lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (acpi_srat_revision >= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) node = acpi_map_pxm_to_node(pxm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (node < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) bad_srat();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (get_uv_system_type() >= UV_X2APIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) apic_id = pa->apic_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (apic_id >= MAX_LOCAL_APIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) set_apicid_to_node(apic_id, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) node_set(node, numa_nodes_parsed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) pxm, apic_id, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int __init x86_acpi_numa_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ret = acpi_numa_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return srat_disabled() ? -EINVAL : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }