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.

Signed-off-by: Marc Zyngier <[email protected]>
---
 virt/kvm/arm/vgic/vgic-mmio-v3.c | 48 ++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index d73f4ffd7d36..31ff8c7e09b0 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -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 (kvm_vgic_global_state.has_gicv4_1 && 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,21 @@ 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_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);
-- 
2.20.1

_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to