aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm/book3s_xics.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-04-26 20:28:37 -0400
committerAlexander Graf <agraf@suse.de>2013-05-02 09:28:36 -0400
commit5975a2e0950291a6bfe9fd5880e7952ff87764be (patch)
treea27a2f6645a74ad756ac4a3eba21e1086beab25d /arch/powerpc/kvm/book3s_xics.c
parentd133b40f2cdd527af01090ffd6a041485d1a29b4 (diff)
KVM: PPC: Book3S: Add API for in-kernel XICS emulation
This adds the API for userspace to instantiate an XICS device in a VM and connect VCPUs to it. The API consists of a new device type for the KVM_CREATE_DEVICE ioctl, a new capability KVM_CAP_IRQ_XICS, which functions similarly to KVM_CAP_IRQ_MPIC, and the KVM_IRQ_LINE ioctl, which is used to assert and deassert interrupt inputs of the XICS. The XICS device has one attribute group, KVM_DEV_XICS_GRP_SOURCES. Each attribute within this group corresponds to the state of one interrupt source. The attribute number is the same as the interrupt source number. This does not support irq routing or irqfd yet. Signed-off-by: Paul Mackerras <paulus@samba.org> Acked-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/kvm/book3s_xics.c')
-rw-r--r--arch/powerpc/kvm/book3s_xics.c190
1 files changed, 165 insertions, 25 deletions
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index ee841ed8a690..f7a103756618 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -11,6 +11,7 @@
11#include <linux/kvm_host.h> 11#include <linux/kvm_host.h>
12#include <linux/err.h> 12#include <linux/err.h>
13#include <linux/gfp.h> 13#include <linux/gfp.h>
14#include <linux/anon_inodes.h>
14 15
15#include <asm/uaccess.h> 16#include <asm/uaccess.h>
16#include <asm/kvm_book3s.h> 17#include <asm/kvm_book3s.h>
@@ -55,8 +56,6 @@
55 * 56 *
56 * - Make ICS lockless as well, or at least a per-interrupt lock or hashed 57 * - Make ICS lockless as well, or at least a per-interrupt lock or hashed
57 * locks array to improve scalability 58 * locks array to improve scalability
58 *
59 * - ioctl's to save/restore the entire state for snapshot & migration
60 */ 59 */
61 60
62/* -- ICS routines -- */ 61/* -- ICS routines -- */
@@ -64,7 +63,8 @@
64static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp, 63static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
65 u32 new_irq); 64 u32 new_irq);
66 65
67static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level) 66static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level,
67 bool report_status)
68{ 68{
69 struct ics_irq_state *state; 69 struct ics_irq_state *state;
70 struct kvmppc_ics *ics; 70 struct kvmppc_ics *ics;
@@ -81,6 +81,9 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level)
81 if (!state->exists) 81 if (!state->exists)
82 return -EINVAL; 82 return -EINVAL;
83 83
84 if (report_status)
85 return state->asserted;
86
84 /* 87 /*
85 * We set state->asserted locklessly. This should be fine as 88 * We set state->asserted locklessly. This should be fine as
86 * we are the only setter, thus concurrent access is undefined 89 * we are the only setter, thus concurrent access is undefined
@@ -96,7 +99,7 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level)
96 /* Attempt delivery */ 99 /* Attempt delivery */
97 icp_deliver_irq(xics, NULL, irq); 100 icp_deliver_irq(xics, NULL, irq);
98 101
99 return 0; 102 return state->asserted;
100} 103}
101 104
102static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics, 105static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
@@ -891,8 +894,8 @@ static void xics_debugfs_init(struct kvmppc_xics *xics)
891 kfree(name); 894 kfree(name);
892} 895}
893 896
894struct kvmppc_ics *kvmppc_xics_create_ics(struct kvm *kvm, 897static struct kvmppc_ics *kvmppc_xics_create_ics(struct kvm *kvm,
895 struct kvmppc_xics *xics, int irq) 898 struct kvmppc_xics *xics, int irq)
896{ 899{
897 struct kvmppc_ics *ics; 900 struct kvmppc_ics *ics;
898 int i, icsid; 901 int i, icsid;
@@ -1044,34 +1047,138 @@ int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval)
1044 return 0; 1047 return 0;
1045} 1048}
1046 1049
1047/* -- ioctls -- */ 1050static int xics_get_source(struct kvmppc_xics *xics, long irq, u64 addr)
1051{
1052 int ret;
1053 struct kvmppc_ics *ics;
1054 struct ics_irq_state *irqp;
1055 u64 __user *ubufp = (u64 __user *) addr;
1056 u16 idx;
1057 u64 val, prio;
1058
1059 ics = kvmppc_xics_find_ics(xics, irq, &idx);
1060 if (!ics)
1061 return -ENOENT;
1048 1062
1049int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args) 1063 irqp = &ics->irq_state[idx];
1064 mutex_lock(&ics->lock);
1065 ret = -ENOENT;
1066 if (irqp->exists) {
1067 val = irqp->server;
1068 prio = irqp->priority;
1069 if (prio == MASKED) {
1070 val |= KVM_XICS_MASKED;
1071 prio = irqp->saved_priority;
1072 }
1073 val |= prio << KVM_XICS_PRIORITY_SHIFT;
1074 if (irqp->asserted)
1075 val |= KVM_XICS_LEVEL_SENSITIVE | KVM_XICS_PENDING;
1076 else if (irqp->masked_pending || irqp->resend)
1077 val |= KVM_XICS_PENDING;
1078 ret = 0;
1079 }
1080 mutex_unlock(&ics->lock);
1081
1082 if (!ret && put_user(val, ubufp))
1083 ret = -EFAULT;
1084
1085 return ret;
1086}
1087
1088static int xics_set_source(struct kvmppc_xics *xics, long irq, u64 addr)
1050{ 1089{
1051 struct kvmppc_xics *xics; 1090 struct kvmppc_ics *ics;
1052 int r; 1091 struct ics_irq_state *irqp;
1092 u64 __user *ubufp = (u64 __user *) addr;
1093 u16 idx;
1094 u64 val;
1095 u8 prio;
1096 u32 server;
1097
1098 if (irq < KVMPPC_XICS_FIRST_IRQ || irq >= KVMPPC_XICS_NR_IRQS)
1099 return -ENOENT;
1100
1101 ics = kvmppc_xics_find_ics(xics, irq, &idx);
1102 if (!ics) {
1103 ics = kvmppc_xics_create_ics(xics->kvm, xics, irq);
1104 if (!ics)
1105 return -ENOMEM;
1106 }
1107 irqp = &ics->irq_state[idx];
1108 if (get_user(val, ubufp))
1109 return -EFAULT;
1110
1111 server = val & KVM_XICS_DESTINATION_MASK;
1112 prio = val >> KVM_XICS_PRIORITY_SHIFT;
1113 if (prio != MASKED &&
1114 kvmppc_xics_find_server(xics->kvm, server) == NULL)
1115 return -EINVAL;
1053 1116
1054 /* locking against multiple callers? */ 1117 mutex_lock(&ics->lock);
1118 irqp->server = server;
1119 irqp->saved_priority = prio;
1120 if (val & KVM_XICS_MASKED)
1121 prio = MASKED;
1122 irqp->priority = prio;
1123 irqp->resend = 0;
1124 irqp->masked_pending = 0;
1125 irqp->asserted = 0;
1126 if ((val & KVM_XICS_PENDING) && (val & KVM_XICS_LEVEL_SENSITIVE))
1127 irqp->asserted = 1;
1128 irqp->exists = 1;
1129 mutex_unlock(&ics->lock);
1055 1130
1056 xics = kvm->arch.xics; 1131 if (val & KVM_XICS_PENDING)
1057 if (!xics) 1132 icp_deliver_irq(xics, NULL, irqp->number);
1058 return -ENODEV;
1059 1133
1060 switch (args->level) { 1134 return 0;
1061 case KVM_INTERRUPT_SET: 1135}
1062 case KVM_INTERRUPT_SET_LEVEL: 1136
1063 case KVM_INTERRUPT_UNSET: 1137int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
1064 r = ics_deliver_irq(xics, args->irq, args->level); 1138 bool line_status)
1065 break; 1139{
1066 default: 1140 struct kvmppc_xics *xics = kvm->arch.xics;
1067 r = -EINVAL; 1141
1142 return ics_deliver_irq(xics, irq, level, line_status);
1143}
1144
1145static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
1146{
1147 struct kvmppc_xics *xics = dev->private;
1148
1149 switch (attr->group) {
1150 case KVM_DEV_XICS_GRP_SOURCES:
1151 return xics_set_source(xics, attr->attr, attr->addr);
1068 } 1152 }
1153 return -ENXIO;
1154}
1069 1155
1070 return r; 1156static int xics_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
1157{
1158 struct kvmppc_xics *xics = dev->private;
1159
1160 switch (attr->group) {
1161 case KVM_DEV_XICS_GRP_SOURCES:
1162 return xics_get_source(xics, attr->attr, attr->addr);
1163 }
1164 return -ENXIO;
1071} 1165}
1072 1166
1073void kvmppc_xics_free(struct kvmppc_xics *xics) 1167static int xics_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
1074{ 1168{
1169 switch (attr->group) {
1170 case KVM_DEV_XICS_GRP_SOURCES:
1171 if (attr->attr >= KVMPPC_XICS_FIRST_IRQ &&
1172 attr->attr < KVMPPC_XICS_NR_IRQS)
1173 return 0;
1174 break;
1175 }
1176 return -ENXIO;
1177}
1178
1179static void kvmppc_xics_free(struct kvm_device *dev)
1180{
1181 struct kvmppc_xics *xics = dev->private;
1075 int i; 1182 int i;
1076 struct kvm *kvm = xics->kvm; 1183 struct kvm *kvm = xics->kvm;
1077 1184
@@ -1083,17 +1190,21 @@ void kvmppc_xics_free(struct kvmppc_xics *xics)
1083 for (i = 0; i <= xics->max_icsid; i++) 1190 for (i = 0; i <= xics->max_icsid; i++)
1084 kfree(xics->ics[i]); 1191 kfree(xics->ics[i]);
1085 kfree(xics); 1192 kfree(xics);
1193 kfree(dev);
1086} 1194}
1087 1195
1088int kvm_xics_create(struct kvm *kvm, u32 type) 1196static int kvmppc_xics_create(struct kvm_device *dev, u32 type)
1089{ 1197{
1090 struct kvmppc_xics *xics; 1198 struct kvmppc_xics *xics;
1199 struct kvm *kvm = dev->kvm;
1091 int ret = 0; 1200 int ret = 0;
1092 1201
1093 xics = kzalloc(sizeof(*xics), GFP_KERNEL); 1202 xics = kzalloc(sizeof(*xics), GFP_KERNEL);
1094 if (!xics) 1203 if (!xics)
1095 return -ENOMEM; 1204 return -ENOMEM;
1096 1205
1206 dev->private = xics;
1207 xics->dev = dev;
1097 xics->kvm = kvm; 1208 xics->kvm = kvm;
1098 1209
1099 /* Already there ? */ 1210 /* Already there ? */
@@ -1120,6 +1231,35 @@ int kvm_xics_create(struct kvm *kvm, u32 type)
1120 return 0; 1231 return 0;
1121} 1232}
1122 1233
1234struct kvm_device_ops kvm_xics_ops = {
1235 .name = "kvm-xics",
1236 .create = kvmppc_xics_create,
1237 .destroy = kvmppc_xics_free,
1238 .set_attr = xics_set_attr,
1239 .get_attr = xics_get_attr,
1240 .has_attr = xics_has_attr,
1241};
1242
1243int kvmppc_xics_connect_vcpu(struct kvm_device *dev, struct kvm_vcpu *vcpu,
1244 u32 xcpu)
1245{
1246 struct kvmppc_xics *xics = dev->private;
1247 int r = -EBUSY;
1248
1249 if (dev->ops != &kvm_xics_ops)
1250 return -EPERM;
1251 if (xics->kvm != vcpu->kvm)
1252 return -EPERM;
1253 if (vcpu->arch.irq_type)
1254 return -EBUSY;
1255
1256 r = kvmppc_xics_create_icp(vcpu, xcpu);
1257 if (!r)
1258 vcpu->arch.irq_type = KVMPPC_IRQ_XICS;
1259
1260 return r;
1261}
1262
1123void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) 1263void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
1124{ 1264{
1125 if (!vcpu->arch.icp) 1265 if (!vcpu->arch.icp)