Commit 41ce82f6 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

KVM: arm64: timers: Move timer registers to the sys_regs file



Move the timer gsisters to the sysreg file. This will further help when
they are directly changed by a nesting hypervisor in the VNCR page.

This requires moving the initialisation of the timer struct so that some
of the helpers (such as arch_timer_ctx_index) can work correctly at an
early stage.

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 3c5ff0c6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -189,6 +189,12 @@ enum vcpu_sysreg {
	SP_EL1,
	SPSR_EL1,

	CNTVOFF_EL2,
	CNTV_CVAL_EL0,
	CNTV_CTL_EL0,
	CNTP_CVAL_EL0,
	CNTP_CTL_EL0,

	/* 32bit specific registers. Keep them at the end of the range */
	DACR32_EL2,	/* Domain Access Control Register */
	IFSR32_EL2,	/* Instruction Fault Status Register */
+122 −33
Original line number Diff line number Diff line
@@ -51,6 +51,93 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
			      struct arch_timer_context *timer,
			      enum kvm_arch_timer_regs treg);

u32 timer_get_ctl(struct arch_timer_context *ctxt)
{
	struct kvm_vcpu *vcpu = ctxt->vcpu;

	switch(arch_timer_ctx_index(ctxt)) {
	case TIMER_VTIMER:
		return __vcpu_sys_reg(vcpu, CNTV_CTL_EL0);
	case TIMER_PTIMER:
		return __vcpu_sys_reg(vcpu, CNTP_CTL_EL0);
	default:
		WARN_ON(1);
		return 0;
	}
}

u64 timer_get_cval(struct arch_timer_context *ctxt)
{
	struct kvm_vcpu *vcpu = ctxt->vcpu;

	switch(arch_timer_ctx_index(ctxt)) {
	case TIMER_VTIMER:
		return __vcpu_sys_reg(vcpu, CNTV_CVAL_EL0);
	case TIMER_PTIMER:
		return __vcpu_sys_reg(vcpu, CNTP_CVAL_EL0);
	default:
		WARN_ON(1);
		return 0;
	}
}

static u64 timer_get_offset(struct arch_timer_context *ctxt)
{
	struct kvm_vcpu *vcpu = ctxt->vcpu;

	switch(arch_timer_ctx_index(ctxt)) {
	case TIMER_VTIMER:
		return __vcpu_sys_reg(vcpu, CNTVOFF_EL2);
	default:
		return 0;
	}
}

static void timer_set_ctl(struct arch_timer_context *ctxt, u32 ctl)
{
	struct kvm_vcpu *vcpu = ctxt->vcpu;

	switch(arch_timer_ctx_index(ctxt)) {
	case TIMER_VTIMER:
		__vcpu_sys_reg(vcpu, CNTV_CTL_EL0) = ctl;
		break;
	case TIMER_PTIMER:
		__vcpu_sys_reg(vcpu, CNTP_CTL_EL0) = ctl;
		break;
	default:
		WARN_ON(1);
	}
}

static void timer_set_cval(struct arch_timer_context *ctxt, u64 cval)
{
	struct kvm_vcpu *vcpu = ctxt->vcpu;

	switch(arch_timer_ctx_index(ctxt)) {
	case TIMER_VTIMER:
		__vcpu_sys_reg(vcpu, CNTV_CVAL_EL0) = cval;
		break;
	case TIMER_PTIMER:
		__vcpu_sys_reg(vcpu, CNTP_CVAL_EL0) = cval;
		break;
	default:
		WARN_ON(1);
	}
}

static void timer_set_offset(struct arch_timer_context *ctxt, u64 offset)
{
	struct kvm_vcpu *vcpu = ctxt->vcpu;

	switch(arch_timer_ctx_index(ctxt)) {
	case TIMER_VTIMER:
		__vcpu_sys_reg(vcpu, CNTVOFF_EL2) = offset;
		break;
	default:
		WARN(offset, "timer %ld\n", arch_timer_ctx_index(ctxt));
	}
}

