diff options
-rw-r--r-- | drivers/clocksource/Kconfig | 15 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 15 | ||||
-rw-r--r-- | include/clocksource/arm_arch_timer.h | 2 |
3 files changed, 32 insertions, 0 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 41c69469ce20..559d80335446 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -74,6 +74,21 @@ config ARM_ARCH_TIMER | |||
74 | bool | 74 | bool |
75 | select CLKSRC_OF if OF | 75 | select CLKSRC_OF if OF |
76 | 76 | ||
77 | config ARM_ARCH_TIMER_EVTSTREAM | ||
78 | bool "Support for ARM architected timer event stream generation" | ||
79 | default y if ARM_ARCH_TIMER | ||
80 | help | ||
81 | This option enables support for event stream generation based on | ||
82 | the ARM architected timer. It is used for waking up CPUs executing | ||
83 | the wfe instruction at a frequency represented as a power-of-2 | ||
84 | divisor of the clock rate. | ||
85 | The main use of the event stream is wfe-based timeouts of userspace | ||
86 | locking implementations. It might also be useful for imposing timeout | ||
87 | on wfe to safeguard against any programming errors in case an expected | ||
88 | event is not generated. | ||
89 | This must be disabled for hardware validation purposes to detect any | ||
90 | hardware anomalies of missing events. | ||
91 | |||
77 | config ARM_GLOBAL_TIMER | 92 | config ARM_GLOBAL_TIMER |
78 | bool | 93 | bool |
79 | select CLKSRC_OF if OF | 94 | select CLKSRC_OF if OF |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index fbd9ccd5e114..105f8ffa66a8 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -294,6 +294,19 @@ static void __arch_timer_setup(unsigned type, | |||
294 | clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); | 294 | clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); |
295 | } | 295 | } |
296 | 296 | ||
297 | static void arch_timer_configure_evtstream(void) | ||
298 | { | ||
299 | int evt_stream_div, pos; | ||
300 | |||
301 | /* Find the closest power of two to the divisor */ | ||
302 | evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ; | ||
303 | pos = fls(evt_stream_div); | ||
304 | if (pos > 1 && !(evt_stream_div & (1 << (pos - 2)))) | ||
305 | pos--; | ||
306 | /* enable event stream */ | ||
307 | arch_timer_evtstrm_enable(min(pos, 15)); | ||
308 | } | ||
309 | |||
297 | static int arch_timer_setup(struct clock_event_device *clk) | 310 | static int arch_timer_setup(struct clock_event_device *clk) |
298 | { | 311 | { |
299 | __arch_timer_setup(ARCH_CP15_TIMER, clk); | 312 | __arch_timer_setup(ARCH_CP15_TIMER, clk); |
@@ -307,6 +320,8 @@ static int arch_timer_setup(struct clock_event_device *clk) | |||
307 | } | 320 | } |
308 | 321 | ||
309 | arch_counter_set_user_access(); | 322 | arch_counter_set_user_access(); |
323 | if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM)) | ||
324 | arch_timer_configure_evtstream(); | ||
310 | 325 | ||
311 | return 0; | 326 | return 0; |
312 | } | 327 | } |
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h index 8707dae4cee2..6d26b40cbf5d 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h | |||
@@ -41,6 +41,8 @@ enum arch_timer_reg { | |||
41 | #define ARCH_TIMER_USR_VT_ACCESS_EN (1 << 8) /* virtual timer registers */ | 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 */ | 42 | #define ARCH_TIMER_USR_PT_ACCESS_EN (1 << 9) /* physical timer registers */ |
43 | 43 | ||
44 | #define ARCH_TIMER_EVT_STREAM_FREQ 10000 /* 100us */ | ||
45 | |||
44 | #ifdef CONFIG_ARM_ARCH_TIMER | 46 | #ifdef CONFIG_ARM_ARCH_TIMER |
45 | 47 | ||
46 | extern u32 arch_timer_get_rate(void); | 48 | extern u32 arch_timer_get_rate(void); |