aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/arm/vgic/vgic-its.c
diff options
context:
space:
mode:
Diffstat (limited to 'virt/kvm/arm/vgic/vgic-its.c')
-rw-r--r--virt/kvm/arm/vgic/vgic-its.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 4654d6edf6a6..6b47b3674690 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -21,6 +21,7 @@
21#include <linux/kvm.h> 21#include <linux/kvm.h>
22#include <linux/kvm_host.h> 22#include <linux/kvm_host.h>
23#include <linux/interrupt.h> 23#include <linux/interrupt.h>
24#include <linux/uaccess.h>
24 25
25#include <linux/irqchip/arm-gic-v3.h> 26#include <linux/irqchip/arm-gic-v3.h>
26 27
@@ -84,6 +85,9 @@ static int vgic_its_init_its(struct kvm *kvm, struct vgic_its *its)
84 struct vgic_io_device *iodev = &its->iodev; 85 struct vgic_io_device *iodev = &its->iodev;
85 int ret; 86 int ret;
86 87
88 if (its->initialized)
89 return 0;
90
87 if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) 91 if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base))
88 return -ENXIO; 92 return -ENXIO;
89 93
@@ -99,5 +103,136 @@ static int vgic_its_init_its(struct kvm *kvm, struct vgic_its *its)
99 KVM_VGIC_V3_ITS_SIZE, &iodev->dev); 103 KVM_VGIC_V3_ITS_SIZE, &iodev->dev);
100 mutex_unlock(&kvm->slots_lock); 104 mutex_unlock(&kvm->slots_lock);
101 105
106 if (!ret)
107 its->initialized = true;
108
102 return ret; 109 return ret;
103} 110}
111
112static int vgic_its_create(struct kvm_device *dev, u32 type)
113{
114 struct vgic_its *its;
115
116 if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
117 return -ENODEV;
118
119 its = kzalloc(sizeof(struct vgic_its), GFP_KERNEL);
120 if (!its)
121 return -ENOMEM;
122
123 its->vgic_its_base = VGIC_ADDR_UNDEF;
124
125 dev->kvm->arch.vgic.has_its = true;
126 its->initialized = false;
127 its->enabled = false;
128
129 dev->private = its;
130
131 return 0;
132}
133
134static void vgic_its_destroy(struct kvm_device *kvm_dev)
135{
136 struct vgic_its *its = kvm_dev->private;
137
138 kfree(its);
139}
140
141static int vgic_its_has_attr(struct kvm_device *dev,
142 struct kvm_device_attr *attr)
143{
144 switch (attr->group) {
145 case KVM_DEV_ARM_VGIC_GRP_ADDR:
146 switch (attr->attr) {
147 case KVM_VGIC_ITS_ADDR_TYPE:
148 return 0;
149 }
150 break;
151 case KVM_DEV_ARM_VGIC_GRP_CTRL:
152 switch (attr->attr) {
153 case KVM_DEV_ARM_VGIC_CTRL_INIT:
154 return 0;
155 }
156 break;
157 }
158 return -ENXIO;
159}
160
161static int vgic_its_set_attr(struct kvm_device *dev,
162 struct kvm_device_attr *attr)
163{
164 struct vgic_its *its = dev->private;
165 int ret;
166
167 switch (attr->group) {
168 case KVM_DEV_ARM_VGIC_GRP_ADDR: {
169 u64 __user *uaddr = (u64 __user *)(long)attr->addr;
170 unsigned long type = (unsigned long)attr->attr;
171 u64 addr;
172
173 if (type != KVM_VGIC_ITS_ADDR_TYPE)
174 return -ENODEV;
175
176 if (its->initialized)
177 return -EBUSY;
178
179 if (copy_from_user(&addr, uaddr, sizeof(addr)))
180 return -EFAULT;
181
182 ret = vgic_check_ioaddr(dev->kvm, &its->vgic_its_base,
183 addr, SZ_64K);
184 if (ret)
185 return ret;
186
187 its->vgic_its_base = addr;
188
189 return 0;
190 }
191 case KVM_DEV_ARM_VGIC_GRP_CTRL:
192 switch (attr->attr) {
193 case KVM_DEV_ARM_VGIC_CTRL_INIT:
194 return vgic_its_init_its(dev->kvm, its);
195 }
196 break;
197 }
198 return -ENXIO;
199}
200
201static int vgic_its_get_attr(struct kvm_device *dev,
202 struct kvm_device_attr *attr)
203{
204 switch (attr->group) {
205 case KVM_DEV_ARM_VGIC_GRP_ADDR: {
206 struct vgic_its *its = dev->private;
207 u64 addr = its->vgic_its_base;
208 u64 __user *uaddr = (u64 __user *)(long)attr->addr;
209 unsigned long type = (unsigned long)attr->attr;
210
211 if (type != KVM_VGIC_ITS_ADDR_TYPE)
212 return -ENODEV;
213
214 if (copy_to_user(uaddr, &addr, sizeof(addr)))
215 return -EFAULT;
216 break;
217 default:
218 return -ENXIO;
219 }
220 }
221
222 return 0;
223}
224
225static struct kvm_device_ops kvm_arm_vgic_its_ops = {
226 .name = "kvm-arm-vgic-its",
227 .create = vgic_its_create,
228 .destroy = vgic_its_destroy,
229 .set_attr = vgic_its_set_attr,
230 .get_attr = vgic_its_get_attr,
231 .has_attr = vgic_its_has_attr,
232};
233
234int kvm_vgic_register_its_device(void)
235{
236 return kvm_register_device_ops(&kvm_arm_vgic_its_ops,
237 KVM_DEV_TYPE_ARM_VGIC_ITS);
238}