Commit cea8896b authored by Anup Patel's avatar Anup Patel Committed by Anup Patel
Browse files

RISC-V: KVM: Fix kvm_riscv_vcpu_timer_pending() for Sstc



The kvm_riscv_vcpu_timer_pending() checks per-VCPU next_cycles
and per-VCPU software injected VS timer interrupt. This function
returns incorrect value when Sstc is available because the per-VCPU
next_cycles are only updated by kvm_riscv_vcpu_timer_save() called
from kvm_arch_vcpu_put(). As a result, when Sstc is available the
VCPU does not block properly upon WFI traps.

To fix the above issue, we introduce kvm_riscv_vcpu_timer_sync()
which will update per-VCPU next_cycles upon every VM exit instead
of kvm_riscv_vcpu_timer_save().

Fixes: 8f5cb44b ("RISC-V: KVM: Support sstc extension")
Signed-off-by: default avatarAnup Patel <apatel@ventanamicro.com>
Reviewed-by: default avatarAtish Patra <atishp@rivosinc.com>
Signed-off-by: default avatarAnup Patel <anup@brainfault.org>
parent 5c20a3a9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ int kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu);
int kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu);
void kvm_riscv_guest_timer_init(struct kvm *kvm);
void kvm_riscv_vcpu_timer_sync(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu);
bool kvm_riscv_vcpu_timer_pending(struct kvm_vcpu *vcpu);

+3 −0
Original line number Diff line number Diff line
@@ -708,6 +708,9 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
				clear_bit(IRQ_VS_SOFT, &v->irqs_pending);
		}
	}

	/* Sync-up timer CSRs */
	kvm_riscv_vcpu_timer_sync(vcpu);
}

int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+15 −2
Original line number Diff line number Diff line
@@ -320,20 +320,33 @@ void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu)
	kvm_riscv_vcpu_timer_unblocking(vcpu);
}

void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu)
void kvm_riscv_vcpu_timer_sync(struct kvm_vcpu *vcpu)
{
	struct kvm_vcpu_timer *t = &vcpu->arch.timer;

	if (!t->sstc_enabled)
		return;

	t = &vcpu->arch.timer;
#if defined(CONFIG_32BIT)
	t->next_cycles = csr_read(CSR_VSTIMECMP);
	t->next_cycles |= (u64)csr_read(CSR_VSTIMECMPH) << 32;
#else
	t->next_cycles = csr_read(CSR_VSTIMECMP);
#endif
}

void kvm_riscv_vcpu_timer_save(struct kvm_vcpu *vcpu)
{
	struct kvm_vcpu_timer *t = &vcpu->arch.timer;

	if (!t->sstc_enabled)
		return;

	/*
	 * The vstimecmp CSRs are saved by kvm_riscv_vcpu_timer_sync()
	 * upon every VM exit so no need to save here.
	 */

	/* timer should be enabled for the remaining operations */
	if (unlikely(!t->init_done))
		return;