Commit 191124ef authored by Daniel Lezcano's avatar Daniel Lezcano
Browse files

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: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
parents 68e90740 346e7480
Loading
Loading
Loading
Loading
+31 −5
Original line number Diff line number Diff line
@@ -87,17 +87,43 @@ static inline u64 arch_counter_get_cntvct(void)
	return cval;
}

static inline void arch_counter_set_user_access(void)
static inline u32 arch_timer_get_cntkctl(void)
{
	u32 cntkctl;

	asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl));
	return cntkctl;
}

	/* disable user access to everything */
	cntkctl &= ~((3 << 8) | (7 << 0));

static inline void arch_timer_set_cntkctl(u32 cntkctl)
{
	asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl));
}

static inline void arch_counter_set_user_access(void)
{
	u32 cntkctl = arch_timer_get_cntkctl();

	/* Disable user access to both physical/virtual counters/timers */
	/* Also disable virtual event stream */
	cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
			| ARCH_TIMER_USR_VT_ACCESS_EN
			| ARCH_TIMER_VIRT_EVT_EN
			| ARCH_TIMER_USR_VCT_ACCESS_EN
			| ARCH_TIMER_USR_PCT_ACCESS_EN);
	arch_timer_set_cntkctl(cntkctl);
}

static inline void arch_timer_evtstrm_enable(int divider)
{
	u32 cntkctl = arch_timer_get_cntkctl();
	cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK;
	/* Set the divider and enable virtual event stream */
	cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
			| ARCH_TIMER_VIRT_EVT_EN;
	arch_timer_set_cntkctl(cntkctl);
	elf_hwcap |= HWCAP_EVTSTRM;
}

#endif

#endif
+1 −0
Original line number Diff line number Diff line
@@ -26,5 +26,6 @@
#define HWCAP_VFPD32	(1 << 19)	/* set if VFP has 32 regs (not 16) */
#define HWCAP_IDIV	(HWCAP_IDIVA | HWCAP_IDIVT)
#define HWCAP_LPAE	(1 << 20)
#define HWCAP_EVTSTRM	(1 << 21)

#endif /* _UAPI__ASMARM_HWCAP_H */
+1 −0
Original line number Diff line number Diff line
@@ -975,6 +975,7 @@ static const char *hwcap_str[] = {
	"idivt",
	"vfpd32",
	"lpae",
	"evtstrm",
	NULL
};

+36 −6
Original line number Diff line number Diff line
@@ -92,19 +92,49 @@ static inline u32 arch_timer_get_cntfrq(void)
	return val;
}

static inline void arch_counter_set_user_access(void)
static inline u32 arch_timer_get_cntkctl(void)
{
	u32 cntkctl;

	/* Disable user access to the timers and the physical counter. */
	asm volatile("mrs	%0, cntkctl_el1" : "=r" (cntkctl));
	cntkctl &= ~((3 << 8) | (1 << 0));
	return cntkctl;
}

	/* Enable user access to the virtual counter and frequency. */
	cntkctl |= (1 << 1);
static inline void arch_timer_set_cntkctl(u32 cntkctl)
{
	asm volatile("msr	cntkctl_el1, %0" : : "r" (cntkctl));
}

static inline void arch_counter_set_user_access(void)
{
	u32 cntkctl = arch_timer_get_cntkctl();

	/* Disable user access to the timers and the physical counter */
	/* Also disable virtual event stream */
	cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
			| ARCH_TIMER_USR_VT_ACCESS_EN
			| ARCH_TIMER_VIRT_EVT_EN
			| ARCH_TIMER_USR_PCT_ACCESS_EN);

	/* Enable user access to the virtual counter */
	cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;

	arch_timer_set_cntkctl(cntkctl);
}

static inline void arch_timer_evtstrm_enable(int divider)
{
	u32 cntkctl = arch_timer_get_cntkctl();
	cntkctl &= ~ARCH_TIMER_EVT_TRIGGER_MASK;
	/* Set the divider and enable virtual event stream */
	cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT)
			| ARCH_TIMER_VIRT_EVT_EN;
	arch_timer_set_cntkctl(cntkctl);
	elf_hwcap |= HWCAP_EVTSTRM;
#ifdef CONFIG_COMPAT
	compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM;
#endif
}

static inline u64 arch_counter_get_cntvct(void)
{
	u64 cval;
+6 −5
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#define COMPAT_HWCAP_IDIVA	(1 << 17)
#define COMPAT_HWCAP_IDIVT	(1 << 18)
#define COMPAT_HWCAP_IDIV	(COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
#define COMPAT_HWCAP_EVTSTRM	(1 << 21)

#ifndef __ASSEMBLY__
/*
@@ -37,11 +38,11 @@
 * instruction set this cpu supports.
 */
#define ELF_HWCAP		(elf_hwcap)
#define COMPAT_ELF_HWCAP	(COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\
				 COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
				 COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
				 COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
				 COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)

#ifdef CONFIG_COMPAT
#define COMPAT_ELF_HWCAP	(compat_elf_hwcap)
extern unsigned int compat_elf_hwcap;
#endif

extern unsigned long elf_hwcap;
#endif
Loading