Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: clocksource: add support for ARM architected timer event stream

The ARM architected timer can generate events (used for waking up
CPUs executing the wfe instruction) at a frequency represented as a
power-of-2 divisor of the clock rate.

An event stream might be used:
- To implement wfe-based timeouts for userspace locking implementations.
- To impose a timeout on a wfe for safeguarding against any programming
error in case an expected event is not generated.

This patch computes the event stream frequency aiming for a period
of 100us between events. It uses ARM/ARM64 specific backends to configure
and enable the event stream.

Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Will Deacon <will.deacon@arm.com>
[sudeep: moving ARM/ARM64 changes into separate patches
and adding Kconfig option]
Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>

authored by

Will Deacon and committed by
Sudeep KarkadaNagesha
037f6377 46efe547

+32
+15
drivers/clocksource/Kconfig
··· 74 74 bool 75 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 92 config ARM_GLOBAL_TIMER 78 93 bool 79 94 select CLKSRC_OF if OF
+15
drivers/clocksource/arm_arch_timer.c
··· 294 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 310 static int arch_timer_setup(struct clock_event_device *clk) 298 311 { 299 312 __arch_timer_setup(ARCH_CP15_TIMER, clk); ··· 320 307 } 321 308 322 309 arch_counter_set_user_access(); 310 + if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM)) 311 + arch_timer_configure_evtstream(); 323 312 324 313 return 0; 325 314 }
+2
include/clocksource/arm_arch_timer.h
··· 41 41 #define ARCH_TIMER_USR_VT_ACCESS_EN (1 << 8) /* virtual timer registers */ 42 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 46 #ifdef CONFIG_ARM_ARCH_TIMER 45 47 46 48 extern u32 arch_timer_get_rate(void);