aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2014-05-02 16:38:29 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2014-05-16 12:12:41 -0400
commitebdc94470d23d73dcab3748ae7eefa9ca669cdbe (patch)
tree0cbd279824819325ea26355234997a38d2efcdc8
parentc31bf0488d67737668b7401fac4b7ed550eaad76 (diff)
arm64: topology: Add support for topology DT bindings
Add support for parsing the explicit topology bindings to discover the topology of the system. Since it is not currently clear how to map multi-level clusters for the scheduler all leaf clusters are presented to the scheduler at the same level. This should be enough to provide good support for current systems. Signed-off-by: Mark Brown <broonie@linaro.org> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm64/kernel/topology.c204
1 files changed, 196 insertions, 8 deletions
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index ff662b23af5f..43514f905916 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -17,10 +17,192 @@
17#include <linux/percpu.h> 17#include <linux/percpu.h>
18#include <linux/node.h> 18#include <linux/node.h>
19#include <linux/nodemask.h> 19#include <linux/nodemask.h>
20#include <linux/of.h>
20#include <linux/sched.h> 21#include <linux/sched.h>
21 22
22#include <asm/topology.h> 23#include <asm/topology.h>
23 24
25static int __init get_cpu_for_node(struct device_node *node)
26{
27 struct device_node *cpu_node;
28 int cpu;
29
30 cpu_node = of_parse_phandle(node, "cpu", 0);
31 if (!cpu_node)
32 return -1;
33
34 for_each_possible_cpu(cpu) {
35 if (of_get_cpu_node(cpu, NULL) == cpu_node) {
36 of_node_put(cpu_node);
37 return cpu;
38 }
39 }
40
41 pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);
42
43 of_node_put(cpu_node);
44 return -1;
45}
46
47static int __init parse_core(struct device_node *core, int cluster_id,
48 int core_id)
49{
50 char name[10];
51 bool leaf = true;
52 int i = 0;
53 int cpu;
54 struct device_node *t;
55
56 do {
57 snprintf(name, sizeof(name), "thread%d", i);
58 t = of_get_child_by_name(core, name);
59 if (t) {
60 leaf = false;
61 cpu = get_cpu_for_node(t);
62 if (cpu >= 0) {
63 cpu_topology[cpu].cluster_id = cluster_id;
64 cpu_topology[cpu].core_id = core_id;
65 cpu_topology[cpu].thread_id = i;
66 } else {
67 pr_err("%s: Can't get CPU for thread\n",
68 t->full_name);
69 of_node_put(t);
70 return -EINVAL;
71 }
72 of_node_put(t);
73 }
74 i++;
75 } while (t);
76
77 cpu = get_cpu_for_node(core);
78 if (cpu >= 0) {
79 if (!leaf) {
80 pr_err("%s: Core has both threads and CPU\n",
81 core->full_name);
82 return -EINVAL;
83 }
84
85 cpu_topology[cpu].cluster_id = cluster_id;
86 cpu_topology[cpu].core_id = core_id;
87 } else if (leaf) {
88 pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
89 return -EINVAL;
90 }
91
92 return 0;
93}
94
95static int __init parse_cluster(struct device_node *cluster, int depth)
96{
97 char name[10];
98 bool leaf = true;
99 bool has_cores = false;
100 struct device_node *c;
101 static int cluster_id __initdata;
102 int core_id = 0;
103 int i, ret;
104
105 /*
106 * First check for child clusters; we currently ignore any
107 * information about the nesting of clusters and present the
108 * scheduler with a flat list of them.
109 */
110 i = 0;
111 do {
112 snprintf(name, sizeof(name), "cluster%d", i);
113 c = of_get_child_by_name(cluster, name);
114 if (c) {
115 leaf = false;
116 ret = parse_cluster(c, depth + 1);
117 of_node_put(c);
118 if (ret != 0)
119 return ret;
120 }
121 i++;
122 } while (c);
123
124 /* Now check for cores */
125 i = 0;
126 do {
127 snprintf(name, sizeof(name), "core%d", i);
128 c = of_get_child_by_name(cluster, name);
129 if (c) {
130 has_cores = true;
131
132 if (depth == 0) {
133 pr_err("%s: cpu-map children should be clusters\n",
134 c->full_name);
135 of_node_put(c);
136 return -EINVAL;
137 }
138
139 if (leaf) {
140 ret = parse_core(c, cluster_id, core_id++);
141 } else {
142 pr_err("%s: Non-leaf cluster with core %s\n",
143 cluster->full_name, name);
144 ret = -EINVAL;
145 }
146
147 of_node_put(c);
148 if (ret != 0)
149 return ret;
150 }
151 i++;
152 } while (c);
153
154 if (leaf && !has_cores)
155 pr_warn("%s: empty cluster\n", cluster->full_name);
156
157 if (leaf)
158 cluster_id++;
159
160 return 0;
161}
162
163static int __init parse_dt_topology(void)
164{
165 struct device_node *cn, *map;
166 int ret = 0;
167 int cpu;
168
169 cn = of_find_node_by_path("/cpus");
170 if (!cn) {
171 pr_err("No CPU information found in DT\n");
172 return 0;
173 }
174
175 /*
176 * When topology is provided cpu-map is essentially a root
177 * cluster with restricted subnodes.
178 */
179 map = of_get_child_by_name(cn, "cpu-map");
180 if (!map)
181 goto out;
182
183 ret = parse_cluster(map, 0);
184 if (ret != 0)
185 goto out_map;
186
187 /*
188 * Check that all cores are in the topology; the SMP code will
189 * only mark cores described in the DT as possible.
190 */
191 for_each_possible_cpu(cpu) {
192 if (cpu_topology[cpu].cluster_id == -1) {
193 pr_err("CPU%d: No topology information specified\n",
194 cpu);
195 ret = -EINVAL;
196 }
197 }
198
199out_map:
200 of_node_put(map);
201out:
202 of_node_put(cn);
203 return ret;
204}
205
24/* 206/*
25 * cpu topology table 207 * cpu topology table
26 */ 208 */
@@ -39,8 +221,7 @@ static void update_siblings_masks(unsigned int cpuid)
39 221
40 if (cpuid_topo->cluster_id == -1) { 222 if (cpuid_topo->cluster_id == -1) {
41 /* 223 /*
42 * DT does not contain topology information for this cpu 224 * DT does not contain topology information for this cpu.
43 * reset it to default behaviour
44 */ 225 */
45 pr_debug("CPU%u: No topology information configured\n", cpuid); 226 pr_debug("CPU%u: No topology information configured\n", cpuid);
46 return; 227 return;
@@ -71,15 +252,10 @@ void store_cpu_topology(unsigned int cpuid)
71 update_siblings_masks(cpuid); 252 update_siblings_masks(cpuid);
72} 253}
73 254
74/* 255static void __init reset_cpu_topology(void)
75 * init_cpu_topology is called at boot when only one cpu is running
76 * which prevent simultaneous write access to cpu_topology array
77 */
78void __init init_cpu_topology(void)
79{ 256{
80 unsigned int cpu; 257 unsigned int cpu;
81 258
82 /* init core mask and power*/
83 for_each_possible_cpu(cpu) { 259 for_each_possible_cpu(cpu) {
84 struct cpu_topology *cpu_topo = &cpu_topology[cpu]; 260 struct cpu_topology *cpu_topo = &cpu_topology[cpu];
85 261
@@ -93,3 +269,15 @@ void __init init_cpu_topology(void)
93 cpumask_set_cpu(cpu, &cpu_topo->thread_sibling); 269 cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
94 } 270 }
95} 271}
272
273void __init init_cpu_topology(void)
274{
275 reset_cpu_topology();
276
277 /*
278 * Discard anything that was parsed if we hit an error so we
279 * don't use partial information.
280 */
281 if (parse_dt_topology())
282 reset_cpu_topology();
283}