As a general rule, GICv5 works a bit differently to previous generation GICs. When it comes to virtual interrupts, as much as possible is handled directly by the hardware and requires minimal software interaction. So far, the GICv5 support has been limited to PPIs. These are handled via a set of ICH_PPI_*_EL2 registers, which are used by the hypervisor to manage the PPI state exposed to the guest. They effectively take the role of the ICH_LR*_EL2 registers found in earlier GICs, but do so for EVERY PPI in parallel. For this reason, the GICv5 PPI support doesn't use AP lists at all - all PPI state is always presented to the guest. The lifecycle of a virtual SPI is largely handled by the hardware with GICv5. GICv5 itself provides a set of system instructions that act upon the virtual domain. One of these, GIC VDPEND, can be used to make a specified interrupt pending for a guest. The state of guest interrupts is tracked by ISTs, which are allocated by the hypervisor and provided directly by the hardware. The enable state for SPIs and LPIs is driven directly by the guest (using the GIC CDEN/CDDIS system instructions). Priority, affinity are also driven by the guest. All of the above means that it is in theory possible to handle virtual SPIs from KVM by just executing GIC VDPEND whenever new state is to be injected into the guest. Of course, reality is a little bit more complicated. KVM itself provides an interface to register a notifier on interrupt deactivation - specifically intended for use with SPIs on Arm-based systems. This notifier requires KVM to track when an interrupt has been consumed by the guest, so that the notifier can be called. SPIs are not per-vcpu - they are effectively global to the VM (even if they are affine to a specific VCPU, KVM doesn't need to know this information). Therefore, this change introduces a per-VM AP list specifically for tracking SPIs for a GICv5 guest. The intent is that while an SPI is in-flight (pending/active) it remains on this list, such that KVM knows to track the state of said SPI. Once the interrupt has been consumed by the guest, it can be popped off the list. Signed-off-by: Sascha Bischoff --- arch/arm64/kvm/vgic/vgic-irs-v5.c | 3 +++ include/kvm/arm_vgic.h | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/arm64/kvm/vgic/vgic-irs-v5.c b/arch/arm64/kvm/vgic/vgic-irs-v5.c index 729a3a3aca3a3..8e69b624194d5 100644 --- a/arch/arm64/kvm/vgic/vgic-irs-v5.c +++ b/arch/arm64/kvm/vgic/vgic-irs-v5.c @@ -685,6 +685,9 @@ int kvm_vgic_v5_irs_init(struct kvm *kvm, unsigned int nr_spis) int ret; int i; + INIT_LIST_HEAD(&dist->vgic_v5_spi_ap_list_head); + raw_spin_lock_init(&dist->vgic_v5_spi_ap_list_lock); + /* * We (KVM) allocate an Interrupt State Table (IST) for SPIs. The * hardware mandates that lower 6 bits of the address are 0. Each ISTE diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 3a2dfbd5210f2..812ad325b01be 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -544,6 +544,20 @@ struct vgic_dist { * GICv5 IRS data. Dynamically allocated due to the size. */ struct vgic_v5_irs *vgic_v5_irs_data; + + /* + * The GICv5 SPI AP list is global to the VM. This spinlock ensures that + * we don't do anything untoward! + */ + raw_spinlock_t vgic_v5_spi_ap_list_lock; + + /* + * List of global (non-private) IRQs that must be tracked because they + * are either Active or Pending (hence the name; AP list). This list + * will only ever contain SPIs or LPIs. All private IRQs must go into a + * specific vcpu's AP list. + */ + struct list_head vgic_v5_spi_ap_list_head; }; struct vgic_v2_cpu_if { -- 2.34.1