linux/arch/x86/mm/srat.c
<<
>>
Prefs
   1/*
   2 * ACPI 3.0 based NUMA setup
   3 * Copyright 2004 Andi Kleen, SuSE Labs.
   4 *
   5 * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs.
   6 *
   7 * Called from acpi_numa_init while reading the SRAT and SLIT tables.
   8 * Assumes all memory regions belonging to a single proximity domain
   9 * are in one chunk. Holes between them will be included in the node.
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/acpi.h>
  14#include <linux/mmzone.h>
  15#include <linux/bitmap.h>
  16#include <linux/init.h>
  17#include <linux/topology.h>
  18#include <linux/bootmem.h>
  19#include <linux/memblock.h>
  20#include <linux/mm.h>
  21#include <asm/proto.h>
  22#include <asm/numa.h>
  23#include <asm/e820.h>
  24#include <asm/apic.h>
  25#include <asm/uv/uv.h>
  26
  27int acpi_numa __initdata;
  28
  29static __init int setup_node(int pxm)
  30{
  31        return acpi_map_pxm_to_node(pxm);
  32}
  33
  34static __init void bad_srat(void)
  35{
  36        printk(KERN_ERR "SRAT: SRAT not used.\n");
  37        acpi_numa = -1;
  38}
  39
  40static __init inline int srat_disabled(void)
  41{
  42        return acpi_numa < 0;
  43}
  44
  45/*
  46 * Callback for SLIT parsing.  pxm_to_node() returns NUMA_NO_NODE for
  47 * I/O localities since SRAT does not list them.  I/O localities are
  48 * not supported at this point.
  49 */
  50void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
  51{
  52        int i, j;
  53
  54        for (i = 0; i < slit->locality_count; i++) {
  55                if (pxm_to_node(i) == NUMA_NO_NODE)
  56                        continue;
  57                for (j = 0; j < slit->locality_count; j++) {
  58                        if (pxm_to_node(j) == NUMA_NO_NODE)
  59                                continue;
  60                        numa_set_distance(pxm_to_node(i), pxm_to_node(j),
  61                                slit->entry[slit->locality_count * i + j]);
  62                }
  63        }
  64}
  65
  66/* Callback for Proximity Domain -> x2APIC mapping */
  67void __init
  68acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
  69{
  70        int pxm, node;
  71        int apic_id;
  72
  73        if (srat_disabled())
  74                return;
  75        if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
  76                bad_srat();
  77                return;
  78        }
  79        if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
  80                return;
  81        pxm = pa->proximity_domain;
  82        apic_id = pa->apic_id;
  83        if (!apic->apic_id_valid(apic_id)) {
  84                printk(KERN_INFO "SRAT: PXM %u -> X2APIC 0x%04x ignored\n",
  85                         pxm, apic_id);
  86                return;
  87        }
  88        node = setup_node(pxm);
  89        if (node < 0) {
  90                printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
  91                bad_srat();
  92                return;
  93        }
  94
  95        if (apic_id >= MAX_LOCAL_APIC) {
  96                printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
  97                return;
  98        }
  99        set_apicid_to_node(apic_id, node);
 100        node_set(node, numa_nodes_parsed);
 101        acpi_numa = 1;
 102        printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n",
 103               pxm, apic_id, node);
 104}
 105
 106/* Callback for Proximity Domain -> LAPIC mapping */
 107void __init
 108acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
 109{
 110        int pxm, node;
 111        int apic_id;
 112
 113        if (srat_disabled())
 114                return;
 115        if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
 116                bad_srat();
 117                return;
 118        }
 119        if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
 120                return;
 121        pxm = pa->proximity_domain_lo;
 122        if (acpi_srat_revision >= 2)
 123                pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8;
 124        node = setup_node(pxm);
 125        if (node < 0) {
 126                printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
 127                bad_srat();
 128                return;
 129        }
 130
 131        if (get_uv_system_type() >= UV_X2APIC)
 132                apic_id = (pa->apic_id << 8) | pa->local_sapic_eid;
 133        else
 134                apic_id = pa->apic_id;
 135
 136        if (apic_id >= MAX_LOCAL_APIC) {
 137                printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u skipped apicid that is too big\n", pxm, apic_id, node);
 138                return;
 139        }
 140
 141        set_apicid_to_node(apic_id, node);
 142        node_set(node, numa_nodes_parsed);
 143        acpi_numa = 1;
 144        printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n",
 145               pxm, apic_id, node);
 146}
 147
 148#ifdef CONFIG_MEMORY_HOTPLUG
 149static inline int save_add_info(void) {return 1;}
 150#else
 151static inline int save_add_info(void) {return 0;}
 152#endif
 153
 154/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
 155int __init
 156acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 157{
 158        u64 start, end;
 159        u32 hotpluggable;
 160        int node, pxm;
 161
 162        if (srat_disabled())
 163                goto out_err;
 164        if (ma->header.length != sizeof(struct acpi_srat_mem_affinity))
 165                goto out_err_bad_srat;
 166        if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
 167                goto out_err;
 168        hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE;
 169        if (hotpluggable && !save_add_info())
 170                goto out_err;
 171
 172        start = ma->base_address;
 173        end = start + ma->length;
 174        pxm = ma->proximity_domain;
 175        if (acpi_srat_revision <= 1)
 176                pxm &= 0xff;
 177
 178        node = setup_node(pxm);
 179        if (node < 0) {
 180                printk(KERN_ERR "SRAT: Too many proximity domains.\n");
 181                goto out_err_bad_srat;
 182        }
 183
 184        if (numa_add_memblk(node, start, end) < 0)
 185                goto out_err_bad_srat;
 186
 187        node_set(node, numa_nodes_parsed);
 188
 189        pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n",
 190                node, pxm,
 191                (unsigned long long) start, (unsigned long long) end - 1,
 192                hotpluggable ? " hotplug" : "",
 193                ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : "");
 194
 195        /* Mark hotplug range in memblock. */
 196        if (hotpluggable && memblock_mark_hotplug(start, ma->length))
 197                pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n",
 198                        (unsigned long long)start, (unsigned long long)end - 1);
 199
 200        max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1));
 201
 202        return 0;
 203out_err_bad_srat:
 204        bad_srat();
 205out_err:
 206        return -1;
 207}
 208
 209void __init acpi_numa_arch_fixup(void) {}
 210
 211int __init x86_acpi_numa_init(void)
 212{
 213        int ret;
 214
 215        ret = acpi_numa_init();
 216        if (ret < 0)
 217                return ret;
 218        return srat_disabled() ? -EINVAL : 0;
 219}
 220