162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2019 Western Digital Corporation or its affiliates. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: 662306a36Sopenharmony_ci * Atish Patra <atish.patra@wdc.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/err.h> 1162306a36Sopenharmony_ci#include <linux/kvm_host.h> 1262306a36Sopenharmony_ci#include <linux/uaccess.h> 1362306a36Sopenharmony_ci#include <clocksource/timer-riscv.h> 1462306a36Sopenharmony_ci#include <asm/csr.h> 1562306a36Sopenharmony_ci#include <asm/delay.h> 1662306a36Sopenharmony_ci#include <asm/kvm_vcpu_timer.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic u64 kvm_riscv_current_cycles(struct kvm_guest_timer *gt) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci return get_cycles64() + gt->time_delta; 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic u64 kvm_riscv_delta_cycles2ns(u64 cycles, 2462306a36Sopenharmony_ci struct kvm_guest_timer *gt, 2562306a36Sopenharmony_ci struct kvm_vcpu_timer *t) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci unsigned long flags; 2862306a36Sopenharmony_ci u64 cycles_now, cycles_delta, delta_ns; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci local_irq_save(flags); 3162306a36Sopenharmony_ci cycles_now = kvm_riscv_current_cycles(gt); 3262306a36Sopenharmony_ci if (cycles_now < cycles) 3362306a36Sopenharmony_ci cycles_delta = cycles - cycles_now; 3462306a36Sopenharmony_ci else 3562306a36Sopenharmony_ci cycles_delta = 0; 3662306a36Sopenharmony_ci delta_ns = (cycles_delta * gt->nsec_mult) >> gt->nsec_shift; 3762306a36Sopenharmony_ci local_irq_restore(flags); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci return delta_ns; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic enum hrtimer_restart kvm_riscv_vcpu_hrtimer_expired(struct hrtimer *h) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci u64 delta_ns; 4562306a36Sopenharmony_ci struct kvm_vcpu_timer *t = container_of(h, struct kvm_vcpu_timer, hrt); 4662306a36Sopenharmony_ci struct kvm_vcpu *vcpu = container_of(t, struct kvm_vcpu, arch.timer); 4762306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (kvm_riscv_current_cycles(gt) < t->next_cycles) { 5062306a36Sopenharmony_ci delta_ns = kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t); 5162306a36Sopenharmony_ci hrtimer_forward_now(&t->hrt, ktime_set(0, delta_ns)); 5262306a36Sopenharmony_ci return HRTIMER_RESTART; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci t->next_set = false; 5662306a36Sopenharmony_ci kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_TIMER); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return HRTIMER_NORESTART; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci if (!t->init_done || !t->next_set) 6462306a36Sopenharmony_ci return -EINVAL; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci hrtimer_cancel(&t->hrt); 6762306a36Sopenharmony_ci t->next_set = false; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int kvm_riscv_vcpu_update_vstimecmp(struct kvm_vcpu *vcpu, u64 ncycles) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci#if defined(CONFIG_32BIT) 7562306a36Sopenharmony_ci csr_write(CSR_VSTIMECMP, ncycles & 0xFFFFFFFF); 7662306a36Sopenharmony_ci csr_write(CSR_VSTIMECMPH, ncycles >> 32); 7762306a36Sopenharmony_ci#else 7862306a36Sopenharmony_ci csr_write(CSR_VSTIMECMP, ncycles); 7962306a36Sopenharmony_ci#endif 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int kvm_riscv_vcpu_update_hrtimer(struct kvm_vcpu *vcpu, u64 ncycles) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 8662306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 8762306a36Sopenharmony_ci u64 delta_ns; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (!t->init_done) 9062306a36Sopenharmony_ci return -EINVAL; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_TIMER); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci delta_ns = kvm_riscv_delta_cycles2ns(ncycles, gt, t); 9562306a36Sopenharmony_ci t->next_cycles = ncycles; 9662306a36Sopenharmony_ci hrtimer_start(&t->hrt, ktime_set(0, delta_ns), HRTIMER_MODE_REL); 9762306a36Sopenharmony_ci t->next_set = true; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciint kvm_riscv_vcpu_timer_next_event(struct kvm_vcpu *vcpu, u64 ncycles) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return t->timer_next_event(vcpu, ncycles); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic enum hrtimer_restart kvm_riscv_vcpu_vstimer_expired(struct hrtimer *h) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci u64 delta_ns; 11262306a36Sopenharmony_ci struct kvm_vcpu_timer *t = container_of(h, struct kvm_vcpu_timer, hrt); 11362306a36Sopenharmony_ci struct kvm_vcpu *vcpu = container_of(t, struct kvm_vcpu, arch.timer); 11462306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (kvm_riscv_current_cycles(gt) < t->next_cycles) { 11762306a36Sopenharmony_ci delta_ns = kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t); 11862306a36Sopenharmony_ci hrtimer_forward_now(&t->hrt, ktime_set(0, delta_ns)); 11962306a36Sopenharmony_ci return HRTIMER_RESTART; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci t->next_set = false; 12362306a36Sopenharmony_ci kvm_vcpu_kick(vcpu); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return HRTIMER_NORESTART; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cibool kvm_riscv_vcpu_timer_pending(struct kvm_vcpu *vcpu) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 13162306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (!kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t) || 13462306a36Sopenharmony_ci kvm_riscv_vcpu_has_interrupts(vcpu, 1UL << IRQ_VS_TIMER)) 13562306a36Sopenharmony_ci return true; 13662306a36Sopenharmony_ci else 13762306a36Sopenharmony_ci return false; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void kvm_riscv_vcpu_timer_blocking(struct kvm_vcpu *vcpu) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 14362306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 14462306a36Sopenharmony_ci u64 delta_ns; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!t->init_done) 14762306a36Sopenharmony_ci return; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci delta_ns = kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t); 15062306a36Sopenharmony_ci hrtimer_start(&t->hrt, ktime_set(0, delta_ns), HRTIMER_MODE_REL); 15162306a36Sopenharmony_ci t->next_set = true; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void kvm_riscv_vcpu_timer_unblocking(struct kvm_vcpu *vcpu) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci kvm_riscv_vcpu_timer_cancel(&vcpu->arch.timer); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ciint kvm_riscv_vcpu_get_reg_timer(struct kvm_vcpu *vcpu, 16062306a36Sopenharmony_ci const struct kvm_one_reg *reg) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 16362306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 16462306a36Sopenharmony_ci u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; 16562306a36Sopenharmony_ci unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 16662306a36Sopenharmony_ci KVM_REG_SIZE_MASK | 16762306a36Sopenharmony_ci KVM_REG_RISCV_TIMER); 16862306a36Sopenharmony_ci u64 reg_val; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (KVM_REG_SIZE(reg->id) != sizeof(u64)) 17162306a36Sopenharmony_ci return -EINVAL; 17262306a36Sopenharmony_ci if (reg_num >= sizeof(struct kvm_riscv_timer) / sizeof(u64)) 17362306a36Sopenharmony_ci return -ENOENT; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci switch (reg_num) { 17662306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(frequency): 17762306a36Sopenharmony_ci reg_val = riscv_timebase; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(time): 18062306a36Sopenharmony_ci reg_val = kvm_riscv_current_cycles(gt); 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(compare): 18362306a36Sopenharmony_ci reg_val = t->next_cycles; 18462306a36Sopenharmony_ci break; 18562306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(state): 18662306a36Sopenharmony_ci reg_val = (t->next_set) ? KVM_RISCV_TIMER_STATE_ON : 18762306a36Sopenharmony_ci KVM_RISCV_TIMER_STATE_OFF; 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci default: 19062306a36Sopenharmony_ci return -ENOENT; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) 19462306a36Sopenharmony_ci return -EFAULT; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ciint kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu, 20062306a36Sopenharmony_ci const struct kvm_one_reg *reg) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 20362306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 20462306a36Sopenharmony_ci u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; 20562306a36Sopenharmony_ci unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 20662306a36Sopenharmony_ci KVM_REG_SIZE_MASK | 20762306a36Sopenharmony_ci KVM_REG_RISCV_TIMER); 20862306a36Sopenharmony_ci u64 reg_val; 20962306a36Sopenharmony_ci int ret = 0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (KVM_REG_SIZE(reg->id) != sizeof(u64)) 21262306a36Sopenharmony_ci return -EINVAL; 21362306a36Sopenharmony_ci if (reg_num >= sizeof(struct kvm_riscv_timer) / sizeof(u64)) 21462306a36Sopenharmony_ci return -ENOENT; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) 21762306a36Sopenharmony_ci return -EFAULT; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci switch (reg_num) { 22062306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(frequency): 22162306a36Sopenharmony_ci if (reg_val != riscv_timebase) 22262306a36Sopenharmony_ci return -EINVAL; 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(time): 22562306a36Sopenharmony_ci gt->time_delta = reg_val - get_cycles64(); 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(compare): 22862306a36Sopenharmony_ci t->next_cycles = reg_val; 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci case KVM_REG_RISCV_TIMER_REG(state): 23162306a36Sopenharmony_ci if (reg_val == KVM_RISCV_TIMER_STATE_ON) 23262306a36Sopenharmony_ci ret = kvm_riscv_vcpu_timer_next_event(vcpu, reg_val); 23362306a36Sopenharmony_ci else 23462306a36Sopenharmony_ci ret = kvm_riscv_vcpu_timer_cancel(t); 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci default: 23762306a36Sopenharmony_ci ret = -ENOENT; 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return ret; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ciint kvm_riscv_vcpu_timer_init(struct kvm_vcpu *vcpu) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (t->init_done) 24962306a36Sopenharmony_ci return -EINVAL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci hrtimer_init(&t->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 25262306a36Sopenharmony_ci t->init_done = true; 25362306a36Sopenharmony_ci t->next_set = false; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Enable sstc for every vcpu if available in hardware */ 25662306a36Sopenharmony_ci if (riscv_isa_extension_available(NULL, SSTC)) { 25762306a36Sopenharmony_ci t->sstc_enabled = true; 25862306a36Sopenharmony_ci t->hrt.function = kvm_riscv_vcpu_vstimer_expired; 25962306a36Sopenharmony_ci t->timer_next_event = kvm_riscv_vcpu_update_vstimecmp; 26062306a36Sopenharmony_ci } else { 26162306a36Sopenharmony_ci t->sstc_enabled = false; 26262306a36Sopenharmony_ci t->hrt.function = kvm_riscv_vcpu_hrtimer_expired; 26362306a36Sopenharmony_ci t->timer_next_event = kvm_riscv_vcpu_update_hrtimer; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciint kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci int ret; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ret = kvm_riscv_vcpu_timer_cancel(&vcpu->arch.timer); 27462306a36Sopenharmony_ci vcpu->arch.timer.init_done = false; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return ret; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciint kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci t->next_cycles = -1ULL; 28462306a36Sopenharmony_ci return kvm_riscv_vcpu_timer_cancel(&vcpu->arch.timer); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void kvm_riscv_vcpu_update_timedelta(struct kvm_vcpu *vcpu) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci#if defined(CONFIG_32BIT) 29262306a36Sopenharmony_ci csr_write(CSR_HTIMEDELTA, (u32)(gt->time_delta)); 29362306a36Sopenharmony_ci csr_write(CSR_HTIMEDELTAH, (u32)(gt->time_delta >> 32)); 29462306a36Sopenharmony_ci#else 29562306a36Sopenharmony_ci csr_write(CSR_HTIMEDELTA, gt->time_delta); 29662306a36Sopenharmony_ci#endif 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_civoid kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci kvm_riscv_vcpu_update_timedelta(vcpu); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!t->sstc_enabled) 30662306a36Sopenharmony_ci return; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci#if defined(CONFIG_32BIT) 30962306a36Sopenharmony_ci csr_write(CSR_VSTIMECMP, (u32)t->next_cycles); 31062306a36Sopenharmony_ci csr_write(CSR_VSTIMECMPH, (u32)(t->next_cycles >> 32)); 31162306a36Sopenharmony_ci#else 31262306a36Sopenharmony_ci csr_write(CSR_VSTIMECMP, t->next_cycles); 31362306a36Sopenharmony_ci#endif 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* timer should be enabled for the remaining operations */ 31662306a36Sopenharmony_ci if (unlikely(!t->init_done)) 31762306a36Sopenharmony_ci return; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci kvm_riscv_vcpu_timer_unblocking(vcpu); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_civoid kvm_riscv_vcpu_timer_sync(struct kvm_vcpu *vcpu) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!t->sstc_enabled) 32762306a36Sopenharmony_ci return; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#if defined(CONFIG_32BIT) 33062306a36Sopenharmony_ci t->next_cycles = csr_read(CSR_VSTIMECMP); 33162306a36Sopenharmony_ci t->next_cycles |= (u64)csr_read(CSR_VSTIMECMPH) << 32; 33262306a36Sopenharmony_ci#else 33362306a36Sopenharmony_ci t->next_cycles = csr_read(CSR_VSTIMECMP); 33462306a36Sopenharmony_ci#endif 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_civoid kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct kvm_vcpu_timer *t = &vcpu->arch.timer; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!t->sstc_enabled) 34262306a36Sopenharmony_ci return; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * The vstimecmp CSRs are saved by kvm_riscv_vcpu_timer_sync() 34662306a36Sopenharmony_ci * upon every VM exit so no need to save here. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* timer should be enabled for the remaining operations */ 35062306a36Sopenharmony_ci if (unlikely(!t->init_done)) 35162306a36Sopenharmony_ci return; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (kvm_vcpu_is_blocking(vcpu)) 35462306a36Sopenharmony_ci kvm_riscv_vcpu_timer_blocking(vcpu); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_civoid kvm_riscv_guest_timer_init(struct kvm *kvm) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct kvm_guest_timer *gt = &kvm->arch.timer; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci riscv_cs_get_mult_shift(>->nsec_mult, >->nsec_shift); 36262306a36Sopenharmony_ci gt->time_delta = -get_cycles64(); 36362306a36Sopenharmony_ci} 364