]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - arch/arm64/kernel/topology.c
Linux 3.16-rc4
[mirror_ubuntu-zesty-kernel.git] / arch / arm64 / kernel / topology.c
CommitLineData
f6e763b9
MB
1/*
2 * arch/arm64/kernel/topology.c
3 *
4 * Copyright (C) 2011,2013,2014 Linaro Limited.
5 *
6 * Based on the arm32 version written by Vincent Guittot in turn based on
7 * arch/sh/kernel/topology.c
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
12 */
13
14#include <linux/cpu.h>
15#include <linux/cpumask.h>
16#include <linux/init.h>
17#include <linux/percpu.h>
18#include <linux/node.h>
19#include <linux/nodemask.h>
ebdc9447 20#include <linux/of.h>
f6e763b9
MB
21#include <linux/sched.h>
22
23#include <asm/topology.h>
24
ebdc9447
MB
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
f6e763b9
MB
206/*
207 * cpu topology table
208 */
209struct cpu_topology cpu_topology[NR_CPUS];
210EXPORT_SYMBOL_GPL(cpu_topology);
211
212const struct cpumask *cpu_coregroup_mask(int cpu)
213{
214 return &cpu_topology[cpu].core_sibling;
215}
216
217static void update_siblings_masks(unsigned int cpuid)
218{
219 struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
220 int cpu;
221
222 if (cpuid_topo->cluster_id == -1) {
223 /*
ebdc9447 224 * DT does not contain topology information for this cpu.
f6e763b9
MB
225 */
226 pr_debug("CPU%u: No topology information configured\n", cpuid);
f6e763b9
MB
227 return;
228 }
229
230 /* update core and thread sibling masks */
231 for_each_possible_cpu(cpu) {
232 cpu_topo = &cpu_topology[cpu];
233
234 if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
235 continue;
236
237 cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
238 if (cpu != cpuid)
239 cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
240
241 if (cpuid_topo->core_id != cpu_topo->core_id)
242 continue;
243
244 cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
245 if (cpu != cpuid)
246 cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
247 }
248}
249
250void store_cpu_topology(unsigned int cpuid)
251{
252 update_siblings_masks(cpuid);
253}
254
ebdc9447 255static void __init reset_cpu_topology(void)
f6e763b9
MB
256{
257 unsigned int cpu;
258
f6e763b9
MB
259 for_each_possible_cpu(cpu) {
260 struct cpu_topology *cpu_topo = &cpu_topology[cpu];
261
262 cpu_topo->thread_id = -1;
c31bf048 263 cpu_topo->core_id = 0;
f6e763b9 264 cpu_topo->cluster_id = -1;
c31bf048 265
f6e763b9 266 cpumask_clear(&cpu_topo->core_sibling);
c31bf048 267 cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
f6e763b9 268 cpumask_clear(&cpu_topo->thread_sibling);
c31bf048 269 cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
f6e763b9
MB
270 }
271}
ebdc9447
MB
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}