On Tue, Dec 12, 2023 at 11:05 AM Yong-Xuan Wang <yongxuan.wang@xxxxxxxxxx> wrote: > > The emulated IMSIC update the external interrupt pending depending on the > value of eidelivery and topei. It might lose an interrupt when it is > interrupted before setting the new value to the pending status. More simpler PATCH subject can be: "RISCV: KVM: update external interrupt atomically for IMSIC swfile" > > For example, when VCPU0 sends an IPI to VCPU1 via IMSIC: > > VCPU0 VCPU1 > > CSRSWAP topei = 0 > The VCPU1 has claimed all the external > interrupt in its interrupt handler. > > topei of VCPU1's IMSIC = 0 > > set pending in VCPU1's IMSIC > > topei of VCPU1' IMSIC = 1 > > set the external interrupt > pending of VCPU1 > > clear the external interrupt pending > of VCPU1 > > When the VCPU1 switches back to VS mode, it exits the interrupt handler > because the result of CSRSWAP topei is 0. If there are no other external > interrupts injected into the VCPU1's IMSIC, VCPU1 will never know this > pending interrupt unless it initiative read the topei. > > If the interruption occurs between updating interrupt pending in IMSIC > and updating external interrupt pending of VCPU, it will not cause a > problem. Suppose that the VCPU1 clears the IPI pending in IMSIC right > after VCPU0 sets the pending, the external interrupt pending of VCPU1 > will not be set because the topei is 0. But when the VCPU1 goes back to > VS mode, the pending IPI will be reported by the CSRSWAP topei, it will > not lose this interrupt. > > So we only need to make the external interrupt updating procedure as a > critical section to avoid the problem. > Please add a "Fixes:" line here > Tested-by: Roy Lin <roy.lin@xxxxxxxxxx> > Tested-by: Wayling Chen <wayling.chen@xxxxxxxxxx> > Co-developed-by: Vincent Chen <vincent.chen@xxxxxxxxxx> > Signed-off-by: Vincent Chen <vincent.chen@xxxxxxxxxx> > Signed-off-by: Yong-Xuan Wang <yongxuan.wang@xxxxxxxxxx> > --- > arch/riscv/kvm/aia_imsic.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c > index 6cf23b8adb71..0278aa0ca16a 100644 > --- a/arch/riscv/kvm/aia_imsic.c > +++ b/arch/riscv/kvm/aia_imsic.c > @@ -37,6 +37,8 @@ struct imsic { > u32 nr_eix; > u32 nr_hw_eix; > > + spinlock_t extirq_update_lock; > + Please rename this lock to "swfile_extirq_lock". > /* > * At any point in time, the register state is in > * one of the following places: > @@ -613,12 +615,17 @@ static void imsic_swfile_extirq_update(struct kvm_vcpu *vcpu) > { > struct imsic *imsic = vcpu->arch.aia_context.imsic_state; > struct imsic_mrif *mrif = imsic->swfile; > + unsigned long flags; > + Add a short summary in a comment block about why external interrupt updates are required to be in the critical section. > + spin_lock_irqsave(&imsic->extirq_update_lock, flags); > > if (imsic_mrif_atomic_read(mrif, &mrif->eidelivery) && > imsic_mrif_topei(mrif, imsic->nr_eix, imsic->nr_msis)) > kvm_riscv_vcpu_set_interrupt(vcpu, IRQ_VS_EXT); > else > kvm_riscv_vcpu_unset_interrupt(vcpu, IRQ_VS_EXT); > + > + spin_unlock_irqrestore(&imsic->extirq_update_lock, flags); > } > > static void imsic_swfile_read(struct kvm_vcpu *vcpu, bool clear, > @@ -1029,6 +1036,7 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu) > imsic->nr_eix = BITS_TO_U64(imsic->nr_msis); > imsic->nr_hw_eix = BITS_TO_U64(kvm_riscv_aia_max_ids); > imsic->vsfile_hgei = imsic->vsfile_cpu = -1; > + spin_lock_init(&imsic->extirq_update_lock); > > /* Setup IMSIC SW-file */ > swfile_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, > -- > 2.17.1 > > Regards, Anup