Currently, we sync-up Guest VSIP and VSIE CSRs with HW state upon VM-exit. This helps us track enable/disable state of interrupts and VSIP.SSIP bit updates by Guest. Unfortunately, the implementation of kvm_riscv_vcpu_sync_interrupts() is racey when running SMP Guest on SMP Host because it can happen that IRQ_S_SOFT is already queued from other Host CPU and we might accidentally clear a valid pending IRQ_S_SOFT. To fix this, we use test_and_set_bit() to update irqs_pending_mask in kvm_riscv_vcpu_sync_interrupts() instead of directly calling kvm_riscv_vcpu_set/unset_interrupt() functions. Signed-off-by: Anup Patel <anup.patel@xxxxxxx> --- arch/riscv/kvm/vcpu.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index f1a218d3a8cf..844542dd13e4 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -662,15 +662,22 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) { - vcpu->arch.guest_csr.vsip = csr_read(CSR_VSIP); - vcpu->arch.guest_csr.vsie = csr_read(CSR_VSIE); + unsigned long vsip; + struct kvm_vcpu_arch *v = &vcpu->arch; + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; - /* Guest can directly update VSIP software interrupt bits */ - if (vcpu->arch.guest_csr.vsip ^ READ_ONCE(vcpu->arch.irqs_pending)) { - if (vcpu->arch.guest_csr.vsip & (1UL << IRQ_S_SOFT)) - kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_S_SOFT); - else - kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_S_SOFT); + /* Read current VSIP and VSIE CSRs */ + vsip = csr_read(CSR_VSIP); + csr->vsie = csr_read(CSR_VSIE); + + /* Sync-up VSIP.SSIP bit changes does by Guest */ + if ((csr->vsip ^ vsip) & (1UL << IRQ_S_SOFT)) { + if (!test_and_set_bit(IRQ_S_SOFT, &v->irqs_pending_mask)) { + if (vsip & (1UL << IRQ_S_SOFT)) + set_bit(IRQ_S_SOFT, &v->irqs_pending); + else + clear_bit(IRQ_S_SOFT, &v->irqs_pending); + } } } -- 2.17.1