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 */ 32 static 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 61 static 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 104 static 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 146 static 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 160 int 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 } 200 EXPORT_SYMBOL(of_node_to_nid); 201 202 int __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