aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common
diff options
context:
space:
mode:
authorNicolas Pitre <nicolas.pitre@linaro.org>2012-11-21 11:53:27 -0500
committerNicolas Pitre <nicolas.pitre@linaro.org>2013-07-30 09:02:16 -0400
commit9797a0e95ead7bfe52260c369ee9fe6ba445afaf (patch)
tree01ed44a4f452c0e62465992066d2c517288d6d27 /arch/arm/common
parentc052de2693498bee6ff2e1b5bcd32309c4f8780b (diff)
ARM: bL_switcher: hot-unplug half of the available CPUs
In a regular kernel configuration, all the CPUs are initially available. But the switcher execution model uses half of them at any time. Instead of hacking the DTB to remove half of the CPUs, let's remove them at run time and make sure we still have a working switcher configuration. This way, the same DTB can be used whether or not the switcher is used. Signed-off-by: Nicolas Pitre <nico@linaro.org>
Diffstat (limited to 'arch/arm/common')
-rw-r--r--arch/arm/common/bL_switcher.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/arch/arm/common/bL_switcher.c b/arch/arm/common/bL_switcher.c
index 4caca71c906f..50e95d894e35 100644
--- a/arch/arm/common/bL_switcher.c
+++ b/arch/arm/common/bL_switcher.c
@@ -289,18 +289,94 @@ int bL_switch_request(unsigned int cpu, unsigned int new_cluster_id)
289} 289}
290EXPORT_SYMBOL_GPL(bL_switch_request); 290EXPORT_SYMBOL_GPL(bL_switch_request);
291 291
292/*
293 * Activation and configuration code.
294 */
295
296static cpumask_t bL_switcher_removed_logical_cpus;
297
298static void __init bL_switcher_restore_cpus(void)
299{
300 int i;
301
302 for_each_cpu(i, &bL_switcher_removed_logical_cpus)
303 cpu_up(i);
304}
305
306static int __init bL_switcher_halve_cpus(void)
307{
308 int cpu, cluster, i, ret;
309 cpumask_t cluster_mask[2], common_mask;
310
311 cpumask_clear(&bL_switcher_removed_logical_cpus);
312 cpumask_clear(&cluster_mask[0]);
313 cpumask_clear(&cluster_mask[1]);
314
315 for_each_online_cpu(i) {
316 cpu = cpu_logical_map(i) & 0xff;
317 cluster = (cpu_logical_map(i) >> 8) & 0xff;
318 if (cluster >= 2) {
319 pr_err("%s: only dual cluster systems are supported\n", __func__);
320 return -EINVAL;
321 }
322 cpumask_set_cpu(cpu, &cluster_mask[cluster]);
323 }
324
325 if (!cpumask_and(&common_mask, &cluster_mask[0], &cluster_mask[1])) {
326 pr_err("%s: no common set of CPUs\n", __func__);
327 return -EINVAL;
328 }
329
330 for_each_online_cpu(i) {
331 cpu = cpu_logical_map(i) & 0xff;
332 cluster = (cpu_logical_map(i) >> 8) & 0xff;
333
334 if (cpumask_test_cpu(cpu, &common_mask)) {
335 /*
336 * We keep only those logical CPUs which number
337 * is equal to their physical CPU number. This is
338 * not perfect but good enough for now.
339 */
340 if (cpu == i)
341 continue;
342 }
343
344 ret = cpu_down(i);
345 if (ret) {
346 bL_switcher_restore_cpus();
347 return ret;
348 }
349 cpumask_set_cpu(i, &bL_switcher_removed_logical_cpus);
350 }
351
352 return 0;
353}
354
292static int __init bL_switcher_init(void) 355static int __init bL_switcher_init(void)
293{ 356{
294 int cpu; 357 int cpu, ret;
295 358
296 pr_info("big.LITTLE switcher initializing\n"); 359 pr_info("big.LITTLE switcher initializing\n");
297 360
361 if (MAX_NR_CLUSTERS != 2) {
362 pr_err("%s: only dual cluster systems are supported\n", __func__);
363 return -EINVAL;
364 }
365
366 cpu_hotplug_driver_lock();
367 ret = bL_switcher_halve_cpus();
368 if (ret) {
369 cpu_hotplug_driver_unlock();
370 return ret;
371 }
372
298 for_each_online_cpu(cpu) { 373 for_each_online_cpu(cpu) {
299 struct bL_thread *t = &bL_threads[cpu]; 374 struct bL_thread *t = &bL_threads[cpu];
300 init_waitqueue_head(&t->wq); 375 init_waitqueue_head(&t->wq);
301 t->wanted_cluster = -1; 376 t->wanted_cluster = -1;
302 t->task = bL_switcher_thread_create(cpu, t); 377 t->task = bL_switcher_thread_create(cpu, t);
303 } 378 }
379 cpu_hotplug_driver_unlock();
304 380
305 pr_info("big.LITTLE switcher initialized\n"); 381 pr_info("big.LITTLE switcher initialized\n");
306 return 0; 382 return 0;