]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 26 Apr 2016 10:06:47 +0000 (11:06 +0100)
committerChristoffer Dall <christoffer.dall@linaro.org>
Fri, 20 May 2016 13:39:50 +0000 (15:39 +0200)
Those three registers are v2 emulation specific, so their implementation
lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
as their implementation is pretty simple.
When the guest enables the distributor, we kick all VCPUs to get
potentially pending interrupts serviced.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
include/linux/irqchip/arm-gic.h
virt/kvm/arm/vgic/vgic-mmio-v2.c
virt/kvm/arm/vgic/vgic.c
virt/kvm/arm/vgic/vgic.h

index be0d26f940af75c785a3f741a350d1589a5b0703..fd051855539b9ee2f871c1dbe9691af29bfb83d2 100644 (file)
@@ -33,6 +33,7 @@
 
 #define GIC_DIST_CTRL                  0x000
 #define GIC_DIST_CTR                   0x004
+#define GIC_DIST_IIDR                  0x008
 #define GIC_DIST_IGROUP                        0x080
 #define GIC_DIST_ENABLE_SET            0x100
 #define GIC_DIST_ENABLE_CLEAR          0x180
index a3e31a93a3fb3bdaa4537417b1d519c216b455a5..d812c933708a443effbaed8a1e0502d569ad9566 100644 (file)
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
+                                           gpa_t addr, unsigned int len)
+{
+       u32 value;
+
+       switch (addr & 0x0c) {
+       case GIC_DIST_CTRL:
+               value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
+               break;
+       case GIC_DIST_CTR:
+               value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+               value = (value >> 5) - 1;
+               value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
+               break;
+       case GIC_DIST_IIDR:
+               value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+               break;
+       default:
+               return 0;
+       }
+
+       return value;
+}
+
+static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
+                                   gpa_t addr, unsigned int len,
+                                   unsigned long val)
+{
+       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+       bool was_enabled = dist->enabled;
+
+       switch (addr & 0x0c) {
+       case GIC_DIST_CTRL:
+               dist->enabled = val & GICD_ENABLE;
+               if (!was_enabled && dist->enabled)
+                       vgic_kick_vcpus(vcpu->kvm);
+               break;
+       case GIC_DIST_CTR:
+       case GIC_DIST_IIDR:
+               /* Nothing to do */
+               return;
+       }
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
        REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
-               vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
+               vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
                VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
                vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
index 7e010087224c35d06c8394b23bfdfe3e772cebe1..12ae84b4931fb0061541b2e7d4f4eb993da6e82c 100644 (file)
@@ -545,3 +545,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
 
        return pending;
 }
+
+void vgic_kick_vcpus(struct kvm *kvm)
+{
+       struct kvm_vcpu *vcpu;
+       int c;
+
+       /*
+        * We've injected an interrupt, time to find out who deserves
+        * a good kick...
+        */
+       kvm_for_each_vcpu(c, vcpu, kvm) {
+               if (kvm_vgic_vcpu_pending_irq(vcpu))
+                       kvm_vcpu_kick(vcpu);
+       }
+}
index fd9acaa1e305c88f820037d52f5a8848638525af..cf620157e1e4aec6c86a68eb6778494aea07fc8e 100644 (file)
 #ifndef __KVM_ARM_VGIC_NEW_H__
 #define __KVM_ARM_VGIC_NEW_H__
 
+#define PRODUCT_ID_KVM         0x4b    /* ASCII code K */
+#define IMPLEMENTER_ARM                0x43b
+
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
                              u32 intid);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
+void vgic_kick_vcpus(struct kvm *kvm);
 
 void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
 void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);