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