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  #include <linux/numa_memblks.h>
14  
15  #include <asm/numa.h>
16  
17  /* define default numa node to 0 */
18  #define DEFAULT_NODE 0
19  
20  /*
21   * Even though we connect cpus to numa domains later in SMP
22   * init, we need to know the node ids now for all cpus.
23  */
of_numa_parse_cpu_nodes(void)24  static 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  		else
39  			node_set(nid, numa_nodes_parsed);
40  	}
41  }
42  
of_numa_parse_memory_nodes(void)43  static 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, continue
55  			 * looking for more memory nodes with
56  			 * "numa-node-id" property
57  			 */
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  
of_numa_parse_distance_map_v1(struct device_node * map)78  static 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  
of_numa_parse_distance_map(void)127  static 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  
of_node_to_nid(struct device_node * device)141  int 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, and
153  		 *  we walk up the tree trying to find a parent with a
154  		 *  "numa-node-id".  Any other type of error indicates
155  		 *  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 defective
169  	 * device tree, the nid may not be in the set of possible
170  	 * 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  
of_numa_init(void)178  int __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