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