linux/drivers/acpi/numa.c
<<
>>
Prefs
   1/*
   2 *  acpi_numa.c - ACPI NUMA support
   3 *
   4 *  Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.com>
   5 *
   6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful,
  14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *  GNU General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License
  19 *  along with this program; if not, write to the Free Software
  20 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21 *
  22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  23 *
  24 */
  25#include <linux/module.h>
  26#include <linux/init.h>
  27#include <linux/kernel.h>
  28#include <linux/types.h>
  29#include <linux/errno.h>
  30#include <linux/acpi.h>
  31#include <acpi/acpi_bus.h>
  32
  33#define ACPI_NUMA       0x80000000
  34#define _COMPONENT      ACPI_NUMA
  35ACPI_MODULE_NAME("numa");
  36
  37static nodemask_t nodes_found_map = NODE_MASK_NONE;
  38
  39/* maps to convert between proximity domain and logical node ID */
  40static int pxm_to_node_map[MAX_PXM_DOMAINS]
  41                                = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
  42static int node_to_pxm_map[MAX_NUMNODES]
  43                                = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
  44
  45int pxm_to_node(int pxm)
  46{
  47        if (pxm < 0)
  48                return NID_INVAL;
  49        return pxm_to_node_map[pxm];
  50}
  51
  52int node_to_pxm(int node)
  53{
  54        if (node < 0)
  55                return PXM_INVAL;
  56        return node_to_pxm_map[node];
  57}
  58
  59void __acpi_map_pxm_to_node(int pxm, int node)
  60{
  61        pxm_to_node_map[pxm] = node;
  62        node_to_pxm_map[node] = pxm;
  63}
  64
  65int acpi_map_pxm_to_node(int pxm)
  66{
  67        int node = pxm_to_node_map[pxm];
  68
  69        if (node < 0){
  70                if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
  71                        return NID_INVAL;
  72                node = first_unset_node(nodes_found_map);
  73                __acpi_map_pxm_to_node(pxm, node);
  74                node_set(node, nodes_found_map);
  75        }
  76
  77        return node;
  78}
  79
  80#if 0
  81void __cpuinit acpi_unmap_pxm_to_node(int node)
  82{
  83        int pxm = node_to_pxm_map[node];
  84        pxm_to_node_map[pxm] = NID_INVAL;
  85        node_to_pxm_map[node] = PXM_INVAL;
  86        node_clear(node, nodes_found_map);
  87}
  88#endif  /*  0  */
  89
  90static void __init
  91acpi_table_print_srat_entry(struct acpi_subtable_header *header)
  92{
  93
  94        ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
  95
  96        if (!header)
  97                return;
  98
  99        switch (header->type) {
 100
 101        case ACPI_SRAT_TYPE_CPU_AFFINITY:
 102#ifdef ACPI_DEBUG_OUTPUT
 103                {
 104                        struct acpi_srat_cpu_affinity *p =
 105                            (struct acpi_srat_cpu_affinity *)header;
 106                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 107                                          "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
 108                                          p->apic_id, p->local_sapic_eid,
 109                                          p->proximity_domain_lo,
 110                                          (p->flags & ACPI_SRAT_CPU_ENABLED)?
 111                                          "enabled" : "disabled"));
 112                }
 113#endif                          /* ACPI_DEBUG_OUTPUT */
 114                break;
 115
 116        case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
 117#ifdef ACPI_DEBUG_OUTPUT
 118                {
 119                        struct acpi_srat_mem_affinity *p =
 120                            (struct acpi_srat_mem_affinity *)header;
 121                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 122                                          "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s\n",
 123                                          (unsigned long)p->base_address,
 124                                          (unsigned long)p->length,
 125                                          p->proximity_domain,
 126                                          (p->flags & ACPI_SRAT_MEM_ENABLED)?
 127                                          "enabled" : "disabled",
 128                                          (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
 129                                          " hot-pluggable" : ""));
 130                }
 131#endif                          /* ACPI_DEBUG_OUTPUT */
 132                break;
 133
 134        case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
 135#ifdef ACPI_DEBUG_OUTPUT
 136                {
 137                        struct acpi_srat_x2apic_cpu_affinity *p =
 138                            (struct acpi_srat_x2apic_cpu_affinity *)header;
 139                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 140                                          "SRAT Processor (x2apicid[0x%08x]) in"
 141                                          " proximity domain %d %s\n",
 142                                          p->apic_id,
 143                                          p->proximity_domain,
 144                                          (p->flags & ACPI_SRAT_CPU_ENABLED) ?
 145                                          "enabled" : "disabled"));
 146                }
 147#endif                          /* ACPI_DEBUG_OUTPUT */
 148                break;
 149        default:
 150                printk(KERN_WARNING PREFIX
 151                       "Found unsupported SRAT entry (type = 0x%x)\n",
 152                       header->type);
 153                break;
 154        }
 155}
 156
 157/*
 158 * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
 159 * up the NUMA heuristics which wants the local node to have a smaller
 160 * distance than the others.
 161 * Do some quick checks here and only use the SLIT if it passes.
 162 */
 163static __init int slit_valid(struct acpi_table_slit *slit)
 164{
 165        int i, j;
 166        int d = slit->locality_count;
 167        for (i = 0; i < d; i++) {
 168                for (j = 0; j < d; j++)  {
 169                        u8 val = slit->entry[d*i + j];
 170                        if (i == j) {
 171                                if (val != LOCAL_DISTANCE)
 172                                        return 0;
 173                        } else if (val <= LOCAL_DISTANCE)
 174                                return 0;
 175                }
 176        }
 177        return 1;
 178}
 179
 180static int __init acpi_parse_slit(struct acpi_table_header *table)
 181{
 182        struct acpi_table_slit *slit;
 183
 184        if (!table)
 185                return -EINVAL;
 186
 187        slit = (struct acpi_table_slit *)table;
 188
 189        if (!slit_valid(slit)) {
 190                printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n");
 191                return -EINVAL;
 192        }
 193        acpi_numa_slit_init(slit);
 194
 195        return 0;
 196}
 197
 198void __init __attribute__ ((weak))
 199acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
 200{
 201        printk(KERN_WARNING PREFIX
 202               "Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id);
 203        return;
 204}
 205
 206
 207static int __init
 208acpi_parse_x2apic_affinity(struct acpi_subtable_header *header,
 209                           const unsigned long end)
 210{
 211        struct acpi_srat_x2apic_cpu_affinity *processor_affinity;
 212
 213        processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
 214        if (!processor_affinity)
 215                return -EINVAL;
 216
 217        acpi_table_print_srat_entry(header);
 218
 219        /* let architecture-dependent part to do it */
 220        acpi_numa_x2apic_affinity_init(processor_affinity);
 221
 222        return 0;
 223}
 224
 225static int __init
 226acpi_parse_processor_affinity(struct acpi_subtable_header *header,
 227                              const unsigned long end)
 228{
 229        struct acpi_srat_cpu_affinity *processor_affinity;
 230
 231        processor_affinity = (struct acpi_srat_cpu_affinity *)header;
 232        if (!processor_affinity)
 233                return -EINVAL;
 234
 235        acpi_table_print_srat_entry(header);
 236
 237        /* let architecture-dependent part to do it */
 238        acpi_numa_processor_affinity_init(processor_affinity);
 239
 240        return 0;
 241}
 242
 243static int __init
 244acpi_parse_memory_affinity(struct acpi_subtable_header * header,
 245                           const unsigned long end)
 246{
 247        struct acpi_srat_mem_affinity *memory_affinity;
 248
 249        memory_affinity = (struct acpi_srat_mem_affinity *)header;
 250        if (!memory_affinity)
 251                return -EINVAL;
 252
 253        acpi_table_print_srat_entry(header);
 254
 255        /* let architecture-dependent part to do it */
 256        acpi_numa_memory_affinity_init(memory_affinity);
 257
 258        return 0;
 259}
 260
 261static int __init acpi_parse_srat(struct acpi_table_header *table)
 262{
 263        struct acpi_table_srat *srat;
 264
 265        if (!table)
 266                return -EINVAL;
 267
 268        srat = (struct acpi_table_srat *)table;
 269
 270        return 0;
 271}
 272
 273static int __init
 274acpi_table_parse_srat(enum acpi_srat_type id,
 275                      acpi_table_entry_handler handler, unsigned int max_entries)
 276{
 277        return acpi_table_parse_entries(ACPI_SIG_SRAT,
 278                                            sizeof(struct acpi_table_srat), id,
 279                                            handler, max_entries);
 280}
 281
 282int __init acpi_numa_init(void)
 283{
 284        /* SRAT: Static Resource Affinity Table */
 285        if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
 286                acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
 287                                      acpi_parse_x2apic_affinity, NR_CPUS);
 288                acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
 289                                      acpi_parse_processor_affinity, NR_CPUS);
 290                acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
 291                                      acpi_parse_memory_affinity,
 292                                      NR_NODE_MEMBLKS);
 293        }
 294
 295        /* SLIT: System Locality Information Table */
 296        acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
 297
 298        acpi_numa_arch_fixup();
 299        return 0;
 300}
 301
 302int acpi_get_pxm(acpi_handle h)
 303{
 304        unsigned long long pxm;
 305        acpi_status status;
 306        acpi_handle handle;
 307        acpi_handle phandle = h;
 308
 309        do {
 310                handle = phandle;
 311                status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
 312                if (ACPI_SUCCESS(status))
 313                        return pxm;
 314                status = acpi_get_parent(handle, &phandle);
 315        } while (ACPI_SUCCESS(status));
 316        return -1;
 317}
 318
 319int acpi_get_node(acpi_handle *handle)
 320{
 321        int pxm, node = -1;
 322
 323        pxm = acpi_get_pxm(handle);
 324        if (pxm >= 0 && pxm < MAX_PXM_DOMAINS)
 325                node = acpi_map_pxm_to_node(pxm);
 326
 327        return node;
 328}
 329EXPORT_SYMBOL(acpi_get_node);
 330