aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2013-10-03 10:13:51 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2013-10-03 10:13:51 -0400
commit191124efb4d6e5e47fe073b4b97350873523e88c (patch)
tree8fb9dbbff739e19aa1750c58fe5ec12ee6547e49 /drivers/clocksource
parent68e90740284c69292881cd38c7ece6f09a18a58f (diff)
parent346e7480f1d4740b3d798da60f83f087ea6488b4 (diff)
Merge branch 'timer_evtstrm' of git://linux-arm.org/linux-skn into clockevents/3.13
Adds support to configure the rate and enable the event stream for architected timer. The event streams can be used to impose a timeout on a wfe, to safeguard against any programming error in case an expected event is not generated or even to implement wfe-based timeouts for userspace locking implementations. This feature can be disabled(enabled by default). Since the timer control register is reset to zero on warm boot, CPU PM notifier is added to save and restore the value. Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/Kconfig15
-rw-r--r--drivers/clocksource/arm_arch_timer.c49
2 files changed, 64 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 971d796e071d..5e940f839a2d 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -75,6 +75,21 @@ config ARM_ARCH_TIMER
75 bool 75 bool
76 select CLKSRC_OF if OF 76 select CLKSRC_OF if OF
77 77
78config ARM_ARCH_TIMER_EVTSTREAM
79 bool "Support for ARM architected timer event stream generation"
80 default y if ARM_ARCH_TIMER
81 help
82 This option enables support for event stream generation based on
83 the ARM architected timer. It is used for waking up CPUs executing
84 the wfe instruction at a frequency represented as a power-of-2
85 divisor of the clock rate.
86 The main use of the event stream is wfe-based timeouts of userspace
87 locking implementations. It might also be useful for imposing timeout
88 on wfe to safeguard against any programming errors in case an expected
89 event is not generated.
90 This must be disabled for hardware validation purposes to detect any
91 hardware anomalies of missing events.
92
78config ARM_GLOBAL_TIMER 93config ARM_GLOBAL_TIMER
79 bool 94 bool
80 select CLKSRC_OF if OF 95 select CLKSRC_OF if OF
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index ce98d5e70927..b94b0d44c158 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -13,6 +13,7 @@
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/smp.h> 14#include <linux/smp.h>
15#include <linux/cpu.h> 15#include <linux/cpu.h>
16#include <linux/cpu_pm.h>
16#include <linux/clockchips.h> 17#include <linux/clockchips.h>
17#include <linux/interrupt.h> 18#include <linux/interrupt.h>
18#include <linux/of_irq.h> 19#include <linux/of_irq.h>
@@ -294,6 +295,19 @@ static void __arch_timer_setup(unsigned type,
294 clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); 295 clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff);
295} 296}
296 297
298static void arch_timer_configure_evtstream(void)
299{
300 int evt_stream_div, pos;
301
302 /* Find the closest power of two to the divisor */
303 evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ;
304 pos = fls(evt_stream_div);
305 if (pos > 1 && !(evt_stream_div & (1 << (pos - 2))))
306 pos--;
307 /* enable event stream */
308 arch_timer_evtstrm_enable(min(pos, 15));
309}
310
297static int arch_timer_setup(struct clock_event_device *clk) 311static int arch_timer_setup(struct clock_event_device *clk)
298{ 312{
299 __arch_timer_setup(ARCH_CP15_TIMER, clk); 313 __arch_timer_setup(ARCH_CP15_TIMER, clk);
@@ -307,6 +321,8 @@ static int arch_timer_setup(struct clock_event_device *clk)
307 } 321 }
308 322
309 arch_counter_set_user_access(); 323 arch_counter_set_user_access();
324 if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM))
325 arch_timer_configure_evtstream();
310 326
311 return 0; 327 return 0;
312} 328}
@@ -460,6 +476,33 @@ static struct notifier_block arch_timer_cpu_nb = {
460 .notifier_call = arch_timer_cpu_notify, 476 .notifier_call = arch_timer_cpu_notify,
461}; 477};
462 478
479#ifdef CONFIG_CPU_PM
480static unsigned int saved_cntkctl;
481static int arch_timer_cpu_pm_notify(struct notifier_block *self,
482 unsigned long action, void *hcpu)
483{
484 if (action == CPU_PM_ENTER)
485 saved_cntkctl = arch_timer_get_cntkctl();
486 else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT)
487 arch_timer_set_cntkctl(saved_cntkctl);
488 return NOTIFY_OK;
489}
490
491static struct notifier_block arch_timer_cpu_pm_notifier = {
492 .notifier_call = arch_timer_cpu_pm_notify,
493};
494
495static int __init arch_timer_cpu_pm_init(void)
496{
497 return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier);
498}
499#else
500static int __init arch_timer_cpu_pm_init(void)
501{
502 return 0;
503}
504#endif
505
463static int __init arch_timer_register(void) 506static int __init arch_timer_register(void)
464{ 507{
465 int err; 508 int err;
@@ -499,11 +542,17 @@ static int __init arch_timer_register(void)
499 if (err) 542 if (err)
500 goto out_free_irq; 543 goto out_free_irq;
501 544
545 err = arch_timer_cpu_pm_init();
546 if (err)
547 goto out_unreg_notify;
548
502 /* Immediately configure the timer on the boot CPU */ 549 /* Immediately configure the timer on the boot CPU */
503 arch_timer_setup(this_cpu_ptr(arch_timer_evt)); 550 arch_timer_setup(this_cpu_ptr(arch_timer_evt));
504 551
505 return 0; 552 return 0;
506 553
554out_unreg_notify:
555 unregister_cpu_notifier(&arch_timer_cpu_nb);
507out_free_irq: 556out_free_irq:
508 if (arch_timer_use_virtual) 557 if (arch_timer_use_virtual)
509 free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt); 558 free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);