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 i, r; 67 68 for_each_node_by_type(np, "memory") { 69 r = of_property_read_u32(np, "numa-node-id", &nid); 70 if (r == -EINVAL) 71 /* 72 * property doesn't exist if -EINVAL, continue 73 * looking for more memory nodes with 74 * "numa-node-id" property 75 */ 76 continue; 77 78 if (nid >= MAX_NUMNODES) { 79 pr_warn("NUMA: Node id %u exceeds maximum value\n", nid); 80 r = -EINVAL; 81 } 82 83 for (i = 0; !r && !of_address_to_resource(np, i, &rsrc); i++) 84 r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1); 85 86 if (!i || r) { 87 of_node_put(np); 88 pr_err("NUMA: bad property in memory node\n"); 89 return r ? : -EINVAL; 90 } 91 } 92 93 return 0; 94 } 95 96 static int __init of_numa_parse_distance_map_v1(struct device_node *map) 97 { 98 const __be32 *matrix; 99 int entry_count; 100 int i; 101 102 pr_info("NUMA: parsing numa-distance-map-v1\n"); 103 104 matrix = of_get_property(map, "distance-matrix", NULL); 105 if (!matrix) { 106 pr_err("NUMA: No distance-matrix property in distance-map\n"); 107 return -EINVAL; 108 } 109 110 entry_count = of_property_count_u32_elems(map, "distance-matrix"); 111 if (entry_count <= 0) { 112 pr_err("NUMA: Invalid distance-matrix\n"); 113 return -EINVAL; 114 } 115 116 for (i = 0; i + 2 < entry_count; i += 3) { 117 u32 nodea, nodeb, distance; 118 119 nodea = of_read_number(matrix, 1); 120 matrix++; 121 nodeb = of_read_number(matrix, 1); 122 matrix++; 123 distance = of_read_number(matrix, 1); 124 matrix++; 125 126 numa_set_distance(nodea, nodeb, distance); 127 pr_debug("NUMA: distance[node%d -> node%d] = %d\n", 128 nodea, nodeb, distance); 129 130 /* Set default distance of node B->A same as A->B */ 131 if (nodeb > nodea) 132 numa_set_distance(nodeb, nodea, distance); 133 } 134 135 return 0; 136 } 137 138 static int __init of_numa_parse_distance_map(void) 139 { 140 int ret = 0; 141 struct device_node *np; 142 143 np = of_find_compatible_node(NULL, NULL, 144 "numa-distance-map-v1"); 145 if (np) 146 ret = of_numa_parse_distance_map_v1(np); 147 148 of_node_put(np); 149 return ret; 150 } 151 152 int of_node_to_nid(struct device_node *device) 153 { 154 struct device_node *np; 155 u32 nid; 156 int r = -ENODATA; 157 158 np = of_node_get(device); 159 160 while (np) { 161 r = of_property_read_u32(np, "numa-node-id", &nid); 162 /* 163 * -EINVAL indicates the property was not found, and 164 * we walk up the tree trying to find a parent with a 165 * "numa-node-id". Any other type of error indicates 166 * a bad device tree and we give up. 167 */ 168 if (r != -EINVAL) 169 break; 170 171 np = of_get_next_parent(np); 172 } 173 if (np && r) 174 pr_warn("NUMA: Invalid \"numa-node-id\" property in node %s\n", 175 np->name); 176 of_node_put(np); 177 178 if (!r) 179 return nid; 180 181 return NUMA_NO_NODE; 182 } 183 EXPORT_SYMBOL(of_node_to_nid); 184 185 int __init of_numa_init(void) 186 { 187 int r; 188 189 of_numa_parse_cpu_nodes(); 190 r = of_numa_parse_memory_nodes(); 191 if (r) 192 return r; 193 return of_numa_parse_distance_map(); 194 } 195