4 * Copyright (C) 2015 ARM Ltd.
5 * Author: Marc Zyngier <marc.zyngier@arm.com>
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.
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.
16 #include <linux/kvm_host.h>
17 #include <kvm/arm_vgic.h>
18 #include <linux/uaccess.h>
23 static int vgic_set_common_attr(struct kvm_device *dev,
24 struct kvm_device_attr *attr)
26 switch (attr->group) {
27 case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
28 u32 __user *uaddr = (u32 __user *)(long)attr->addr;
32 if (get_user(val, uaddr))
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
41 if (val < (VGIC_NR_PRIVATE_IRQS + 32) ||
42 val > VGIC_MAX_RESERVED ||
46 mutex_lock(&dev->kvm->lock);
48 if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis)
51 dev->kvm->arch.vgic.nr_spis =
52 val - VGIC_NR_PRIVATE_IRQS;
54 mutex_unlock(&dev->kvm->lock);
63 static int vgic_get_common_attr(struct kvm_device *dev,
64 struct kvm_device_attr *attr)
68 switch (attr->group) {
69 case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: {
70 u32 __user *uaddr = (u32 __user *)(long)attr->addr;
72 r = put_user(dev->kvm->arch.vgic.nr_spis +
73 VGIC_NR_PRIVATE_IRQS, uaddr);
81 static int vgic_create(struct kvm_device *dev, u32 type)
83 return kvm_vgic_create(dev->kvm, type);
86 static void vgic_destroy(struct kvm_device *dev)
91 void kvm_register_vgic_device(unsigned long 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);
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);
109 static int vgic_v2_set_attr(struct kvm_device *dev,
110 struct kvm_device_attr *attr)
114 ret = vgic_set_common_attr(dev, attr);
119 static int vgic_v2_get_attr(struct kvm_device *dev,
120 struct kvm_device_attr *attr)
124 ret = vgic_get_common_attr(dev, attr);
128 static int vgic_v2_has_attr(struct kvm_device *dev,
129 struct kvm_device_attr *attr)
131 switch (attr->group) {
132 case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
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,
149 #ifdef CONFIG_KVM_ARM_VGIC_V3
151 static int vgic_v3_set_attr(struct kvm_device *dev,
152 struct kvm_device_attr *attr)
154 return vgic_set_common_attr(dev, attr);
157 static int vgic_v3_get_attr(struct kvm_device *dev,
158 struct kvm_device_attr *attr)
160 return vgic_get_common_attr(dev, attr);
163 static int vgic_v3_has_attr(struct kvm_device *dev,
164 struct kvm_device_attr *attr)
166 switch (attr->group) {
167 case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
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,
182 #endif /* CONFIG_KVM_ARM_VGIC_V3 */