forked from mirrors/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>
			
			
This commit is contained in:
		
							parent
							
								
									46efe547ac
								
							
						
					
					
						commit
						037f637767
					
				
					 3 changed files with 32 additions and 0 deletions
				
			
		|  | @ -74,6 +74,21 @@ config ARM_ARCH_TIMER | ||||||
| 	bool | 	bool | ||||||
| 	select CLKSRC_OF if OF | 	select CLKSRC_OF if OF | ||||||
| 
 | 
 | ||||||
|  | config ARM_ARCH_TIMER_EVTSTREAM | ||||||
|  | 	bool "Support for ARM architected timer event stream generation" | ||||||
|  | 	default y if ARM_ARCH_TIMER | ||||||
|  | 	help | ||||||
|  | 	  This option enables support for event stream generation based on | ||||||
|  | 	  the ARM architected timer. It is used for waking up CPUs executing | ||||||
|  | 	  the wfe instruction at a frequency represented as a power-of-2 | ||||||
|  | 	  divisor of the clock rate. | ||||||
|  | 	  The main use of the event stream is wfe-based timeouts of userspace | ||||||
|  | 	  locking implementations. It might also be useful for imposing timeout | ||||||
|  | 	  on wfe to safeguard against any programming errors in case an expected | ||||||
|  | 	  event is not generated. | ||||||
|  | 	  This must be disabled for hardware validation purposes to detect any | ||||||
|  | 	  hardware anomalies of missing events. | ||||||
|  | 
 | ||||||
| config ARM_GLOBAL_TIMER | config ARM_GLOBAL_TIMER | ||||||
| 	bool | 	bool | ||||||
| 	select CLKSRC_OF if OF | 	select CLKSRC_OF if OF | ||||||
|  |  | ||||||
|  | @ -294,6 +294,19 @@ static void __arch_timer_setup(unsigned type, | ||||||
| 	clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); | 	clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void arch_timer_configure_evtstream(void) | ||||||
|  | { | ||||||
|  | 	int evt_stream_div, pos; | ||||||
|  | 
 | ||||||
|  | 	/* Find the closest power of two to the divisor */ | ||||||
|  | 	evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ; | ||||||
|  | 	pos = fls(evt_stream_div); | ||||||
|  | 	if (pos > 1 && !(evt_stream_div & (1 << (pos - 2)))) | ||||||
|  | 		pos--; | ||||||
|  | 	/* enable event stream */ | ||||||
|  | 	arch_timer_evtstrm_enable(min(pos, 15)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int arch_timer_setup(struct clock_event_device *clk) | static int arch_timer_setup(struct clock_event_device *clk) | ||||||
| { | { | ||||||
| 	__arch_timer_setup(ARCH_CP15_TIMER, clk); | 	__arch_timer_setup(ARCH_CP15_TIMER, clk); | ||||||
|  | @ -307,6 +320,8 @@ static int arch_timer_setup(struct clock_event_device *clk) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	arch_counter_set_user_access(); | 	arch_counter_set_user_access(); | ||||||
|  | 	if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM)) | ||||||
|  | 		arch_timer_configure_evtstream(); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -41,6 +41,8 @@ enum arch_timer_reg { | ||||||
| #define ARCH_TIMER_USR_VT_ACCESS_EN	(1 << 8) /* virtual timer registers */ | #define ARCH_TIMER_USR_VT_ACCESS_EN	(1 << 8) /* virtual timer registers */ | ||||||
| #define ARCH_TIMER_USR_PT_ACCESS_EN	(1 << 9) /* physical timer registers */ | #define ARCH_TIMER_USR_PT_ACCESS_EN	(1 << 9) /* physical timer registers */ | ||||||
| 
 | 
 | ||||||
|  | #define ARCH_TIMER_EVT_STREAM_FREQ	10000	/* 100us */ | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_ARM_ARCH_TIMER | #ifdef CONFIG_ARM_ARCH_TIMER | ||||||
| 
 | 
 | ||||||
| extern u32 arch_timer_get_rate(void); | extern u32 arch_timer_get_rate(void); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Will Deacon
						Will Deacon