u64 kvm_phys_timer_read(void)
{
	return timecounter->cc->read(timecounter->cc);
@@ -124,8 +211,8 @@ static u64 kvm_timer_compute_delta(struct arch_timer_context *timer_ctx)
{
	u64 cval, now;

	cval = timer_ctx->cnt_cval;
	now = kvm_phys_timer_read() - timer_ctx->cntvoff;
	cval = timer_get_cval(timer_ctx);
	now = kvm_phys_timer_read() - timer_get_offset(timer_ctx);

	if (now < cval) {
		u64 ns;
@@ -144,8 +231,8 @@ static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx)
{
	WARN_ON(timer_ctx && timer_ctx->loaded);
	return timer_ctx &&
	       !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
		(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE);
		((timer_get_ctl(timer_ctx) &
		  (ARCH_TIMER_CTRL_IT_MASK | ARCH_TIMER_CTRL_ENABLE)) == ARCH_TIMER_CTRL_ENABLE);
}

/*
@@ -256,8 +343,8 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
	if (!kvm_timer_irq_can_fire(timer_ctx))
		return false;

	cval = timer_ctx->cnt_cval;
	now = kvm_phys_timer_read() - timer_ctx->cntvoff;
	cval = timer_get_cval(timer_ctx);
	now = kvm_phys_timer_read() - timer_get_offset(timer_ctx);

	return cval <= now;
}
@@ -350,8 +437,8 @@ static void timer_save_state(struct arch_timer_context *ctx)

	switch (index) {
	case TIMER_VTIMER:
		ctx->cnt_ctl = read_sysreg_el0(SYS_CNTV_CTL);
		ctx->cnt_cval = read_sysreg_el0(SYS_CNTV_CVAL);
		timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTV_CTL));
		timer_set_cval(ctx, read_sysreg_el0(SYS_CNTV_CVAL));

		/* Disable the timer */
		write_sysreg_el0(0, SYS_CNTV_CTL);
@@ -359,8 +446,8 @@ static void timer_save_state(struct arch_timer_context *ctx)

		break;
	case TIMER_PTIMER:
		ctx->cnt_ctl = read_sysreg_el0(SYS_CNTP_CTL);
		ctx->cnt_cval = read_sysreg_el0(SYS_CNTP_CVAL);
		timer_set_ctl(ctx, read_sysreg_el0(SYS_CNTP_CTL));
		timer_set_cval(ctx, read_sysreg_el0(SYS_CNTP_CVAL));

		/* Disable the timer */
		write_sysreg_el0(0, SYS_CNTP_CTL);
@@ -429,14 +516,14 @@ static void timer_restore_state(struct arch_timer_context *ctx)

	switch (index) {
	case TIMER_VTIMER:
		write_sysreg_el0(ctx->cnt_cval, SYS_CNTV_CVAL);
		write_sysreg_el0(timer_get_cval(ctx), SYS_CNTV_CVAL);
		isb();
		write_sysreg_el0(ctx->cnt_ctl, SYS_CNTV_CTL);
		write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTV_CTL);
		break;
	case TIMER_PTIMER:
		write_sysreg_el0(ctx->cnt_cval, SYS_CNTP_CVAL);
		write_sysreg_el0(timer_get_cval(ctx), SYS_CNTP_CVAL);
		isb();
		write_sysreg_el0(ctx->cnt_ctl, SYS_CNTP_CTL);
		write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTP_CTL);
		break;
	case NR_KVM_TIMERS:
		BUG();
@@ -528,7 +615,7 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
		kvm_timer_vcpu_load_nogic(vcpu);
	}

	set_cntvoff(map.direct_vtimer->cntvoff);
	set_cntvoff(timer_get_offset(map.direct_vtimer));

	kvm_timer_unblocking(vcpu);

@@ -639,8 +726,8 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
	 * resets the timer to be disabled and unmasked and is compliant with
	 * the ARMv7 architecture.
	 */
	vcpu_vtimer(vcpu)->cnt_ctl = 0;
	vcpu_ptimer(vcpu)->cnt_ctl = 0;
	timer_set_ctl(vcpu_vtimer(vcpu), 0);
	timer_set_ctl(vcpu_ptimer(vcpu), 0);

	if (timer->enabled) {
		kvm_timer_update_irq(vcpu, false, vcpu_vtimer(vcpu));
@@ -668,13 +755,13 @@ static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff)

	mutex_lock(&kvm->lock);
	kvm_for_each_vcpu(i, tmp, kvm)
		vcpu_vtimer(tmp)->cntvoff = cntvoff;
		timer_set_offset(vcpu_vtimer(tmp), cntvoff);

	/*
	 * When called from the vcpu create path, the CPU being created is not
	 * included in the loop above, so we just set it here as well.
	 */
	vcpu_vtimer(vcpu)->cntvoff = cntvoff;
	timer_set_offset(vcpu_vtimer(vcpu), cntvoff);
	mutex_unlock(&kvm->lock);
}

