diff options
author | Eric Auger <eric.auger@linaro.org> | 2015-12-21 10:33:22 -0500 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2016-05-20 09:40:00 -0400 |
commit | fca256026bb0d78991f975a7d4a3f601b7234401 (patch) | |
tree | b847f2667ca0718a0e8e1071562a60939eb67c1c /virt | |
parent | c86c772191d7e65f873e6908e9604b31168936cd (diff) |
KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
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>
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/arm/vgic/vgic-kvm-device.c | 83 |
1 files changed, 79 insertions, 4 deletions
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c index ff332f34a221..05ff925f5377 100644 --- a/virt/kvm/arm/vgic/vgic-kvm-device.c +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c | |||
@@ -15,9 +15,69 @@ | |||
15 | */ | 15 | */ |
16 | #include <linux/kvm_host.h> | 16 | #include <linux/kvm_host.h> |
17 | #include <kvm/arm_vgic.h> | 17 | #include <kvm/arm_vgic.h> |
18 | #include <linux/uaccess.h> | ||
19 | #include "vgic.h" | ||
18 | 20 | ||
19 | /* common helpers */ | 21 | /* common helpers */ |
20 | 22 | ||
23 | static int vgic_set_common_attr(struct kvm_device *dev, | ||
24 | struct kvm_device_attr *attr) | ||
25 | { | ||
26 | switch (attr->group) { | ||
27 | case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { | ||
28 | u32 __user *uaddr = (u32 __user *)(long)attr->addr; | ||
29 | u32 val; | ||
30 | int ret = 0; | ||
31 | |||
32 | if (get_user(val, uaddr)) | ||
33 | return -EFAULT; | ||
34 | |||
35 | /* | ||
36 | * We require: | ||
37 | * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs | ||
38 | * - at most 1024 interrupts | ||
39 | * - a multiple of 32 interrupts | ||
40 | */ | ||
41 | if (val < (VGIC_NR_PRIVATE_IRQS + 32) || | ||
42 | val > VGIC_MAX_RESERVED || | ||
43 | (val & 31)) | ||
44 | return -EINVAL; | ||
45 | |||
46 | mutex_lock(&dev->kvm->lock); | ||
47 | |||
48 | if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis) | ||
49 | ret = -EBUSY; | ||
50 | else | ||
51 | dev->kvm->arch.vgic.nr_spis = | ||
52 | val - VGIC_NR_PRIVATE_IRQS; | ||
53 | |||
54 | mutex_unlock(&dev->kvm->lock); | ||
55 | |||
56 | return ret; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | return -ENXIO; | ||
61 | } | ||
62 | |||
63 | static int vgic_get_common_attr(struct kvm_device *dev, | ||
64 | struct kvm_device_attr *attr) | ||
65 | { | ||
66 | int r = -ENXIO; | ||
67 | |||
68 | switch (attr->group) { | ||
69 | case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { | ||
70 | u32 __user *uaddr = (u32 __user *)(long)attr->addr; | ||
71 | |||
72 | r = put_user(dev->kvm->arch.vgic.nr_spis + | ||
73 | VGIC_NR_PRIVATE_IRQS, uaddr); | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | return r; | ||
79 | } | ||
80 | |||
21 | static int vgic_create(struct kvm_device *dev, u32 type) | 81 | static int vgic_create(struct kvm_device *dev, u32 type) |
22 | { | 82 | { |
23 | return kvm_vgic_create(dev->kvm, type); | 83 | return kvm_vgic_create(dev->kvm, type); |
@@ -49,18 +109,29 @@ void kvm_register_vgic_device(unsigned long type) | |||
49 | static int vgic_v2_set_attr(struct kvm_device *dev, | 109 | static int vgic_v2_set_attr(struct kvm_device *dev, |
50 | struct kvm_device_attr *attr) | 110 | struct kvm_device_attr *attr) |
51 | { | 111 | { |
52 | return -ENXIO; | 112 | int ret; |
113 | |||
114 | ret = vgic_set_common_attr(dev, attr); | ||
115 | return ret; | ||
116 | |||
53 | } | 117 | } |
54 | 118 | ||
55 | static int vgic_v2_get_attr(struct kvm_device *dev, | 119 | static int vgic_v2_get_attr(struct kvm_device *dev, |
56 | struct kvm_device_attr *attr) | 120 | struct kvm_device_attr *attr) |
57 | { | 121 | { |
58 | return -ENXIO; | 122 | int ret; |
123 | |||
124 | ret = vgic_get_common_attr(dev, attr); | ||
125 | return ret; | ||
59 | } | 126 | } |
60 | 127 | ||
61 | static int vgic_v2_has_attr(struct kvm_device *dev, | 128 | static int vgic_v2_has_attr(struct kvm_device *dev, |
62 | struct kvm_device_attr *attr) | 129 | struct kvm_device_attr *attr) |
63 | { | 130 | { |
131 | switch (attr->group) { | ||
132 | case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: | ||
133 | return 0; | ||
134 | } | ||
64 | return -ENXIO; | 135 | return -ENXIO; |
65 | } | 136 | } |
66 | 137 | ||
@@ -80,18 +151,22 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = { | |||
80 | static int vgic_v3_set_attr(struct kvm_device *dev, | 151 | static int vgic_v3_set_attr(struct kvm_device *dev, |
81 | struct kvm_device_attr *attr) | 152 | struct kvm_device_attr *attr) |
82 | { | 153 | { |
83 | return -ENXIO; | 154 | return vgic_set_common_attr(dev, attr); |
84 | } | 155 | } |
85 | 156 | ||
86 | static int vgic_v3_get_attr(struct kvm_device *dev, | 157 | static int vgic_v3_get_attr(struct kvm_device *dev, |
87 | struct kvm_device_attr *attr) | 158 | struct kvm_device_attr *attr) |
88 | { | 159 | { |
89 | return -ENXIO; | 160 | return vgic_get_common_attr(dev, attr); |
90 | } | 161 | } |
91 | 162 | ||
92 | static int vgic_v3_has_attr(struct kvm_device *dev, | 163 | static int vgic_v3_has_attr(struct kvm_device *dev, |
93 | struct kvm_device_attr *attr) | 164 | struct kvm_device_attr *attr) |
94 | { | 165 | { |
166 | switch (attr->group) { | ||
167 | case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: | ||
168 | return 0; | ||
169 | } | ||
95 | return -ENXIO; | 170 | return -ENXIO; |
96 | } | 171 | } |
97 | 172 | ||