188 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * OF NUMA Parsing support.4 *5 * Copyright (C) 2015 - 2016 Cavium Inc.6 */7 8#define pr_fmt(fmt) "OF: NUMA: " fmt9 10#include <linux/of.h>11#include <linux/of_address.h>12#include <linux/nodemask.h>13#include <linux/numa_memblks.h>14 15#include <asm/numa.h>16 17/* define default numa node to 0 */18#define DEFAULT_NODE 019 20/*21 * Even though we connect cpus to numa domains later in SMP22 * init, we need to know the node ids now for all cpus.23*/24static void __init of_numa_parse_cpu_nodes(void)25{26 u32 nid;27 int r;28 struct device_node *np;29 30 for_each_of_cpu_node(np) {31 r = of_property_read_u32(np, "numa-node-id", &nid);32 if (r)33 continue;34 35 pr_debug("CPU on %u\n", nid);36 if (nid >= MAX_NUMNODES)37 pr_warn("Node id %u exceeds maximum value\n", nid);38 else39 node_set(nid, numa_nodes_parsed);40 }41}42 43static int __init of_numa_parse_memory_nodes(void)44{45 struct device_node *np = NULL;46 struct resource rsrc;47 u32 nid;48 int i, r = -EINVAL;49 50 for_each_node_by_type(np, "memory") {51 r = of_property_read_u32(np, "numa-node-id", &nid);52 if (r == -EINVAL)53 /*54 * property doesn't exist if -EINVAL, continue55 * looking for more memory nodes with56 * "numa-node-id" property57 */58 continue;59 60 if (nid >= MAX_NUMNODES) {61 pr_warn("Node id %u exceeds maximum value\n", nid);62 r = -EINVAL;63 }64 65 for (i = 0; !r && !of_address_to_resource(np, i, &rsrc); i++)66 r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1);67 68 if (!i || r) {69 of_node_put(np);70 pr_err("bad property in memory node\n");71 return r ? : -EINVAL;72 }73 }74 75 return r;76}77 78static int __init of_numa_parse_distance_map_v1(struct device_node *map)79{80 const __be32 *matrix;81 int entry_count;82 int i;83 84 pr_info("parsing numa-distance-map-v1\n");85 86 matrix = of_get_property(map, "distance-matrix", NULL);87 if (!matrix) {88 pr_err("No distance-matrix property in distance-map\n");89 return -EINVAL;90 }91 92 entry_count = of_property_count_u32_elems(map, "distance-matrix");93 if (entry_count <= 0) {94 pr_err("Invalid distance-matrix\n");95 return -EINVAL;96 }97 98 for (i = 0; i + 2 < entry_count; i += 3) {99 u32 nodea, nodeb, distance;100 101 nodea = of_read_number(matrix, 1);102 matrix++;103 nodeb = of_read_number(matrix, 1);104 matrix++;105 distance = of_read_number(matrix, 1);106 matrix++;107 108 if ((nodea == nodeb && distance != LOCAL_DISTANCE) ||109 (nodea != nodeb && distance <= LOCAL_DISTANCE)) {110 pr_err("Invalid distance[node%d -> node%d] = %d\n",111 nodea, nodeb, distance);112 return -EINVAL;113 }114 115 node_set(nodea, numa_nodes_parsed);116 117 numa_set_distance(nodea, nodeb, distance);118 119 /* Set default distance of node B->A same as A->B */120 if (nodeb > nodea)121 numa_set_distance(nodeb, nodea, distance);122 }123 124 return 0;125}126 127static int __init of_numa_parse_distance_map(void)128{129 int ret = 0;130 struct device_node *np;131 132 np = of_find_compatible_node(NULL, NULL,133 "numa-distance-map-v1");134 if (np)135 ret = of_numa_parse_distance_map_v1(np);136 137 of_node_put(np);138 return ret;139}140 141int of_node_to_nid(struct device_node *device)142{143 struct device_node *np;144 u32 nid;145 int r = -ENODATA;146 147 np = of_node_get(device);148 149 while (np) {150 r = of_property_read_u32(np, "numa-node-id", &nid);151 /*152 * -EINVAL indicates the property was not found, and153 * we walk up the tree trying to find a parent with a154 * "numa-node-id". Any other type of error indicates155 * a bad device tree and we give up.156 */157 if (r != -EINVAL)158 break;159 160 np = of_get_next_parent(np);161 }162 if (np && r)163 pr_warn("Invalid \"numa-node-id\" property in node %pOFn\n",164 np);165 of_node_put(np);166 167 /*168 * If numa=off passed on command line, or with a defective169 * device tree, the nid may not be in the set of possible170 * nodes. Check for this case and return NUMA_NO_NODE.171 */172 if (!r && nid < MAX_NUMNODES && node_possible(nid))173 return nid;174 175 return NUMA_NO_NODE;176}177 178int __init of_numa_init(void)179{180 int r;181 182 of_numa_parse_cpu_nodes();183 r = of_numa_parse_memory_nodes();184 if (r)185 return r;186 return of_numa_parse_distance_map();187}188