arch/arm64/include/asm/arch_timer.h

Source file repositories/reference/linux-study-clean/arch/arm64/include/asm/arch_timer.h

File Facts

System
Linux kernel
Corpus path
arch/arm64/include/asm/arch_timer.h
Extension
.h
Size
4737 bytes
Lines
222
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct arch_timer_erratum_workaround {
	enum arch_timer_erratum_match_type match_type;
	const void *id;
	const char *desc;
	u64 (*read_cntpct_el0)(void);
	u64 (*read_cntvct_el0)(void);
	int (*set_next_event_phys)(unsigned long, struct clock_event_device *);
	int (*set_next_event_virt)(unsigned long, struct clock_event_device *);
	bool disable_compat_vdso;
};

DECLARE_PER_CPU(const struct arch_timer_erratum_workaround *,
		timer_unstable_counter_workaround);

static inline notrace u64 arch_timer_read_cntpct_el0(void)
{
	u64 cnt;

	asm volatile(ALTERNATIVE("isb\n mrs %0, cntpct_el0",
				 "nop\n" __mrs_s("%0", SYS_CNTPCTSS_EL0),
				 ARM64_HAS_ECV)
		     : "=r" (cnt));

	return cnt;
}

static inline notrace u64 arch_timer_read_cntvct_el0(void)
{
	u64 cnt;

	asm volatile(ALTERNATIVE("isb\n mrs %0, cntvct_el0",
				 "nop\n" __mrs_s("%0", SYS_CNTVCTSS_EL0),
				 ARM64_HAS_ECV)
		     : "=r" (cnt));

	return cnt;
}

#define arch_timer_reg_read_stable(reg)					\
	({								\
		erratum_handler(read_ ## reg)();			\
	})

/*
 * These register accessors are marked inline so the compiler can
 * nicely work out which register we want, and chuck away the rest of
 * the code.
 */
static __always_inline
void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u64 val)
{
	if (access == ARCH_TIMER_PHYS_ACCESS) {
		switch (reg) {
		case ARCH_TIMER_REG_CTRL:
			write_sysreg(val, cntp_ctl_el0);
			isb();
			break;
		case ARCH_TIMER_REG_CVAL:
			write_sysreg(val, cntp_cval_el0);
			break;
		default:
			BUILD_BUG();
		}
	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
		switch (reg) {
		case ARCH_TIMER_REG_CTRL:
			write_sysreg(val, cntv_ctl_el0);
			isb();
			break;
		case ARCH_TIMER_REG_CVAL:
			write_sysreg(val, cntv_cval_el0);
			break;
		default:
			BUILD_BUG();
		}
	} else {
		BUILD_BUG();
	}
}

static __always_inline
u64 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
{
	if (access == ARCH_TIMER_PHYS_ACCESS) {
		switch (reg) {
		case ARCH_TIMER_REG_CTRL:
			return read_sysreg(cntp_ctl_el0);
		default:
			BUILD_BUG();
		}

Annotation

Implementation Notes