]> git.karo-electronics.de Git - karo-tx-linux.git/blob - virt/kvm/arm/vgic/vgic-kvm-device.c
KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_NR_IRQS
[karo-tx-linux.git] / virt / kvm / arm / vgic / vgic-kvm-device.c
1 /*
2  * VGIC: KVM DEVICE API
3  *
4  * Copyright (C) 2015 ARM Ltd.
5  * Author: Marc Zyngier <marc.zyngier@arm.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 #include <linux/kvm_host.h>
17 #include <kvm/arm_vgic.h>
18 #include <linux/uaccess.h>
19 #include "vgic.h"
20
21 /* common helpers */
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
81 static int vgic_create(struct kvm_device *dev, u32 type)
82 {
83         return kvm_vgic_create(dev->kvm, type);
84 }
85
86 static void vgic_destroy(struct kvm_device *dev)
87 {
88         kfree(dev);
89 }
90
91 void kvm_register_vgic_device(unsigned long type)
92 {
93         switch (type) {
94         case KVM_DEV_TYPE_ARM_VGIC_V2:
95                 kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
96                                         KVM_DEV_TYPE_ARM_VGIC_V2);
97                 break;
98 #ifdef CONFIG_KVM_ARM_VGIC_V3
99         case KVM_DEV_TYPE_ARM_VGIC_V3:
100                 kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
101                                         KVM_DEV_TYPE_ARM_VGIC_V3);
102                 break;
103 #endif
104         }
105 }
106
107 /* V2 ops */
108
109 static int vgic_v2_set_attr(struct kvm_device *dev,
110                             struct kvm_device_attr *attr)
111 {
112         int ret;
113
114         ret = vgic_set_common_attr(dev, attr);
115         return ret;
116
117 }
118
119 static int vgic_v2_get_attr(struct kvm_device *dev,
120                             struct kvm_device_attr *attr)
121 {
122         int ret;
123
124         ret = vgic_get_common_attr(dev, attr);
125         return ret;
126 }
127
128 static int vgic_v2_has_attr(struct kvm_device *dev,
129                             struct kvm_device_attr *attr)
130 {
131         switch (attr->group) {
132         case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
133                 return 0;
134         }
135         return -ENXIO;
136 }
137
138 struct kvm_device_ops kvm_arm_vgic_v2_ops = {
139         .name = "kvm-arm-vgic-v2",
140         .create = vgic_create,
141         .destroy = vgic_destroy,
142         .set_attr = vgic_v2_set_attr,
143         .get_attr = vgic_v2_get_attr,
144         .has_attr = vgic_v2_has_attr,
145 };
146
147 /* V3 ops */
148
149 #ifdef CONFIG_KVM_ARM_VGIC_V3
150
151 static int vgic_v3_set_attr(struct kvm_device *dev,
152                             struct kvm_device_attr *attr)
153 {
154         return vgic_set_common_attr(dev, attr);
155 }
156
157 static int vgic_v3_get_attr(struct kvm_device *dev,
158                             struct kvm_device_attr *attr)
159 {
160         return vgic_get_common_attr(dev, attr);
161 }
162
163 static int vgic_v3_has_attr(struct kvm_device *dev,
164                             struct kvm_device_attr *attr)
165 {
166         switch (attr->group) {
167         case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
168                 return 0;
169         }
170         return -ENXIO;
171 }
172
173 struct kvm_device_ops kvm_arm_vgic_v3_ops = {
174         .name = "kvm-arm-vgic-v3",
175         .create = vgic_create,
176         .destroy = vgic_destroy,
177         .set_attr = vgic_v3_set_attr,
178         .get_attr = vgic_v3_get_attr,
179         .has_attr = vgic_v3_has_attr,
180 };
181
182 #endif /* CONFIG_KVM_ARM_VGIC_V3 */
183