aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2016-04-08 18:50:25 -0400
committerWill Deacon <will.deacon@arm.com>2016-04-15 13:06:08 -0400
commit298535c00a2cbcd59e38f8f1c0c9ae7b9911e946 (patch)
tree722bd77c438600fb7ce8e204469b86a1344320ee
parent2bc4da1d2b4d828cb4e3a5593967556b1bd78898 (diff)
of, numa: Add NUMA of binding implementation.
Add device tree parsing for NUMA topology using device "numa-node-id" property in distance-map and cpu nodes. This is a complete rewrite of a previous patch by: Ganapatrao Kulkarni<gkulkarni@caviumnetworks.com> Signed-off-by: David Daney <david.daney@cavium.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--drivers/of/Kconfig3
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/of_numa.c211
-rw-r--r--include/linux/of.h9
4 files changed, 224 insertions, 0 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index e2a48415d969..b3bec3aaa45d 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -112,4 +112,7 @@ config OF_OVERLAY
112 While this option is selected automatically when needed, you can 112 While this option is selected automatically when needed, you can
113 enable it manually to improve device tree unit test coverage. 113 enable it manually to improve device tree unit test coverage.
114 114
115config OF_NUMA
116 bool
117
115endif # OF 118endif # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 156c072b3117..bee3fa96b981 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_OF_MTD) += of_mtd.o
14obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o 14obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
15obj-$(CONFIG_OF_RESOLVE) += resolver.o 15obj-$(CONFIG_OF_RESOLVE) += resolver.o
16obj-$(CONFIG_OF_OVERLAY) += overlay.o 16obj-$(CONFIG_OF_OVERLAY) += overlay.o
17obj-$(CONFIG_OF_NUMA) += of_numa.o
17 18
18obj-$(CONFIG_OF_UNITTEST) += unittest-data/ 19obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c
new file mode 100644
index 000000000000..0f2784bc1874
--- /dev/null
+++ b/drivers/of/of_numa.c
@@ -0,0 +1,211 @@
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*/
32static 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
61static int __init of_numa_parse_memory_nodes(void)
62{
63 struct device_node *np = NULL;
64 struct resource rsrc;
65 u32 nid;
66 int r = 0;
67
68 for (;;) {
69 np = of_find_node_by_type(np, "memory");
70 if (!np)
71 break;
72
73 r = of_property_read_u32(np, "numa-node-id", &nid);
74 if (r == -EINVAL)
75 /*
76 * property doesn't exist if -EINVAL, continue
77 * looking for more memory nodes with
78 * "numa-node-id" property
79 */
80 continue;
81 else if (r)
82 /* some other error */
83 break;
84
85 r = of_address_to_resource(np, 0, &rsrc);
86 if (r) {
87 pr_err("NUMA: bad reg property in memory node\n");
88 break;
89 }
90
91 pr_debug("NUMA: base = %llx len = %llx, node = %u\n",
92 rsrc.start, rsrc.end - rsrc.start + 1, nid);
93
94 r = numa_add_memblk(nid, rsrc.start,
95 rsrc.end - rsrc.start + 1);
96 if (r)
97 break;
98 }
99 of_node_put(np);
100
101 return r;
102}
103
104static int __init of_numa_parse_distance_map_v1(struct device_node *map)
105{
106 const __be32 *matrix;
107 int entry_count;
108 int i;
109
110 pr_info("NUMA: parsing numa-distance-map-v1\n");
111
112 matrix = of_get_property(map, "distance-matrix", NULL);
113 if (!matrix) {
114 pr_err("NUMA: No distance-matrix property in distance-map\n");
115 return -EINVAL;
116 }
117
118 entry_count = of_property_count_u32_elems(map, "distance-matrix");
119 if (entry_count <= 0) {
120 pr_err("NUMA: Invalid distance-matrix\n");
121 return -EINVAL;
122 }
123
124 for (i = 0; i + 2 < entry_count; i += 3) {
125 u32 nodea, nodeb, distance;
126
127 nodea = of_read_number(matrix, 1);
128 matrix++;
129 nodeb = of_read_number(matrix, 1);
130 matrix++;
131 distance = of_read_number(matrix, 1);
132 matrix++;
133
134 numa_set_distance(nodea, nodeb, distance);
135 pr_debug("NUMA: distance[node%d -> node%d] = %d\n",
136 nodea, nodeb, distance);
137
138 /* Set default distance of node B->A same as A->B */
139 if (nodeb > nodea)
140 numa_set_distance(nodeb, nodea, distance);
141 }
142
143 return 0;
144}
145
146static int __init of_numa_parse_distance_map(void)
147{
148 int ret = 0;
149 struct device_node *np;
150
151 np = of_find_compatible_node(NULL, NULL,
152 "numa-distance-map-v1");
153 if (np)
154 ret = of_numa_parse_distance_map_v1(np);
155
156 of_node_put(np);
157 return ret;
158}
159
160int of_node_to_nid(struct device_node *device)
161{
162 struct device_node *np;
163 u32 nid;
164 int r = -ENODATA;
165
166 np = of_node_get(device);
167
168 while (np) {
169 struct device_node *parent;
170
171 r = of_property_read_u32(np, "numa-node-id", &nid);
172 /*
173 * -EINVAL indicates the property was not found, and
174 * we walk up the tree trying to find a parent with a
175 * "numa-node-id". Any other type of error indicates
176 * a bad device tree and we give up.
177 */
178 if (r != -EINVAL)
179 break;
180
181 parent = of_get_parent(np);
182 of_node_put(np);
183 np = parent;
184 }
185 if (np && r)
186 pr_warn("NUMA: Invalid \"numa-node-id\" property in node %s\n",
187 np->name);
188 of_node_put(np);
189
190 if (!r) {
191 if (nid >= MAX_NUMNODES)
192 pr_warn("NUMA: Node id %u exceeds maximum value\n",
193 nid);
194 else
195 return nid;
196 }
197
198 return NUMA_NO_NODE;
199}
200EXPORT_SYMBOL(of_node_to_nid);
201
202int __init of_numa_init(void)
203{
204 int r;
205
206 of_numa_parse_cpu_nodes();
207 r = of_numa_parse_memory_nodes();
208 if (r)
209 return r;
210 return of_numa_parse_distance_map();
211}
diff --git a/include/linux/of.h b/include/linux/of.h
index 7fcb681baadf..76f07c84040f 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -685,6 +685,15 @@ static inline int of_node_to_nid(struct device_node *device)
685} 685}
686#endif 686#endif
687 687
688#ifdef CONFIG_OF_NUMA
689extern int of_numa_init(void);
690#else
691static inline int of_numa_init(void)
692{
693 return -ENOSYS;
694}
695#endif
696
688static inline struct device_node *of_find_matching_node( 697static inline struct device_node *of_find_matching_node(
689 struct device_node *from, 698 struct device_node *from,
690 const struct of_device_id *matches) 699 const struct of_device_id *matches)