linux/drivers/of/of_numa.c
<<
>>
Prefs
   1/*
   2 * OF NUMA Parsing support.
   3 *
   4 * Copyright (C) 2015 - 2016 Cavium Inc.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include <linux/of.h>
  20#include <linux/of_address.h>
  21#include <linux/nodemask.h>
  22
  23#include <asm/numa.h>
  24
  25/* define default numa node to 0 */
  26#define DEFAULT_NODE 0
  27
  28/*
  29 * Even though we connect cpus to numa domains later in SMP
  30 * init, we need to know the node ids now for all cpus.
  31*/
  32static void __init of_numa_parse_cpu_nodes(void)
  33{
  34        u32 nid;
  35        int r;
  36        struct device_node *cpus;
  37        struct device_node *np = NULL;
  38
  39        cpus = of_find_node_by_path("/cpus");
  40        if (!cpus)
  41                return;
  42
  43        for_each_child_of_node(cpus, np) {
  44                /* Skip things that are not CPUs */
  45                if (of_node_cmp(np->type, "cpu") != 0)
  46                        continue;
  47
  48                r = of_property_read_u32(np, "numa-node-id", &nid);
  49                if (r)
  50                        continue;
  51
  52                pr_debug("NUMA: CPU on %u\n", nid);
  53                if (nid >= MAX_NUMNODES)
  54                        pr_warn("NUMA: Node id %u exceeds maximum value\n",
  55                                nid);
  56                else
  57                        node_set(nid, numa_nodes_parsed);
  58        }
  59}
  60
  61static int __init of_numa_parse_memory_nodes(void)
  62{
  63        struct device_node *np = NULL;
  64        struct resource rsrc;
  65        u32 nid;
  66        int r = 0;
  67
  68        for (;;) {
  69                np = of_find_node_by_type(np, "memory");
  70                if (!np)
  71                        break;
  72
  73                r = of_property_read_u32(np, "numa-node-id", &nid);
  74                if (r == -EINVAL)
  75                        /*
  76                         * property doesn't exist if -EINVAL, continue
  77                         * looking for more memory nodes with
  78                         * "numa-node-id" property
  79                         */
  80                        continue;
  81                else if (r)
  82                        /* some other error */
  83                        break;
  84
  85                r = of_address_to_resource(np, 0, &rsrc);
  86                if (r) {
  87                        pr_err("NUMA: bad reg property in memory node\n");
  88                        break;
  89                }
  90
  91                pr_debug("NUMA:  base = %llx len = %llx, node = %u\n",
  92                         rsrc.start, rsrc.end - rsrc.start + 1, nid);
  93
  94                r = numa_add_memblk(nid, rsrc.start,
  95                                    rsrc.end - rsrc.start + 1);
  96                if (r)
  97                        break;
  98        }
  99        of_node_put(np);
 100
 101        return r;
 102}
 103
 104static int __init of_numa_parse_distance_map_v1(struct device_node *map)
 105{
 106        const __be32 *matrix;
 107        int entry_count;
 108        int i;
 109
 110        pr_info("NUMA: parsing numa-distance-map-v1\n");
 111
 112        matrix = of_get_property(map, "distance-matrix", NULL);
 113        if (!matrix) {
 114                pr_err("NUMA: No distance-matrix property in distance-map\n");
 115                return -EINVAL;
 116        }
 117
 118        entry_count = of_property_count_u32_elems(map, "distance-matrix");
 119        if (entry_count <= 0) {
 120                pr_err("NUMA: Invalid distance-matrix\n");
 121                return -EINVAL;
 122        }
 123
 124        for (i = 0; i + 2 < entry_count; i += 3) {
 125                u32 nodea, nodeb, distance;
 126
 127                nodea = of_read_number(matrix, 1);
 128                matrix++;
 129                nodeb = of_read_number(matrix, 1);
 130                matrix++;
 131                distance = of_read_number(matrix, 1);
 132                matrix++;
 133
 134                numa_set_distance(nodea, nodeb, distance);
 135                pr_debug("NUMA:  distance[node%d -> node%d] = %d\n",
 136                         nodea, nodeb, distance);
 137
 138                /* Set default distance of node B->A same as A->B */
 139                if (nodeb > nodea)
 140                        numa_set_distance(nodeb, nodea, distance);
 141        }
 142
 143        return 0;
 144}
 145
 146static int __init of_numa_parse_distance_map(void)
 147{
 148        int ret = 0;
 149        struct device_node *np;
 150
 151        np = of_find_compatible_node(NULL, NULL,
 152                                     "numa-distance-map-v1");
 153        if (np)
 154                ret = of_numa_parse_distance_map_v1(np);
 155
 156        of_node_put(np);
 157        return ret;
 158}
 159
 160int of_node_to_nid(struct device_node *device)
 161{
 162        struct device_node *np;
 163        u32 nid;
 164        int r = -ENODATA;
 165
 166        np = of_node_get(device);
 167
 168        while (np) {
 169                struct device_node *parent;
 170
 171                r = of_property_read_u32(np, "numa-node-id", &nid);
 172                /*
 173                 * -EINVAL indicates the property was not found, and
 174                 *  we walk up the tree trying to find a parent with a
 175                 *  "numa-node-id".  Any other type of error indicates
 176                 *  a bad device tree and we give up.
 177                 */
 178                if (r != -EINVAL)
 179                        break;
 180
 181                parent = of_get_parent(np);
 182                of_node_put(np);
 183                np = parent;
 184        }
 185        if (np && r)
 186                pr_warn("NUMA: Invalid \"numa-node-id\" property in node %s\n",
 187                        np->name);
 188        of_node_put(np);
 189
 190        if (!r) {
 191                if (nid >= MAX_NUMNODES)
 192                        pr_warn("NUMA: Node id %u exceeds maximum value\n",
 193                                nid);
 194                else
 195                        return nid;
 196        }
 197
 198        return NUMA_NO_NODE;
 199}
 200EXPORT_SYMBOL(of_node_to_nid);
 201
 202int __init of_numa_init(void)
 203{
 204        int r;
 205
 206        of_numa_parse_cpu_nodes();
 207        r = of_numa_parse_memory_nodes();
 208        if (r)
 209                return r;
 210        return of_numa_parse_distance_map();
 211}
 212