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 #define pr_fmt(fmt) "OF: NUMA: " fmt 20 21 #include <linux/of.h> 22 #include <linux/of_address.h> 23 #include <linux/nodemask.h> 24 25 #include <asm/numa.h> 26 27 /* define default numa node to 0 */ 28 #define DEFAULT_NODE 0 29 30 /* 31 * Even though we connect cpus to numa domains later in SMP 32 * init, we need to know the node ids now for all cpus. 33 */ 34 static void __init of_numa_parse_cpu_nodes(void) 35 { 36 u32 nid; 37 int r; 38 struct device_node *cpus; 39 struct device_node *np = NULL; 40 41 cpus = of_find_node_by_path("/cpus"); 42 if (!cpus) 43 return; 44 45 for_each_child_of_node(cpus, np) { 46 /* Skip things that are not CPUs */ 47 if (of_node_cmp(np->type, "cpu") != 0) 48 continue; 49 50 r = of_property_read_u32(np, "numa-node-id", &nid); 51 if (r) 52 continue; 53 54 pr_debug("CPU on %u\n", nid); 55 if (nid >= MAX_NUMNODES) 56 pr_warn("Node id %u exceeds maximum value\n", nid); 57 else 58 node_set(nid, numa_nodes_parsed); 59 } 60 } 61 62 static int __init of_numa_parse_memory_nodes(void) 63 { 64 struct device_node *np = NULL; 65 struct resource rsrc; 66 u32 nid; 67 int i, r; 68 69 for_each_node_by_type(np, "memory") { 70 r = of_property_read_u32(np, "numa-node-id", &nid); 71 if (r == -EINVAL) 72 /* 73 * property doesn't exist if -EINVAL, continue 74 * looking for more memory nodes with 75 * "numa-node-id" property 76 */ 77 continue; 78 79 if (nid >= MAX_NUMNODES) { 80 pr_warn("Node id %u exceeds maximum value\n", nid); 81 r = -EINVAL; 82 } 83 84 for (i = 0; !r && !of_address_to_resource(np, i, &rsrc); i++) 85 r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1); 86 87 if (!i || r) { 88 of_node_put(np); 89 pr_err("bad property in memory node\n"); 90 return r ? : -EINVAL; 91 } 92 } 93 94 return 0; 95 } 96 97 static int __init of_numa_parse_distance_map_v1(struct device_node *map) 98 { 99 const __be32 *matrix; 100 int entry_count; 101 int i; 102 103 pr_info("parsing numa-distance-map-v1\n"); 104 105 matrix = of_get_property(map, "distance-matrix", NULL); 106 if (!matrix) { 107 pr_err("No distance-matrix property in distance-map\n"); 108 return -EINVAL; 109 } 110 111 entry_count = of_property_count_u32_elems(map, "distance-matrix"); 112 if (entry_count <= 0) { 113 pr_err("Invalid distance-matrix\n"); 114 return -EINVAL; 115 } 116 117 for (i = 0; i + 2 < entry_count; i += 3) { 118 u32 nodea, nodeb, distance; 119 120 nodea = of_read_number(matrix, 1); 121 matrix++; 122 nodeb = of_read_number(matrix, 1); 123 matrix++; 124 distance = of_read_number(matrix, 1); 125 matrix++; 126 127 numa_set_distance(nodea, nodeb, distance); 128 pr_debug("distance[node%d -> node%d] = %d\n", 129 nodea, nodeb, distance); 130 131 /* Set default distance of node B->A same as A->B */ 132 if (nodeb > nodea) 133 numa_set_distance(nodeb, nodea, distance); 134 } 135 136 return 0; 137 } 138 139 static int __init of_numa_parse_distance_map(void) 140 { 141 int ret = 0; 142 struct device_node *np; 143 144 np = of_find_compatible_node(NULL, NULL, 145 "numa-distance-map-v1"); 146 if (np) 147 ret = of_numa_parse_distance_map_v1(np); 148 149 of_node_put(np); 150 return ret; 151 } 152 153 int of_node_to_nid(struct device_node *device) 154 { 155 struct device_node *np; 156 u32 nid; 157 int r = -ENODATA; 158 159 np = of_node_get(device); 160 161 while (np) { 162 r = of_property_read_u32(np, "numa-node-id", &nid); 163 /* 164 * -EINVAL indicates the property was not found, and 165 * we walk up the tree trying to find a parent with a 166 * "numa-node-id". Any other type of error indicates 167 * a bad device tree and we give up. 168 */ 169 if (r != -EINVAL) 170 break; 171 172 np = of_get_next_parent(np); 173 } 174 if (np && r) 175 pr_warn("Invalid \"numa-node-id\" property in node %s\n", 176 np->name); 177 of_node_put(np); 178 179 if (!r) 180 return nid; 181 182 return NUMA_NO_NODE; 183 } 184 EXPORT_SYMBOL(of_node_to_nid); 185 186 int __init of_numa_init(void) 187 { 188 int r; 189 190 of_numa_parse_cpu_nodes(); 191 r = of_numa_parse_memory_nodes(); 192 if (r) 193 return r; 194 return of_numa_parse_distance_map(); 195 } 196