blob: ed734264a51671340a2b868650750c442930011e [file] [log] [blame]
Mark Brownf6e763b2014-03-04 07:51:17 +00001/*
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>
Mark Brownebdc9442014-05-02 21:38:29 +010020#include <linux/of.h>
Mark Brownf6e763b2014-03-04 07:51:17 +000021#include <linux/sched.h>
Robin Randhawa4f569992015-06-09 15:10:00 +010022#include <linux/sched.h>
23#include <linux/sched_energy.h>
Mark Brownf6e763b2014-03-04 07:51:17 +000024
Zi Shen Lim4e6f7082014-06-07 01:55:27 +010025#include <asm/cputype.h>
Mark Brownf6e763b2014-03-04 07:51:17 +000026#include <asm/topology.h>
27
Juri Lelli5e900d42015-04-30 11:53:48 +010028static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
29
30unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu)
31{
32 return per_cpu(cpu_scale, cpu);
33}
34
35static void set_capacity_scale(unsigned int cpu, unsigned long capacity)
36{
37 per_cpu(cpu_scale, cpu) = capacity;
38}
39
Mark Brownebdc9442014-05-02 21:38:29 +010040static int __init get_cpu_for_node(struct device_node *node)
41{
42 struct device_node *cpu_node;
43 int cpu;
44
45 cpu_node = of_parse_phandle(node, "cpu", 0);
46 if (!cpu_node)
47 return -1;
48
49 for_each_possible_cpu(cpu) {
50 if (of_get_cpu_node(cpu, NULL) == cpu_node) {
51 of_node_put(cpu_node);
52 return cpu;
53 }
54 }
55
56 pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);
57
58 of_node_put(cpu_node);
59 return -1;
60}
61
62static int __init parse_core(struct device_node *core, int cluster_id,
63 int core_id)
64{
65 char name[10];
66 bool leaf = true;
67 int i = 0;
68 int cpu;
69 struct device_node *t;
70
71 do {
72 snprintf(name, sizeof(name), "thread%d", i);
73 t = of_get_child_by_name(core, name);
74 if (t) {
75 leaf = false;
76 cpu = get_cpu_for_node(t);
77 if (cpu >= 0) {
78 cpu_topology[cpu].cluster_id = cluster_id;
79 cpu_topology[cpu].core_id = core_id;
80 cpu_topology[cpu].thread_id = i;
81 } else {
82 pr_err("%s: Can't get CPU for thread\n",
83 t->full_name);
84 of_node_put(t);
85 return -EINVAL;
86 }
87 of_node_put(t);
88 }
89 i++;
90 } while (t);
91
92 cpu = get_cpu_for_node(core);
93 if (cpu >= 0) {
94 if (!leaf) {
95 pr_err("%s: Core has both threads and CPU\n",
96 core->full_name);
97 return -EINVAL;
98 }
99
100 cpu_topology[cpu].cluster_id = cluster_id;
101 cpu_topology[cpu].core_id = core_id;
102 } else if (leaf) {
103 pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
104 return -EINVAL;
105 }
106
107 return 0;
108}
109
110static int __init parse_cluster(struct device_node *cluster, int depth)
111{
112 char name[10];
113 bool leaf = true;
114 bool has_cores = false;
115 struct device_node *c;
116 static int cluster_id __initdata;
117 int core_id = 0;
118 int i, ret;
119
120 /*
121 * First check for child clusters; we currently ignore any
122 * information about the nesting of clusters and present the
123 * scheduler with a flat list of them.
124 */
125 i = 0;
126 do {
127 snprintf(name, sizeof(name), "cluster%d", i);
128 c = of_get_child_by_name(cluster, name);
129 if (c) {
130 leaf = false;
131 ret = parse_cluster(c, depth + 1);
132 of_node_put(c);
133 if (ret != 0)
134 return ret;
135 }
136 i++;
137 } while (c);
138
139 /* Now check for cores */
140 i = 0;
141 do {
142 snprintf(name, sizeof(name), "core%d", i);
143 c = of_get_child_by_name(cluster, name);
144 if (c) {
145 has_cores = true;
146
147 if (depth == 0) {
148 pr_err("%s: cpu-map children should be clusters\n",
149 c->full_name);
150 of_node_put(c);
151 return -EINVAL;
152 }
153
154 if (leaf) {
155 ret = parse_core(c, cluster_id, core_id++);
156 } else {
157 pr_err("%s: Non-leaf cluster with core %s\n",
158 cluster->full_name, name);
159 ret = -EINVAL;
160 }
161
162 of_node_put(c);
163 if (ret != 0)
164 return ret;
165 }
166 i++;
167 } while (c);
168
169 if (leaf && !has_cores)
170 pr_warn("%s: empty cluster\n", cluster->full_name);
171
172 if (leaf)
173 cluster_id++;
174
175 return 0;
176}
177
178static int __init parse_dt_topology(void)
179{
180 struct device_node *cn, *map;
181 int ret = 0;
182 int cpu;
183
184 cn = of_find_node_by_path("/cpus");
185 if (!cn) {
186 pr_err("No CPU information found in DT\n");
187 return 0;
188 }
189
190 /*
191 * When topology is provided cpu-map is essentially a root
192 * cluster with restricted subnodes.
193 */
194 map = of_get_child_by_name(cn, "cpu-map");
195 if (!map)
196 goto out;
197
198 ret = parse_cluster(map, 0);
199 if (ret != 0)
200 goto out_map;
201
202 /*
203 * Check that all cores are in the topology; the SMP code will
204 * only mark cores described in the DT as possible.
205 */
Zi Shen Lim4e6f7082014-06-07 01:55:27 +0100206 for_each_possible_cpu(cpu)
207 if (cpu_topology[cpu].cluster_id == -1)
Mark Brownebdc9442014-05-02 21:38:29 +0100208 ret = -EINVAL;
Mark Brownebdc9442014-05-02 21:38:29 +0100209
210out_map:
211 of_node_put(map);
212out:
213 of_node_put(cn);
214 return ret;
215}
216
Mark Brownf6e763b2014-03-04 07:51:17 +0000217/*
218 * cpu topology table
219 */
220struct cpu_topology cpu_topology[NR_CPUS];
221EXPORT_SYMBOL_GPL(cpu_topology);
222
Robin Randhawa4f569992015-06-09 15:10:00 +0100223/* sd energy functions */
224static inline
225const struct sched_group_energy * const cpu_cluster_energy(int cpu)
226{
227 struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1];
228
229 if (!sge) {
230 pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu);
231 return NULL;
232 }
233
234 return sge;
235}
236
237static inline
238const struct sched_group_energy * const cpu_core_energy(int cpu)
239{
240 struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0];
241
242 if (!sge) {
243 pr_warn("Invalid sched_group_energy for CPU%d\n", cpu);
244 return NULL;
245 }
246
247 return sge;
248}
249
Mark Brownf6e763b2014-03-04 07:51:17 +0000250const struct cpumask *cpu_coregroup_mask(int cpu)
251{
252 return &cpu_topology[cpu].core_sibling;
253}
254
Dietmar Eggemannbb2a44422016-11-30 20:36:31 +0000255static int cpu_cpu_flags(void)
256{
257 return SD_ASYM_CPUCAPACITY;
258}
259
Juri Lelli5e900d42015-04-30 11:53:48 +0100260static inline int cpu_corepower_flags(void)
261{
262 return SD_SHARE_PKG_RESOURCES | SD_SHARE_POWERDOMAIN | \
263 SD_SHARE_CAP_STATES;
264}
265
266static struct sched_domain_topology_level arm64_topology[] = {
267#ifdef CONFIG_SCHED_MC
268 { cpu_coregroup_mask, cpu_corepower_flags, cpu_core_energy, SD_INIT_NAME(MC) },
269#endif
Dietmar Eggemannbb2a44422016-11-30 20:36:31 +0000270 { cpu_cpu_mask, cpu_cpu_flags, cpu_cluster_energy, SD_INIT_NAME(DIE) },
Juri Lelli5e900d42015-04-30 11:53:48 +0100271 { NULL, },
272};
273
274static void update_cpu_capacity(unsigned int cpu)
275{
276 unsigned long capacity = SCHED_CAPACITY_SCALE;
277
278 if (cpu_core_energy(cpu)) {
279 int max_cap_idx = cpu_core_energy(cpu)->nr_cap_states - 1;
280 capacity = cpu_core_energy(cpu)->cap_states[max_cap_idx].cap;
281 }
282
283 set_capacity_scale(cpu, capacity);
284
285 pr_info("CPU%d: update cpu_capacity %lu\n",
286 cpu, arch_scale_cpu_capacity(NULL, cpu));
287}
288
Mark Brownf6e763b2014-03-04 07:51:17 +0000289static void update_siblings_masks(unsigned int cpuid)
290{
291 struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
292 int cpu;
293
Mark Brownf6e763b2014-03-04 07:51:17 +0000294 /* update core and thread sibling masks */
295 for_each_possible_cpu(cpu) {
296 cpu_topo = &cpu_topology[cpu];
297
298 if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
299 continue;
300
301 cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
302 if (cpu != cpuid)
303 cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
304
305 if (cpuid_topo->core_id != cpu_topo->core_id)
306 continue;
307
308 cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
309 if (cpu != cpuid)
310 cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
311 }
312}
313
314void store_cpu_topology(unsigned int cpuid)
315{
Zi Shen Lim4e6f7082014-06-07 01:55:27 +0100316 struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
317 u64 mpidr;
318
319 if (cpuid_topo->cluster_id != -1)
320 goto topology_populated;
321
322 mpidr = read_cpuid_mpidr();
323
324 /* Uniprocessor systems can rely on default topology values */
325 if (mpidr & MPIDR_UP_BITMASK)
326 return;
327
328 /* Create cpu topology mapping based on MPIDR. */
329 if (mpidr & MPIDR_MT_BITMASK) {
330 /* Multiprocessor system : Multi-threads per core */
331 cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
332 cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
Mark Brown1cefdae2014-11-21 00:36:49 +0000333 cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
334 MPIDR_AFFINITY_LEVEL(mpidr, 3) << 8;
Zi Shen Lim4e6f7082014-06-07 01:55:27 +0100335 } else {
336 /* Multiprocessor system : Single-thread per core */
337 cpuid_topo->thread_id = -1;
338 cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
Mark Brown1cefdae2014-11-21 00:36:49 +0000339 cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
340 MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8 |
341 MPIDR_AFFINITY_LEVEL(mpidr, 3) << 16;
Zi Shen Lim4e6f7082014-06-07 01:55:27 +0100342 }
343
344 pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n",
345 cpuid, cpuid_topo->cluster_id, cpuid_topo->core_id,
346 cpuid_topo->thread_id, mpidr);
347
348topology_populated:
Mark Brownf6e763b2014-03-04 07:51:17 +0000349 update_siblings_masks(cpuid);
Juri Lelli5e900d42015-04-30 11:53:48 +0100350 update_cpu_capacity(cpuid);
Mark Brownf6e763b2014-03-04 07:51:17 +0000351}
352
Mark Brownebdc9442014-05-02 21:38:29 +0100353static void __init reset_cpu_topology(void)
Mark Brownf6e763b2014-03-04 07:51:17 +0000354{
355 unsigned int cpu;
356
Mark Brownf6e763b2014-03-04 07:51:17 +0000357 for_each_possible_cpu(cpu) {
358 struct cpu_topology *cpu_topo = &cpu_topology[cpu];
359
360 cpu_topo->thread_id = -1;
Mark Brownc31bf042014-05-02 21:38:28 +0100361 cpu_topo->core_id = 0;
Mark Brownf6e763b2014-03-04 07:51:17 +0000362 cpu_topo->cluster_id = -1;
Mark Brownc31bf042014-05-02 21:38:28 +0100363
Mark Brownf6e763b2014-03-04 07:51:17 +0000364 cpumask_clear(&cpu_topo->core_sibling);
Mark Brownc31bf042014-05-02 21:38:28 +0100365 cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
Mark Brownf6e763b2014-03-04 07:51:17 +0000366 cpumask_clear(&cpu_topo->thread_sibling);
Mark Brownc31bf042014-05-02 21:38:28 +0100367 cpumask_set_cpu(cpu, &cpu_topo->thread_sibling);
Mark Brownf6e763b2014-03-04 07:51:17 +0000368 }
369}
Mark Brownebdc9442014-05-02 21:38:29 +0100370
371void __init init_cpu_topology(void)
372{
373 reset_cpu_topology();
374
375 /*
376 * Discard anything that was parsed if we hit an error so we
377 * don't use partial information.
378 */
Sudeep Hollae094d442015-07-23 18:28:26 +0100379 if (of_have_populated_dt() && parse_dt_topology())
Mark Brownebdc9442014-05-02 21:38:29 +0100380 reset_cpu_topology();
Robin Randhawa4f569992015-06-09 15:10:00 +0100381 else
382 set_sched_topology(arm64_topology);
383
384 init_sched_energy_costs();
Mark Brownebdc9442014-05-02 21:38:29 +0100385}