KVM: arm/arm64: Introduce an allocator for in-kernel irq lines
authorChristoffer Dall <cdall@linaro.org>
Thu, 4 May 2017 11:24:20 +0000 (13:24 +0200)
committerChristoffer Dall <cdall@linaro.org>
Thu, 8 Jun 2017 14:59:57 +0000 (16:59 +0200)
Having multiple devices being able to signal the same interrupt line is
very confusing and almost certainly guarantees a configuration error.

Therefore, introduce a very simple allocator which allows a device to
claim an interrupt line from the vgic for a given VM.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
include/kvm/arm_vgic.h
virt/kvm/arm/vgic/vgic.c

index dde59fbc5f8017f9ac6383e4cbc429e4105044b3..5d5b34534ce93f4ee4708de900fca1b4255660af 100644 (file)
@@ -121,6 +121,9 @@ struct vgic_irq {
        u8 source;                      /* GICv2 SGIs only */
        u8 priority;
        enum vgic_irq_config config;    /* Level or edge */
+
+       void *owner;                    /* Opaque pointer to reserve an interrupt
+                                          for in-kernel devices. */
 };
 
 struct vgic_register_region;
@@ -340,4 +343,6 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
  */
 int kvm_vgic_setup_default_irq_routing(struct kvm *kvm);
 
+int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner);
+
 #endif /* __KVM_ARM_VGIC_H */
index c66feaca2a5d905ef29e0e72ecf9991636ce6b49..9628945234e46aac045c00fcd0b2531a106760c8 100644 (file)
@@ -434,6 +434,39 @@ int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
        return 0;
 }
 
+/**
+ * kvm_vgic_set_owner - Set the owner of an interrupt for a VM
+ *
+ * @vcpu:   Pointer to the VCPU (used for PPIs)
+ * @intid:  The virtual INTID identifying the interrupt (PPI or SPI)
+ * @owner:  Opaque pointer to the owner
+ *
+ * Returns 0 if intid is not already used by another in-kernel device and the
+ * owner is set, otherwise returns an error code.
+ */
+int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner)
+{
+       struct vgic_irq *irq;
+       int ret = 0;
+
+       if (!vgic_initialized(vcpu->kvm))
+               return -EAGAIN;
+
+       /* SGIs and LPIs cannot be wired up to any device */
+       if (!irq_is_ppi(intid) && !vgic_valid_spi(vcpu->kvm, intid))
+               return -EINVAL;
+
+       irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
+       spin_lock(&irq->irq_lock);
+       if (irq->owner && irq->owner != owner)
+               ret = -EEXIST;
+       else
+               irq->owner = owner;
+       spin_unlock(&irq->irq_lock);
+
+       return ret;
+}
+
 /**
  * vgic_prune_ap_list - Remove non-relevant interrupts from the list
  *