Patch "RISCV: KVM: update external interrupt atomically for IMSIC swfile" has been added to the 6.6-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    RISCV: KVM: update external interrupt atomically for IMSIC swfile

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     riscv-kvm-update-external-interrupt-atomically-for-i.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit f93d15794db13e526a5e9d1b23ad81bd7dcb2c4e
Author: Yong-Xuan Wang <yongxuan.wang@xxxxxxxxxx>
Date:   Wed Dec 13 06:16:09 2023 +0000

    RISCV: KVM: update external interrupt atomically for IMSIC swfile
    
    [ Upstream commit 4ad9843e1ea088bd2529290234c6c4c6374836a7 ]
    
    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.
    
    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.
    
    Fixes: db8b7e97d613 ("RISC-V: KVM: Add in-kernel virtualization of AIA IMSIC")
    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>
    Signed-off-by: Anup Patel <anup@xxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 6cf23b8adb712..e808723a85f1b 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -55,6 +55,7 @@ struct imsic {
 	/* IMSIC SW-file */
 	struct imsic_mrif *swfile;
 	phys_addr_t swfile_pa;
+	spinlock_t swfile_extirq_lock;
 };
 
 #define imsic_vs_csr_read(__c)			\
@@ -613,12 +614,23 @@ 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;
+
+	/*
+	 * The critical section is necessary during external interrupt
+	 * updates to avoid the risk of losing interrupts due to potential
+	 * interruptions between reading topei and updating pending status.
+	 */
+
+	spin_lock_irqsave(&imsic->swfile_extirq_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->swfile_extirq_lock, flags);
 }
 
 static void imsic_swfile_read(struct kvm_vcpu *vcpu, bool clear,
@@ -1039,6 +1051,7 @@ int kvm_riscv_vcpu_aia_imsic_init(struct kvm_vcpu *vcpu)
 	}
 	imsic->swfile = page_to_virt(swfile_page);
 	imsic->swfile_pa = page_to_phys(swfile_page);
+	spin_lock_init(&imsic->swfile_extirq_lock);
 
 	/* Setup IO device */
 	kvm_iodevice_init(&imsic->iodev, &imsic_iodoev_ops);




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux