diff options
-rw-r--r-- | arch/arm/common/bL_switcher.c | 78 |
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 | } |
290 | EXPORT_SYMBOL_GPL(bL_switch_request); | 290 | EXPORT_SYMBOL_GPL(bL_switch_request); |
291 | 291 | ||
292 | /* | ||
293 | * Activation and configuration code. | ||
294 | */ | ||
295 | |||
296 | static cpumask_t bL_switcher_removed_logical_cpus; | ||
297 | |||
298 | static 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 | |||
306 | static 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 | |||
292 | static int __init bL_switcher_init(void) | 355 | static 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; |