KVM: arm/arm64: vgic-new: Add PENDING registers handlers
authorAndre Przywara <andre.przywara@arm.com>
Tue, 1 Dec 2015 14:33:41 +0000 (14:33 +0000)
committerChristoffer Dall <christoffer.dall@linaro.org>
Fri, 20 May 2016 13:39:52 +0000 (15:39 +0200)
The pending register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.
For level triggered interrupts the real line level is unaffected by
this write, so we keep this state separate and combine it with the
device's level to get the actual pending state.

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

index d5355b502f4ae461f9b5c9be16a08d1e5c2f134c..c13a7089bc9aff746c9c38b63054e7f89dfd730a 100644 (file)
@@ -78,10 +78,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
                vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
                VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_SET,
-               vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+               vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
                VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_PENDING_CLEAR,
-               vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+               vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
                VGIC_ACCESS_32bit),
        REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_ACTIVE_SET,
                vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
index 32ed8dbd93d6456bdd69c502ea706210508ca5f2..d8dc8f6480dd10a5935e0eeafb2794705bc29916 100644 (file)
@@ -95,6 +95,66 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
        }
 }
 
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+                                    gpa_t addr, unsigned int len)
+{
+       u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+       u32 value = 0;
+       int i;
+
+       /* Loop over all IRQs affected by this read */
+       for (i = 0; i < len * 8; i++) {
+               struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+               if (irq->pending)
+                       value |= (1U << i);
+       }
+
+       return value;
+}
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+                             gpa_t addr, unsigned int len,
+                             unsigned long val)
+{
+       u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+       int i;
+
+       for_each_set_bit(i, &val, len * 8) {
+               struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+               spin_lock(&irq->irq_lock);
+               irq->pending = true;
+               if (irq->config == VGIC_CONFIG_LEVEL)
+                       irq->soft_pending = true;
+
+               vgic_queue_irq_unlock(vcpu->kvm, irq);
+       }
+}
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+                             gpa_t addr, unsigned int len,
+                             unsigned long val)
+{
+       u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
+       int i;
+
+       for_each_set_bit(i, &val, len * 8) {
+               struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+
+               spin_lock(&irq->irq_lock);
+
+               if (irq->config == VGIC_CONFIG_LEVEL) {
+                       irq->soft_pending = false;
+                       irq->pending = irq->line_level;
+               } else {
+                       irq->pending = false;
+               }
+
+               spin_unlock(&irq->irq_lock);
+       }
+}
+
 static int match_region(const void *key, const void *elt)
 {
        const unsigned int offset = (unsigned long)key;
index 57e19fe8df554535299e09e7e75ed56d5a4b8827..97ee703a1bd6165555dbbceeb18d078b9b887f5a 100644 (file)
@@ -107,6 +107,18 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu,
                             gpa_t addr, unsigned int len,
                             unsigned long val);
 
+unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
+                                    gpa_t addr, unsigned int len);
+
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+                             gpa_t addr, unsigned int len,
+                             unsigned long val);
+
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+                             gpa_t addr, unsigned int len,
+                             unsigned long val);
+
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif