aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common
diff options
context:
space:
mode:
authorDave Martin <dave.martin@linaro.org>2012-12-10 12:19:58 -0500
committerNicolas Pitre <nicolas.pitre@linaro.org>2013-09-23 18:39:06 -0400
commit491990e29f5d285a1b75e74785e3160716b79040 (patch)
tree72229acfce9b46c63f86ad383ff5f97ed0f8908b /arch/arm/common
parentc0f4375146a738bae23e48fa8b5383abf02177cb (diff)
ARM: bL_switcher: Add runtime control notifier
Some subsystems will need to respond synchronously to runtime enabling and disabling of the switcher. This patch adds a dedicated notifier interface to support such subsystems. Pre- and post- enable/disable notifications are sent to registered callbacks, allowing safe transition of non-b.L- transparent subsystems across these control transitions. Notifier callbacks may veto switcher (de)activation on pre notifications only. Post notifications won't revert the action. If enabling or disabling of the switcher fails after the pre-change notification has been sent, subsystems which have registered notifiers can be left in an inappropriate state. This patch sends a suitable post-change notification on failure, indicating that the old state has been reestablished. For example, a failed initialisation will result in the following sequence: BL_NOTIFY_PRE_ENABLE /* switcher initialisation fails */ BL_NOTIFY_POST_DISABLE It is the responsibility of notified subsystems to respond in an appropriate way. Signed-off-by: Dave Martin <dave.martin@linaro.org> Signed-off-by: Nicolas Pitre <nico@linaro.org>
Diffstat (limited to 'arch/arm/common')
-rw-r--r--arch/arm/common/bL_switcher.c60
1 files changed, 50 insertions, 10 deletions
diff --git a/arch/arm/common/bL_switcher.c b/arch/arm/common/bL_switcher.c
index 7d98629aa446..016488730cb7 100644
--- a/arch/arm/common/bL_switcher.c
+++ b/arch/arm/common/bL_switcher.c
@@ -22,6 +22,7 @@
22#include <linux/clockchips.h> 22#include <linux/clockchips.h>
23#include <linux/hrtimer.h> 23#include <linux/hrtimer.h>
24#include <linux/tick.h> 24#include <linux/tick.h>
25#include <linux/notifier.h>
25#include <linux/mm.h> 26#include <linux/mm.h>
26#include <linux/mutex.h> 27#include <linux/mutex.h>
27#include <linux/string.h> 28#include <linux/string.h>
@@ -304,10 +305,34 @@ EXPORT_SYMBOL_GPL(bL_switch_request);
304 */ 305 */
305 306
306static DEFINE_MUTEX(bL_switcher_activation_lock); 307static DEFINE_MUTEX(bL_switcher_activation_lock);
308static BLOCKING_NOTIFIER_HEAD(bL_activation_notifier);
307static unsigned int bL_switcher_active; 309static unsigned int bL_switcher_active;
308static unsigned int bL_switcher_cpu_original_cluster[NR_CPUS]; 310static unsigned int bL_switcher_cpu_original_cluster[NR_CPUS];
309static cpumask_t bL_switcher_removed_logical_cpus; 311static cpumask_t bL_switcher_removed_logical_cpus;
310 312
313int bL_switcher_register_notifier(struct notifier_block *nb)
314{
315 return blocking_notifier_chain_register(&bL_activation_notifier, nb);
316}
317EXPORT_SYMBOL_GPL(bL_switcher_register_notifier);
318
319int bL_switcher_unregister_notifier(struct notifier_block *nb)
320{
321 return blocking_notifier_chain_unregister(&bL_activation_notifier, nb);
322}
323EXPORT_SYMBOL_GPL(bL_switcher_unregister_notifier);
324
325static int bL_activation_notify(unsigned long val)
326{
327 int ret;
328
329 ret = blocking_notifier_call_chain(&bL_activation_notifier, val, NULL);
330 if (ret & NOTIFY_STOP_MASK)
331 pr_err("%s: notifier chain failed with status 0x%x\n",
332 __func__, ret);
333 return notifier_to_errno(ret);
334}
335
311static void bL_switcher_restore_cpus(void) 336static void bL_switcher_restore_cpus(void)
312{ 337{
313 int i; 338 int i;
@@ -425,12 +450,13 @@ static int bL_switcher_enable(void)
425 450
426 pr_info("big.LITTLE switcher initializing\n"); 451 pr_info("big.LITTLE switcher initializing\n");
427 452
453 ret = bL_activation_notify(BL_NOTIFY_PRE_ENABLE);
454 if (ret)
455 goto error;
456
428 ret = bL_switcher_halve_cpus(); 457 ret = bL_switcher_halve_cpus();
429 if (ret) { 458 if (ret)
430 cpu_hotplug_driver_unlock(); 459 goto error;
431 mutex_unlock(&bL_switcher_activation_lock);
432 return ret;
433 }
434 460
435 for_each_online_cpu(cpu) { 461 for_each_online_cpu(cpu) {
436 struct bL_thread *t = &bL_threads[cpu]; 462 struct bL_thread *t = &bL_threads[cpu];
@@ -441,11 +467,18 @@ static int bL_switcher_enable(void)
441 } 467 }
442 468
443 bL_switcher_active = 1; 469 bL_switcher_active = 1;
470 bL_activation_notify(BL_NOTIFY_POST_ENABLE);
444 pr_info("big.LITTLE switcher initialized\n"); 471 pr_info("big.LITTLE switcher initialized\n");
472 goto out;
473
474error:
475 pr_warn("big.LITTLE switcher initialization failed\n");
476 bL_activation_notify(BL_NOTIFY_POST_DISABLE);
445 477
478out:
446 cpu_hotplug_driver_unlock(); 479 cpu_hotplug_driver_unlock();
447 mutex_unlock(&bL_switcher_activation_lock); 480 mutex_unlock(&bL_switcher_activation_lock);
448 return 0; 481 return ret;
449} 482}
450 483
451#ifdef CONFIG_SYSFS 484#ifdef CONFIG_SYSFS
@@ -458,11 +491,15 @@ static void bL_switcher_disable(void)
458 491
459 mutex_lock(&bL_switcher_activation_lock); 492 mutex_lock(&bL_switcher_activation_lock);
460 cpu_hotplug_driver_lock(); 493 cpu_hotplug_driver_lock();
461 if (!bL_switcher_active) { 494
462 cpu_hotplug_driver_unlock(); 495 if (!bL_switcher_active)
463 mutex_unlock(&bL_switcher_activation_lock); 496 goto out;
464 return; 497
498 if (bL_activation_notify(BL_NOTIFY_PRE_DISABLE) != 0) {
499 bL_activation_notify(BL_NOTIFY_POST_ENABLE);
500 goto out;
465 } 501 }
502
466 bL_switcher_active = 0; 503 bL_switcher_active = 0;
467 504
468 /* 505 /*
@@ -504,6 +541,9 @@ static void bL_switcher_disable(void)
504 } 541 }
505 542
506 bL_switcher_restore_cpus(); 543 bL_switcher_restore_cpus();
544 bL_activation_notify(BL_NOTIFY_POST_DISABLE);
545
546out:
507 cpu_hotplug_driver_unlock(); 547 cpu_hotplug_driver_unlock();
508 mutex_unlock(&bL_switcher_activation_lock); 548 mutex_unlock(&bL_switcher_activation_lock);
509} 549}