Skip to content

Commit

Permalink
arm_arch_timer: Expose event stream status
Browse files Browse the repository at this point in the history
The arch timer configuration for a CPU might get reset after suspending
said CPU.

In order to reliably use the event stream in the kernel (e.g. for delays),
we keep track of the state where we can safely consider the event stream as
properly configured. After writing to cntkctl, we issue an ISB to ensure
that subsequent delay loops can rely on the event stream being enabled.

Signed-off-by: Julien Thierry <julien.thierry@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Danny Lin <danny@kdrag0n.dev>
  • Loading branch information
Julien Thierry authored and wloot committed Mar 22, 2019
1 parent 2410865 commit 44c3efa
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 2 deletions.
1 change: 1 addition & 0 deletions arch/arm/include/asm/arch_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ static inline u32 arch_timer_get_cntkctl(void)
static inline void arch_timer_set_cntkctl(u32 cntkctl)
{
asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
isb();
}

#endif
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/include/asm/arch_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ static inline u32 arch_timer_get_cntkctl(void)
static inline void arch_timer_set_cntkctl(u32 cntkctl)
{
asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
isb();
}

static inline u64 arch_counter_get_cntpct(void)
Expand Down
25 changes: 23 additions & 2 deletions drivers/clocksource/arm_arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ static bool arch_timer_use_virtual = true;
static bool arch_timer_c3stop;
static bool arch_timer_mem_use_virtual;

static cpumask_t evtstrm_available = CPU_MASK_NONE;

/*
* Architected system timer support.
*/
Expand Down Expand Up @@ -307,6 +309,7 @@ static void arch_timer_evtstrm_enable(int divider)
#ifdef CONFIG_COMPAT
compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
#endif
cpumask_set_cpu(smp_processor_id(), &evtstrm_available);
}

static void arch_timer_configure_evtstream(void)
Expand Down Expand Up @@ -408,6 +411,16 @@ u32 arch_timer_get_rate(void)
return arch_timer_rate;
}

bool arch_timer_evtstrm_available(void)
{
/*
* We might get called from a preemptible context. This is fine
* because availability of the event stream should be always the same
* for a preemptible context and context where we might resume a task.
*/
return cpumask_test_cpu(raw_smp_processor_id(), &evtstrm_available);
}

static u64 arch_counter_get_cntvct_mem(void)
{
u32 vct_lo, vct_hi, tmp_hi;
Expand Down Expand Up @@ -522,6 +535,8 @@ static int arch_timer_cpu_notify(struct notifier_block *self,
break;
}

cpumask_clear_cpu(smp_processor_id(), &evtstrm_available);

return NOTIFY_OK;
}

Expand All @@ -534,10 +549,16 @@ static DEFINE_PER_CPU(unsigned long, saved_cntkctl);
static int arch_timer_cpu_pm_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
if (action == CPU_PM_ENTER)
if (action == CPU_PM_ENTER) {
__this_cpu_write(saved_cntkctl, arch_timer_get_cntkctl());
else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT)

cpumask_clear_cpu(smp_processor_id(), &evtstrm_available);
} else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) {
arch_timer_set_cntkctl(__this_cpu_read(saved_cntkctl));

if (elf_hwcap & HWCAP_EVTSTRM)
cpumask_set_cpu(smp_processor_id(), &evtstrm_available);
}
return NOTIFY_OK;
}

Expand Down
6 changes: 6 additions & 0 deletions include/clocksource/arm_arch_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ extern u32 arch_timer_get_rate(void);
extern u64 (*arch_timer_read_counter)(void);
extern struct timecounter *arch_timer_get_timecounter(void);

extern bool arch_timer_evtstrm_available(void);
#else

static inline u32 arch_timer_get_rate(void)
Expand All @@ -74,6 +75,11 @@ static inline struct timecounter *arch_timer_get_timecounter(void)
return NULL;
}

static inline bool arch_timer_evtstrm_available(void)
{
return false;
}

#endif

#endif

0 comments on commit 44c3efa

Please sign in to comment.