Skip to content

Commit 2b4825a

Browse files
author
Marc Zyngier
committed
KVM: arm64: timers: Use CNTPOFF_EL2 to offset the physical timer
With ECV and CNTPOFF_EL2, it is very easy to offer an offset for the physical timer. So let's do just that. Nothing can set the offset yet, so this should have no effect whatsoever (famous last words...). Reviewed-by: Colton Lewis <coltonlewis@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20230330174800.2677007-5-maz@kernel.org
1 parent 3263499 commit 2b4825a

File tree

4 files changed

+21
-2
lines changed

4 files changed

+21
-2
lines changed

arch/arm64/kvm/arch_timer.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
5252
struct arch_timer_context *timer,
5353
enum kvm_arch_timer_regs treg);
5454

55+
static bool has_cntpoff(void)
56+
{
57+
return (has_vhe() && cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF));
58+
}
59+
5560
u32 timer_get_ctl(struct arch_timer_context *ctxt)
5661
{
5762
struct kvm_vcpu *vcpu = ctxt->vcpu;
@@ -84,7 +89,7 @@ u64 timer_get_cval(struct arch_timer_context *ctxt)
8489

8590
static u64 timer_get_offset(struct arch_timer_context *ctxt)
8691
{
87-
if (ctxt->offset.vm_offset)
92+
if (ctxt && ctxt->offset.vm_offset)
8893
return *ctxt->offset.vm_offset;
8994

9095
return 0;
@@ -432,6 +437,12 @@ static void set_cntvoff(u64 cntvoff)
432437
kvm_call_hyp(__kvm_timer_set_cntvoff, cntvoff);
433438
}
434439

440+
static void set_cntpoff(u64 cntpoff)
441+
{
442+
if (has_cntpoff())
443+
write_sysreg_s(cntpoff, SYS_CNTPOFF_EL2);
444+
}
445+
435446
static void timer_save_state(struct arch_timer_context *ctx)
436447
{
437448
struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
@@ -480,6 +491,7 @@ static void timer_save_state(struct arch_timer_context *ctx)
480491
write_sysreg_el0(0, SYS_CNTP_CTL);
481492
isb();
482493

494+
set_cntpoff(0);
483495
break;
484496
case NR_KVM_TIMERS:
485497
BUG();
@@ -550,6 +562,7 @@ static void timer_restore_state(struct arch_timer_context *ctx)
550562
write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTV_CTL);
551563
break;
552564
case TIMER_PTIMER:
565+
set_cntpoff(timer_get_offset(ctx));
553566
write_sysreg_el0(timer_get_cval(ctx), SYS_CNTP_CVAL);
554567
isb();
555568
write_sysreg_el0(timer_get_ctl(ctx), SYS_CNTP_CTL);
@@ -767,6 +780,7 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
767780
vtimer->vcpu = vcpu;
768781
vtimer->offset.vm_offset = &vcpu->kvm->arch.timer_data.voffset;
769782
ptimer->vcpu = vcpu;
783+
ptimer->offset.vm_offset = &vcpu->kvm->arch.timer_data.poffset;
770784

771785
/* Synchronize cntvoff across all vtimers of a VM. */
772786
timer_set_offset(vtimer, kvm_phys_timer_read());
@@ -1297,6 +1311,8 @@ void kvm_timer_init_vhe(void)
12971311
val = read_sysreg(cnthctl_el2);
12981312
val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
12991313
val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
1314+
if (cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF))
1315+
val |= CNTHCTL_ECV;
13001316
write_sysreg(val, cnthctl_el2);
13011317
}
13021318

arch/arm64/kvm/hypercalls.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
4747
cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.voffset;
4848
break;
4949
case KVM_PTP_PHYS_COUNTER:
50-
cycles = systime_snapshot.cycles;
50+
cycles = systime_snapshot.cycles - vcpu->kvm->arch.timer_data.poffset;
5151
break;
5252
default:
5353
return;

include/clocksource/arm_arch_timer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#define CNTHCTL_EVNTEN (1 << 2)
2222
#define CNTHCTL_EVNTDIR (1 << 3)
2323
#define CNTHCTL_EVNTI (0xF << 4)
24+
#define CNTHCTL_ECV (1 << 12)
2425

2526
enum arch_timer_reg {
2627
ARCH_TIMER_REG_CTRL,

include/kvm/arm_arch_timer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ struct arch_timer_offset {
3434
struct arch_timer_vm_data {
3535
/* Offset applied to the virtual timer/counter */
3636
u64 voffset;
37+
/* Offset applied to the physical timer/counter */
38+
u64 poffset;
3739
};
3840

3941
struct arch_timer_context {

0 commit comments

Comments
 (0)