Blame view

drivers/of/of_numa.c 3.86 KB
af6074fc9   Rob Herring   of: Use SPDX lice...
1
  // SPDX-License-Identifier: GPL-2.0
298535c00   David Daney   of, numa: Add NUM...
2
3
4
5
  /*
   * OF NUMA Parsing support.
   *
   * Copyright (C) 2015 - 2016 Cavium Inc.
298535c00   David Daney   of, numa: Add NUM...
6
   */
ad0218051   Kefeng Wang   of_numa: Use pr_f...
7
  #define pr_fmt(fmt) "OF: NUMA: " fmt
298535c00   David Daney   of, numa: Add NUM...
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  #include <linux/of.h>
  #include <linux/of_address.h>
  #include <linux/nodemask.h>
  
  #include <asm/numa.h>
  
  /* define default numa node to 0 */
  #define DEFAULT_NODE 0
  
  /*
   * Even though we connect cpus to numa domains later in SMP
   * init, we need to know the node ids now for all cpus.
  */
  static void __init of_numa_parse_cpu_nodes(void)
  {
  	u32 nid;
  	int r;
651d44f96   Rob Herring   of: use for_each_...
25
  	struct device_node *np;
298535c00   David Daney   of, numa: Add NUM...
26

651d44f96   Rob Herring   of: use for_each_...
27
  	for_each_of_cpu_node(np) {
298535c00   David Daney   of, numa: Add NUM...
28
29
30
  		r = of_property_read_u32(np, "numa-node-id", &nid);
  		if (r)
  			continue;
ad0218051   Kefeng Wang   of_numa: Use pr_f...
31
32
  		pr_debug("CPU on %u
  ", nid);
298535c00   David Daney   of, numa: Add NUM...
33
  		if (nid >= MAX_NUMNODES)
ad0218051   Kefeng Wang   of_numa: Use pr_f...
34
35
  			pr_warn("Node id %u exceeds maximum value
  ", nid);
298535c00   David Daney   of, numa: Add NUM...
36
37
38
39
40
41
42
43
44
45
  		else
  			node_set(nid, numa_nodes_parsed);
  	}
  }
  
  static int __init of_numa_parse_memory_nodes(void)
  {
  	struct device_node *np = NULL;
  	struct resource rsrc;
  	u32 nid;
84b14256c   Zhen Lei   of/numa: fix a me...
46
  	int i, r;
298535c00   David Daney   of, numa: Add NUM...
47

84b14256c   Zhen Lei   of/numa: fix a me...
48
  	for_each_node_by_type(np, "memory") {
298535c00   David Daney   of, numa: Add NUM...
49
50
51
52
53
54
55
56
  		r = of_property_read_u32(np, "numa-node-id", &nid);
  		if (r == -EINVAL)
  			/*
  			 * property doesn't exist if -EINVAL, continue
  			 * looking for more memory nodes with
  			 * "numa-node-id" property
  			 */
  			continue;
298535c00   David Daney   of, numa: Add NUM...
57

571a588fe   Zhen Lei   of/numa: add nid ...
58
  		if (nid >= MAX_NUMNODES) {
ad0218051   Kefeng Wang   of_numa: Use pr_f...
59
60
  			pr_warn("Node id %u exceeds maximum value
  ", nid);
571a588fe   Zhen Lei   of/numa: add nid ...
61
62
  			r = -EINVAL;
  		}
84b14256c   Zhen Lei   of/numa: fix a me...
63
64
65
66
67
  		for (i = 0; !r && !of_address_to_resource(np, i, &rsrc); i++)
  			r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1);
  
  		if (!i || r) {
  			of_node_put(np);
ad0218051   Kefeng Wang   of_numa: Use pr_f...
68
69
  			pr_err("bad property in memory node
  ");
84b14256c   Zhen Lei   of/numa: fix a me...
70
71
  			return r ? : -EINVAL;
  		}
298535c00   David Daney   of, numa: Add NUM...
72
  	}
298535c00   David Daney   of, numa: Add NUM...
73

84b14256c   Zhen Lei   of/numa: fix a me...
74
  	return 0;
298535c00   David Daney   of, numa: Add NUM...
75
76
77
78
79
80
81
  }
  
  static int __init of_numa_parse_distance_map_v1(struct device_node *map)
  {
  	const __be32 *matrix;
  	int entry_count;
  	int i;
ad0218051   Kefeng Wang   of_numa: Use pr_f...
82
83
  	pr_info("parsing numa-distance-map-v1
  ");
298535c00   David Daney   of, numa: Add NUM...
84
85
86
  
  	matrix = of_get_property(map, "distance-matrix", NULL);
  	if (!matrix) {
ad0218051   Kefeng Wang   of_numa: Use pr_f...
87
88
  		pr_err("No distance-matrix property in distance-map
  ");
298535c00   David Daney   of, numa: Add NUM...
89
90
91
92
93
  		return -EINVAL;
  	}
  
  	entry_count = of_property_count_u32_elems(map, "distance-matrix");
  	if (entry_count <= 0) {
ad0218051   Kefeng Wang   of_numa: Use pr_f...
94
95
  		pr_err("Invalid distance-matrix
  ");
298535c00   David Daney   of, numa: Add NUM...
96
97
98
99
100
101
102
103
104
105
106
107
  		return -EINVAL;
  	}
  
  	for (i = 0; i + 2 < entry_count; i += 3) {
  		u32 nodea, nodeb, distance;
  
  		nodea = of_read_number(matrix, 1);
  		matrix++;
  		nodeb = of_read_number(matrix, 1);
  		matrix++;
  		distance = of_read_number(matrix, 1);
  		matrix++;
89c38422e   John Garry   of, numa: Validat...
108
109
110
111
112
113
114
  		if ((nodea == nodeb && distance != LOCAL_DISTANCE) ||
  		    (nodea != nodeb && distance <= LOCAL_DISTANCE)) {
  			pr_err("Invalid distance[node%d -> node%d] = %d
  ",
  			       nodea, nodeb, distance);
  			return -EINVAL;
  		}
298535c00   David Daney   of, numa: Add NUM...
115
  		numa_set_distance(nodea, nodeb, distance);
298535c00   David Daney   of, numa: Add NUM...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  
  		/* Set default distance of node B->A same as A->B */
  		if (nodeb > nodea)
  			numa_set_distance(nodeb, nodea, distance);
  	}
  
  	return 0;
  }
  
  static int __init of_numa_parse_distance_map(void)
  {
  	int ret = 0;
  	struct device_node *np;
  
  	np = of_find_compatible_node(NULL, NULL,
  				     "numa-distance-map-v1");
  	if (np)
  		ret = of_numa_parse_distance_map_v1(np);
  
  	of_node_put(np);
  	return ret;
  }
  
  int of_node_to_nid(struct device_node *device)
  {
  	struct device_node *np;
  	u32 nid;
  	int r = -ENODATA;
  
  	np = of_node_get(device);
  
  	while (np) {
298535c00   David Daney   of, numa: Add NUM...
148
149
150
151
152
153
154
155
156
  		r = of_property_read_u32(np, "numa-node-id", &nid);
  		/*
  		 * -EINVAL indicates the property was not found, and
  		 *  we walk up the tree trying to find a parent with a
  		 *  "numa-node-id".  Any other type of error indicates
  		 *  a bad device tree and we give up.
  		 */
  		if (r != -EINVAL)
  			break;
837dae1b4   Kefeng Wang   of_numa: Use of_g...
157
  		np = of_get_next_parent(np);
298535c00   David Daney   of, numa: Add NUM...
158
159
  	}
  	if (np && r)
a613b26a5   Rob Herring   of: Convert to us...
160
161
162
  		pr_warn("Invalid \"numa-node-id\" property in node %pOFn
  ",
  			np);
298535c00   David Daney   of, numa: Add NUM...
163
  	of_node_put(np);
b6cc9474e   David Daney   of, numa: Return ...
164
165
166
167
168
169
  	/*
  	 * If numa=off passed on command line, or with a defective
  	 * device tree, the nid may not be in the set of possible
  	 * nodes.  Check for this case and return NUMA_NO_NODE.
  	 */
  	if (!r && nid < MAX_NUMNODES && node_possible(nid))
9787ed6e5   Zhen Lei   of/numa: remove a...
170
  		return nid;
298535c00   David Daney   of, numa: Add NUM...
171
172
173
  
  	return NUMA_NO_NODE;
  }
298535c00   David Daney   of, numa: Add NUM...
174
175
176
177
178
179
180
181
182
183
184
  
  int __init of_numa_init(void)
  {
  	int r;
  
  	of_numa_parse_cpu_nodes();
  	r = of_numa_parse_memory_nodes();
  	if (r)
  		return r;
  	return of_numa_parse_distance_map();
  }