KVM: arm/arm64: vgic-new: vgic_kvm_device: KVM_DEV_ARM_VGIC_GRP_CTRL
[deliverable/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
This page took 0.037164 seconds and 5 git commands to generate.