KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
authorEric Auger <eric.auger@linaro.org>
Mon, 21 Dec 2015 15:33:22 +0000 (16:33 +0100)
committerChristoffer Dall <christoffer.dall@linaro.org>
Fri, 20 May 2016 13:40:00 +0000 (15:40 +0200)
This patch implements the KVM_DEV_ARM_VGIC_GRP_NR_IRQS group. This
modality is supported by both VGIC V2 and V3 KVM device as will be
other groups, hence the introduction of common helpers.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
virt/kvm/arm/vgic/vgic-kvm-device.c

index ff332f3..05ff925 100644 (file)
  */
 #include <linux/kvm_host.h>
 #include <kvm/arm_vgic.h>
+#include <linux/uaccess.h>
+#include "vgic.h"
 
 /* common helpers */
 
+static int vgic_set_common_attr(struct kvm_device *dev,
+                               struct kvm_device_attr *attr)
+{
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+               u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+               u32 val;
+               int ret = 0;
+
+               if (get_user(val, uaddr))
+                       return -EFAULT;
+
+               /*
+                * We require:
+                * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
+                * - at most 1024 interrupts
+                * - a multiple of 32 interrupts
+                */
+               if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
+                   val > VGIC_MAX_RESERVED ||
+                   (val & 31))
+                       return -EINVAL;
+
+               mutex_lock(&dev->kvm->lock);
+
+               if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
+                       ret = -EBUSY;
+               else
+                       dev->kvm->arch.vgic.nr_spis =
+                               val - VGIC_NR_PRIVATE_IRQS;
+
+               mutex_unlock(&dev->kvm->lock);
+
+               return ret;
+       }
+       }
+
+       return -ENXIO;
+}
+
+static int vgic_get_common_attr(struct kvm_device *dev,
+                               struct kvm_device_attr *attr)
+{
+       int r = -ENXIO;
+
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
+               u32 __user *uaddr = (u32 __user *)(long)attr->addr;
+
+               r = put_user(dev->kvm->arch.vgic.nr_spis +
+                            VGIC_NR_PRIVATE_IRQS, uaddr);
+               break;
+       }
+       }
+
+       return r;
+}
+
 static int vgic_create(struct kvm_device *dev, u32 type)
 {
        return kvm_vgic_create(dev->kvm, type);
@@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type)
 static int vgic_v2_set_attr(struct kvm_device *dev,
                            struct kvm_device_attr *attr)
 {
-       return -ENXIO;
+       int ret;
+
+       ret = vgic_set_common_attr(dev, attr);
+       return ret;
+
 }
 
 static int vgic_v2_get_attr(struct kvm_device *dev,
                            struct kvm_device_attr *attr)
 {
-       return -ENXIO;
+       int ret;
+
+       ret = vgic_get_common_attr(dev, attr);
+       return ret;
 }
 
 static int vgic_v2_has_attr(struct kvm_device *dev,
                            struct kvm_device_attr *attr)
 {
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+               return 0;
+       }
        return -ENXIO;
 }
 
@@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
 static int vgic_v3_set_attr(struct kvm_device *dev,
                            struct kvm_device_attr *attr)
 {
-       return -ENXIO;
+       return vgic_set_common_attr(dev, attr);
 }
 
 static int vgic_v3_get_attr(struct kvm_device *dev,
                            struct kvm_device_attr *attr)
 {
-       return -ENXIO;
+       return vgic_get_common_attr(dev, attr);
 }
 
 static int vgic_v3_has_attr(struct kvm_device *dev,
                            struct kvm_device_attr *attr)
 {
+       switch (attr->group) {
+       case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
+               return 0;
+       }
        return -ENXIO;
 }