OSDN Git Service

KVM: arm64: GICv4.1: Plumb SGI implementation selection in the distributor
authorMarc Zyngier <maz@kernel.org>
Wed, 4 Mar 2020 20:33:27 +0000 (20:33 +0000)
committerMarc Zyngier <maz@kernel.org>
Tue, 24 Mar 2020 12:15:51 +0000 (12:15 +0000)
The GICv4.1 architecture gives the hypervisor the option to let
the guest choose whether it wants the good old SGIs with an
active state, or the new, HW-based ones that do not have one.

For this, plumb the configuration of SGIs into the GICv3 MMIO
handling, present the GICD_TYPER2.nASSGIcap to the guest,
and handle the GICD_CTLR.nASSGIreq setting.

In order to be able to deal with the restore of a guest, also
apply the GICD_CTLR.nASSGIreq setting at first run so that we
can move the restored SGIs to the HW if that's what the guest
had selected in a previous life.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Zenghui Yu <yuzenghui@huawei.com>
Link: https://lore.kernel.org/r/20200304203330.4967-21-maz@kernel.org
virt/kvm/arm/vgic/vgic-mmio-v3.c
virt/kvm/arm/vgic/vgic-v3.c

index f4da9d1..905032a 100644 (file)
@@ -3,6 +3,7 @@
  * VGICv3 MMIO handling functions
  */
 
+#include <linux/bitfield.h>
 #include <linux/irqchip/arm-gic-v3.h>
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
@@ -70,6 +71,8 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
                if (vgic->enabled)
                        value |= GICD_CTLR_ENABLE_SS_G1;
                value |= GICD_CTLR_ARE_NS | GICD_CTLR_DS;
+               if (vgic->nassgireq)
+                       value |= GICD_CTLR_nASSGIreq;
                break;
        case GICD_TYPER:
                value = vgic->nr_spis + VGIC_NR_PRIVATE_IRQS;
@@ -81,6 +84,10 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
                        value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
                }
                break;
+       case GICD_TYPER2:
+               if (kvm_vgic_global_state.has_gicv4_1)
+                       value = GICD_TYPER2_nASSGIcap;
+               break;
        case GICD_IIDR:
                value = (PRODUCT_ID_KVM << GICD_IIDR_PRODUCT_ID_SHIFT) |
                        (vgic->implementation_rev << GICD_IIDR_REVISION_SHIFT) |
@@ -98,17 +105,43 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu,
                                    unsigned long val)
 {
        struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-       bool was_enabled = dist->enabled;
 
        switch (addr & 0x0c) {
-       case GICD_CTLR:
+       case GICD_CTLR: {
+               bool was_enabled, is_hwsgi;
+
+               mutex_lock(&vcpu->kvm->lock);
+
+               was_enabled = dist->enabled;
+               is_hwsgi = dist->nassgireq;
+
                dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
 
+               /* Not a GICv4.1? No HW SGIs */
+               if (!kvm_vgic_global_state.has_gicv4_1)
+                       val &= ~GICD_CTLR_nASSGIreq;
+
+               /* Dist stays enabled? nASSGIreq is RO */
+               if (was_enabled && dist->enabled) {
+                       val &= ~GICD_CTLR_nASSGIreq;
+                       val |= FIELD_PREP(GICD_CTLR_nASSGIreq, is_hwsgi);
+               }
+
+               /* Switching HW SGIs? */
+               dist->nassgireq = val & GICD_CTLR_nASSGIreq;
+               if (is_hwsgi != dist->nassgireq)
+                       vgic_v4_configure_vsgis(vcpu->kvm);
+
                if (!was_enabled && dist->enabled)
                        vgic_kick_vcpus(vcpu->kvm);
+
+               mutex_unlock(&vcpu->kvm->lock);
                break;
+       }
        case GICD_TYPER:
+       case GICD_TYPER2:
        case GICD_IIDR:
+               /* This is at best for documentation purposes... */
                return;
        }
 }
@@ -117,10 +150,22 @@ static int vgic_mmio_uaccess_write_v3_misc(struct kvm_vcpu *vcpu,
                                           gpa_t addr, unsigned int len,
                                           unsigned long val)
 {
+       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
        switch (addr & 0x0c) {
+       case GICD_TYPER2:
        case GICD_IIDR:
                if (val != vgic_mmio_read_v3_misc(vcpu, addr, len))
                        return -EINVAL;
+               return 0;
+       case GICD_CTLR:
+               /* Not a GICv4.1? No HW SGIs */
+               if (!kvm_vgic_global_state.has_gicv4_1)
+                       val &= ~GICD_CTLR_nASSGIreq;
+
+               dist->enabled = val & GICD_CTLR_ENABLE_SS_G1;
+               dist->nassgireq = val & GICD_CTLR_nASSGIreq;
+               return 0;
        }
 
        vgic_mmio_write_v3_misc(vcpu, addr, len, val);
index 1bc09b5..2c9fc13 100644 (file)
@@ -540,6 +540,8 @@ int vgic_v3_map_resources(struct kvm *kvm)
                goto out;
        }
 
+       if (kvm_vgic_global_state.has_gicv4_1)
+               vgic_v4_configure_vsgis(kvm);
        dist->ready = true;
 
 out: