]> 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_CTRL
[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         int r;
27
28         switch (attr->group) {
29         case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
30                 u32 __user *uaddr = (u32 __user *)(long)attr->addr;
31                 u32 val;
32                 int ret = 0;
33
34                 if (get_user(val, uaddr))
35                         return -EFAULT;
36
37                 /*
38                  * We require:
39                  * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs
40                  * - at most 1024 interrupts
41                  * - a multiple of 32 interrupts
42                  */
43                 if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
44                     val > VGIC_MAX_RESERVED ||
45                     (val & 31))
46                         return -EINVAL;
47
48                 mutex_lock(&dev->kvm->lock);
49
50                 if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
51                         ret = -EBUSY;
52                 else
53                         dev->kvm->arch.vgic.nr_spis =
54                                 val - VGIC_NR_PRIVATE_IRQS;
55
56                 mutex_unlock(&dev->kvm->lock);
57
58                 return ret;
59         }
60         case KVM_DEV_ARM_VGIC_GRP_CTRL: {
61                 switch (attr->attr) {
62                 case KVM_DEV_ARM_VGIC_CTRL_INIT:
63                         mutex_lock(&dev->kvm->lock);
64                         r = vgic_init(dev->kvm);
65                         mutex_unlock(&dev->kvm->lock);
66                         return r;
67                 }
68                 break;
69         }
70         }
71
72         return -ENXIO;
73 }
74
75 static int vgic_get_common_attr(struct kvm_device *dev,
76                                 struct kvm_device_attr *attr)
77 {
78         int r = -ENXIO;
79
80         switch (attr->group) {
81         case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
82                 u32 __user *uaddr = (u32 __user *)(long)attr->addr;
83
84                 r = put_user(dev->kvm->arch.vgic.nr_spis +
85                              VGIC_NR_PRIVATE_IRQS, uaddr);
86                 break;
87         }
88         }
89
90         return r;
91 }
92
93 static int vgic_create(struct kvm_device *dev, u32 type)
94 {
95         return kvm_vgic_create(dev->kvm, type);
96 }
97
98 static void vgic_destroy(struct kvm_device *dev)
99 {
100         kfree(dev);
101 }
102
103 void kvm_register_vgic_device(unsigned long type)
104 {
105         switch (type) {
106         case KVM_DEV_TYPE_ARM_VGIC_V2:
107                 kvm_register_device_ops(&kvm_arm_vgic_v2_ops,
108                                         KVM_DEV_TYPE_ARM_VGIC_V2);
109                 break;
110 #ifdef CONFIG_KVM_ARM_VGIC_V3
111         case KVM_DEV_TYPE_ARM_VGIC_V3:
112                 kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
113                                         KVM_DEV_TYPE_ARM_VGIC_V3);
114                 break;
115 #endif
116         }
117 }
118
119 /* V2 ops */
120
121 static int vgic_v2_set_attr(struct kvm_device *dev,
122                             struct kvm_device_attr *attr)
123 {
124         int ret;
125
126         ret = vgic_set_common_attr(dev, attr);
127         return ret;
128
129 }
130
131 static int vgic_v2_get_attr(struct kvm_device *dev,
132                             struct kvm_device_attr *attr)
133 {
134         int ret;
135
136         ret = vgic_get_common_attr(dev, attr);
137         return ret;
138 }
139
140 static int vgic_v2_has_attr(struct kvm_device *dev,
141                             struct kvm_device_attr *attr)
142 {
143         switch (attr->group) {
144         case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
145                 return 0;
146         case KVM_DEV_ARM_VGIC_GRP_CTRL:
147                 switch (attr->attr) {
148                 case KVM_DEV_ARM_VGIC_CTRL_INIT:
149                         return 0;
150                 }
151         }
152         return -ENXIO;
153 }
154
155 struct kvm_device_ops kvm_arm_vgic_v2_ops = {
156         .name = "kvm-arm-vgic-v2",
157         .create = vgic_create,
158         .destroy = vgic_destroy,
159         .set_attr = vgic_v2_set_attr,
160         .get_attr = vgic_v2_get_attr,
161         .has_attr = vgic_v2_has_attr,
162 };
163
164 /* V3 ops */
165
166 #ifdef CONFIG_KVM_ARM_VGIC_V3
167
168 static int vgic_v3_set_attr(struct kvm_device *dev,
169                             struct kvm_device_attr *attr)
170 {
171         return vgic_set_common_attr(dev, attr);
172 }
173
174 static int vgic_v3_get_attr(struct kvm_device *dev,
175                             struct kvm_device_attr *attr)
176 {
177         return vgic_get_common_attr(dev, attr);
178 }
179
180 static int vgic_v3_has_attr(struct kvm_device *dev,
181                             struct kvm_device_attr *attr)
182 {
183         switch (attr->group) {
184         case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
185                 return 0;
186         case KVM_DEV_ARM_VGIC_GRP_CTRL:
187                 switch (attr->attr) {
188                 case KVM_DEV_ARM_VGIC_CTRL_INIT:
189                         return 0;
190                 }
191         }
192         return -ENXIO;
193 }
194
195 struct kvm_device_ops kvm_arm_vgic_v3_ops = {
196         .name = "kvm-arm-vgic-v3",
197         .create = vgic_create,
198         .destroy = vgic_destroy,
199         .set_attr = vgic_v3_set_attr,
200         .get_attr = vgic_v3_get_attr,
201         .has_attr = vgic_v3_has_attr,
202 };
203
204 #endif /* CONFIG_KVM_ARM_VGIC_V3 */
205