@@ -684,9 +771,12 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);

	vtimer->vcpu = vcpu;
	ptimer->vcpu = vcpu;

	/* Synchronize cntvoff across all vtimers of a VM. */
	update_vtimer_cntvoff(vcpu, kvm_phys_timer_read());
	ptimer->cntvoff = 0;
	timer_set_offset(ptimer, 0);

	hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
	timer->bg_timer.function = kvm_bg_timer_expire;
@@ -704,9 +794,6 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)

	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;

	vtimer->vcpu = vcpu;
	ptimer->vcpu = vcpu;
}

static void kvm_timer_init_interrupt(void *info)
@@ -756,10 +843,12 @@ static u64 read_timer_ctl(struct arch_timer_context *timer)
	 * UNKNOWN when ENABLE bit is 0, so we chose to set ISTATUS bit
	 * regardless of ENABLE bit for our implementation convenience.
	 */
	u32 ctl = timer_get_ctl(timer);

	if (!kvm_timer_compute_delta(timer))
		return timer->cnt_ctl | ARCH_TIMER_CTRL_IT_STAT;
	else
		return timer->cnt_ctl;
		ctl |= ARCH_TIMER_CTRL_IT_STAT;

	return ctl;
}

u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
@@ -795,8 +884,8 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,

	switch (treg) {
	case TIMER_REG_TVAL:
		val = timer->cnt_cval - kvm_phys_timer_read() + timer->cntvoff;
		val &= lower_32_bits(val);
		val = timer_get_cval(timer) - kvm_phys_timer_read() + timer_get_offset(timer);
		val = lower_32_bits(val);
		break;

	case TIMER_REG_CTL:
@@ -804,11 +893,11 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
		break;

	case TIMER_REG_CVAL:
		val = timer->cnt_cval;
		val = timer_get_cval(timer);
		break;

	case TIMER_REG_CNT:
		val = kvm_phys_timer_read() - timer->cntvoff;
		val = kvm_phys_timer_read() - timer_get_offset(timer);
		break;

	default:
@@ -842,15 +931,15 @@ static void kvm_arm_timer_write(struct kvm_vcpu *vcpu,
{
	switch (treg) {
	case TIMER_REG_TVAL:
		timer->cnt_cval = kvm_phys_timer_read() - timer->cntvoff + (s32)val;
		timer_set_cval(timer, kvm_phys_timer_read() - timer_get_offset(timer) + (s32)val);
		break;

	case TIMER_REG_CTL:
		timer->cnt_ctl = val & ~ARCH_TIMER_CTRL_IT_STAT;
		timer_set_ctl(timer, val & ~ARCH_TIMER_CTRL_IT_STAT);
		break;

	case TIMER_REG_CVAL:
		timer->cnt_cval = val;
		timer_set_cval(timer, val);
		break;

	default:
+4 −4
Original line number Diff line number Diff line
@@ -301,8 +301,8 @@ TRACE_EVENT(kvm_timer_save_state,
	),

	TP_fast_assign(
		__entry->ctl			= ctx->cnt_ctl;
		__entry->cval			= ctx->cnt_cval;
		__entry->ctl			= timer_get_ctl(ctx);
		__entry->cval			= timer_get_cval(ctx);
		__entry->timer_idx		= arch_timer_ctx_index(ctx);
	),

@@ -323,8 +323,8 @@ TRACE_EVENT(kvm_timer_restore_state,
	),

	TP_fast_assign(
		__entry->ctl			= ctx->cnt_ctl;
		__entry->cval			= ctx->cnt_cval;
		__entry->ctl			= timer_get_ctl(ctx);
		__entry->cval			= timer_get_cval(ctx);
		__entry->timer_idx		= arch_timer_ctx_index(ctx);
	),

+4 −7
Original line number Diff line number Diff line
@@ -26,16 +26,9 @@ enum kvm_arch_timer_regs {
struct arch_timer_context {
	struct kvm_vcpu			*vcpu;

	/* Registers: control register, timer value */
	u32				cnt_ctl;
	u64				cnt_cval;

	/* Timer IRQ */
	struct kvm_irq_level		irq;

	/* Virtual offset */
	u64				cntvoff;

	/* Emulated Timer (may be unused) */
	struct hrtimer			hrtimer;

@@ -109,4 +102,8 @@ void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu,
				enum kvm_arch_timer_regs treg,
				u64 val);

/* Needed for tracing */
u32 timer_get_ctl(struct arch_timer_context *ctxt);
u64 timer_get_cval(struct arch_timer_context *ctxt);

#endif