aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/arm/include/asm/arch_timer.h36
-rw-r--r--arch/arm/include/uapi/asm/hwcap.h1
-rw-r--r--arch/arm/kernel/setup.c1
-rw-r--r--arch/arm64/include/asm/arch_timer.h42
-rw-r--r--arch/arm64/include/asm/hwcap.h11
-rw-r--r--arch/arm64/include/uapi/asm/hwcap.h1
-rw-r--r--arch/arm64/kernel/setup.c11
-rw-r--r--drivers/clocksource/Kconfig15
-rw-r--r--drivers/clocksource/arm_arch_timer.c49
-rw-r--r--include/clocksource/arm_arch_timer.h10
10 files changed, 161 insertions, 16 deletions
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 5665134bfa3e..0704e0cf5571 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -87,17 +87,43 @@ static inline u64 arch_counter_get_cntvct(void)
87 return cval; 87 return cval;
88} 88}
89 89
90static inline void arch_counter_set_user_access(void) 90static inline u32 arch_timer_get_cntkctl(void)
91{ 91{
92 u32 cntkctl; 92 u32 cntkctl;
93
94 asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); 93 asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl));
94 return cntkctl;
95}
95 96
96 /* disable user access to everything */ 97static inline void arch_timer_set_cntkctl(u32 cntkctl)
97 cntkctl &= ~((3 << 8) | (7 << 0)); 98{
98
99 asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); 99 asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
100} 100}
101
102static inline void arch_counter_set_user_access(void)
103{
104 u32 cntkctl = arch_timer_get_cntkctl();
105
106 /* Disable user access to both physical/virtual counters/timers */
107 /* Also disable virtual event stream */
108 cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
109 | ARCH_TIMER_USR_VT_ACCESS_EN
110 | ARCH_TIMER_VIRT_EVT_EN
111 | ARCH_TIMER_USR_VCT_ACCESS_EN
112 | ARCH_TIMER_USR_PCT_ACCESS_EN);
113 arch_timer_set_cntkctl(cntkctl);
114}
115
116static inline void arch_timer_evtstrm_enable(int divider)
117{
118 u32 cntkctl = arch_timer_get_cntkctl();
119 cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK;
120 /* Set the divider and enable virtual event stream */
121 cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
122 | ARCH_TIMER_VIRT_EVT_EN;
123 arch_timer_set_cntkctl(cntkctl);
124 elf_hwcap |= HWCAP_EVTSTRM;
125}
126
101#endif 127#endif
102 128
103#endif 129#endif
diff --git a/arch/arm/include/uapi/asm/hwcap.h b/arch/arm/include/uapi/asm/hwcap.h
index 6d34d080372a..7dcc10d67253 100644
--- a/arch/arm/include/uapi/asm/hwcap.h
+++ b/arch/arm/include/uapi/asm/hwcap.h
@@ -26,5 +26,6 @@
26#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */ 26#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
27#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT) 27#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
28#define HWCAP_LPAE (1 << 20) 28#define HWCAP_LPAE (1 << 20)
29#define HWCAP_EVTSTRM (1 << 21)
29 30
30#endif /* _UAPI__ASMARM_HWCAP_H */ 31#endif /* _UAPI__ASMARM_HWCAP_H */
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 0e1e2b3afa45..5d65438685d8 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -975,6 +975,7 @@ static const char *hwcap_str[] = {
975 "idivt", 975 "idivt",
976 "vfpd32", 976 "vfpd32",
977 "lpae", 977 "lpae",
978 "evtstrm",
978 NULL 979 NULL
979}; 980};
980 981
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index c9f1d2816c2b..9400596a0f39 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -92,19 +92,49 @@ static inline u32 arch_timer_get_cntfrq(void)
92 return val; 92 return val;
93} 93}
94 94
95static inline void arch_counter_set_user_access(void) 95static inline u32 arch_timer_get_cntkctl(void)
96{ 96{
97 u32 cntkctl; 97 u32 cntkctl;
98
99 /* Disable user access to the timers and the physical counter. */
100 asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl)); 98 asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl));
101 cntkctl &= ~((3 << 8) | (1 << 0)); 99 return cntkctl;
100}
102 101
103 /* Enable user access to the virtual counter and frequency. */ 102static inline void arch_timer_set_cntkctl(u32 cntkctl)
104 cntkctl |= (1 << 1); 103{
105 asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); 104 asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
106} 105}
107 106
107static inline void arch_counter_set_user_access(void)
108{
109 u32 cntkctl = arch_timer_get_cntkctl();
110
111 /* Disable user access to the timers and the physical counter */
112 /* Also disable virtual event stream */
113 cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
114 | ARCH_TIMER_USR_VT_ACCESS_EN
115 | ARCH_TIMER_VIRT_EVT_EN
116 | ARCH_TIMER_USR_PCT_ACCESS_EN);
117
118 /* Enable user access to the virtual counter */
119 cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
120
121 arch_timer_set_cntkctl(cntkctl);
122}
123
124static inline void arch_timer_evtstrm_enable(int divider)
125{
126 u32 cntkctl = arch_timer_get_cntkctl();
127 cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK;
128 /* Set the divider and enable virtual event stream */
129 cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
130 | ARCH_TIMER_VIRT_EVT_EN;
131 arch_timer_set_cntkctl(cntkctl);
132 elf_hwcap |= HWCAP_EVTSTRM;
133#ifdef CONFIG_COMPAT
134 compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
135#endif
136}
137
108static inline u64 arch_counter_get_cntvct(void) 138static inline u64 arch_counter_get_cntvct(void)
109{ 139{
110 u64 cval; 140 u64 cval;
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index e2950b098e76..6cddbb0c9f54 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -30,6 +30,7 @@
30#define COMPAT_HWCAP_IDIVA (1 << 17) 30#define COMPAT_HWCAP_IDIVA (1 << 17)
31#define COMPAT_HWCAP_IDIVT (1 << 18) 31#define COMPAT_HWCAP_IDIVT (1 << 18)
32#define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT) 32#define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
33#define COMPAT_HWCAP_EVTSTRM (1 << 21)
33 34
34#ifndef __ASSEMBLY__ 35#ifndef __ASSEMBLY__
35/* 36/*
@@ -37,11 +38,11 @@
37 * instruction set this cpu supports. 38 * instruction set this cpu supports.
38 */ 39 */
39#define ELF_HWCAP (elf_hwcap) 40#define ELF_HWCAP (elf_hwcap)
40#define COMPAT_ELF_HWCAP (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\ 41
41 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\ 42#ifdef CONFIG_COMPAT
42 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\ 43#define COMPAT_ELF_HWCAP (compat_elf_hwcap)
43 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\ 44extern unsigned int compat_elf_hwcap;
44 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV) 45#endif
45 46
46extern unsigned long elf_hwcap; 47extern unsigned long elf_hwcap;
47#endif 48#endif
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index eea497578b87..9b12476e9c85 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -21,6 +21,7 @@
21 */ 21 */
22#define HWCAP_FP (1 << 0) 22#define HWCAP_FP (1 << 0)
23#define HWCAP_ASIMD (1 << 1) 23#define HWCAP_ASIMD (1 << 1)
24#define HWCAP_EVTSTRM (1 << 2)
24 25
25 26
26#endif /* _UAPI__ASM_HWCAP_H */ 27#endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 055cfb80e05c..d355b7b9710b 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -60,6 +60,16 @@ EXPORT_SYMBOL(processor_id);
60unsigned long elf_hwcap __read_mostly; 60unsigned long elf_hwcap __read_mostly;
61EXPORT_SYMBOL_GPL(elf_hwcap); 61EXPORT_SYMBOL_GPL(elf_hwcap);
62 62
63#ifdef CONFIG_COMPAT
64#define COMPAT_ELF_HWCAP_DEFAULT \
65 (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
66 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
67 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
68 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
69 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
70unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
71#endif
72
63static const char *cpu_name; 73static const char *cpu_name;
64static const char *machine_name; 74static const char *machine_name;
65phys_addr_t __fdt_pointer __initdata; 75phys_addr_t __fdt_pointer __initdata;
@@ -304,6 +314,7 @@ subsys_initcall(topology_init);
304static const char *hwcap_str[] = { 314static const char *hwcap_str[] = {
305 "fp", 315 "fp",
306 "asimd", 316 "asimd",
317 "evtstrm",
307 NULL 318 NULL
308}; 319};
309 320
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);
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 93b7f96f9c59..6d26b40cbf5d 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -33,6 +33,16 @@ enum arch_timer_reg {
33#define ARCH_TIMER_MEM_PHYS_ACCESS 2 33#define ARCH_TIMER_MEM_PHYS_ACCESS 2
34#define ARCH_TIMER_MEM_VIRT_ACCESS 3 34#define ARCH_TIMER_MEM_VIRT_ACCESS 3
35 35
36#define ARCH_TIMER_USR_PCT_ACCESS_EN (1 << 0) /* physical counter */
37#define ARCH_TIMER_USR_VCT_ACCESS_EN (1 << 1) /* virtual counter */
38#define ARCH_TIMER_VIRT_EVT_EN (1 << 2)
39#define ARCH_TIMER_EVT_TRIGGER_SHIFT (4)
40#define ARCH_TIMER_EVT_TRIGGER_MASK (0xF << ARCH_TIMER_EVT_TRIGGER_SHIFT)
41#define ARCH_TIMER_USR_VT_ACCESS_EN (1 << 8) /* virtual timer registers */
42#define ARCH_TIMER_USR_PT_ACCESS_EN (1 << 9) /* physical timer registers */
43
44#define ARCH_TIMER_EVT_STREAM_FREQ 10000 /* 100us */
45
36#ifdef CONFIG_ARM_ARCH_TIMER 46#ifdef CONFIG_ARM_ARCH_TIMER
37 47
38extern u32 arch_timer_get_rate(void); 48extern u32 arch_timer_get_rate(void);