aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2013-07-15 07:36:01 -0400
committerCornelia Huck <cornelia.huck@de.ibm.com>2014-03-21 08:42:49 -0400
commit841b91c584b6d1e2a2cb508bd2d0236cd37e1750 (patch)
tree0a2f1b2cfa471cefa22bc9c12628361ed2c0ac4c
parentd938dc55225a7212e7f31c5a8571da304cc3de16 (diff)
KVM: s390: adapter interrupt sources
Add a new interface to register/deregister sources of adapter interrupts identified by an unique id via the flic. Adapters may also be maskable and carry a list of pinned pages. These adapters will be used by irq routing later. Acked-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
-rw-r--r--Documentation/virtual/kvm/devices/s390_flic.txt45
-rw-r--r--arch/s390/include/asm/kvm_host.h23
-rw-r--r--arch/s390/include/uapi/asm/kvm.h22
-rw-r--r--arch/s390/kvm/interrupt.c173
-rw-r--r--arch/s390/kvm/kvm-s390.c1
-rw-r--r--arch/s390/kvm/kvm-s390.h2
6 files changed, 265 insertions, 1 deletions
diff --git a/Documentation/virtual/kvm/devices/s390_flic.txt b/Documentation/virtual/kvm/devices/s390_flic.txt
index 410fa673e5b6..4ceef53164b0 100644
--- a/Documentation/virtual/kvm/devices/s390_flic.txt
+++ b/Documentation/virtual/kvm/devices/s390_flic.txt
@@ -12,6 +12,7 @@ FLIC provides support to
12- inspect currently pending interrupts (KVM_FLIC_GET_ALL_IRQS) 12- inspect currently pending interrupts (KVM_FLIC_GET_ALL_IRQS)
13- purge all pending floating interrupts (KVM_DEV_FLIC_CLEAR_IRQS) 13- purge all pending floating interrupts (KVM_DEV_FLIC_CLEAR_IRQS)
14- enable/disable for the guest transparent async page faults 14- enable/disable for the guest transparent async page faults
15- register and modify adapter interrupt sources (KVM_DEV_FLIC_ADAPTER_*)
15 16
16Groups: 17Groups:
17 KVM_DEV_FLIC_ENQUEUE 18 KVM_DEV_FLIC_ENQUEUE
@@ -44,3 +45,47 @@ Groups:
44 Disables async page faults for the guest and waits until already pending 45 Disables async page faults for the guest and waits until already pending
45 async page faults are done. This is necessary to trigger a completion interrupt 46 async page faults are done. This is necessary to trigger a completion interrupt
46 for every init interrupt before migrating the interrupt list. 47 for every init interrupt before migrating the interrupt list.
48
49 KVM_DEV_FLIC_ADAPTER_REGISTER
50 Register an I/O adapter interrupt source. Takes a kvm_s390_io_adapter
51 describing the adapter to register:
52
53struct kvm_s390_io_adapter {
54 __u32 id;
55 __u8 isc;
56 __u8 maskable;
57 __u8 swap;
58 __u8 pad;
59};
60
61 id contains the unique id for the adapter, isc the I/O interruption subclass
62 to use, maskable whether this adapter may be masked (interrupts turned off)
63 and swap whether the indicators need to be byte swapped.
64
65
66 KVM_DEV_FLIC_ADAPTER_MODIFY
67 Modifies attributes of an existing I/O adapter interrupt source. Takes
68 a kvm_s390_io_adapter_req specifiying the adapter and the operation:
69
70struct kvm_s390_io_adapter_req {
71 __u32 id;
72 __u8 type;
73 __u8 mask;
74 __u16 pad0;
75 __u64 addr;
76};
77
78 id specifies the adapter and type the operation. The supported operations
79 are:
80
81 KVM_S390_IO_ADAPTER_MASK
82 mask or unmask the adapter, as specified in mask
83
84 KVM_S390_IO_ADAPTER_MAP
85 perform a gmap translation for the guest address provided in addr,
86 pin a userspace page for the translated address and add it to the
87 list of mappings
88
89 KVM_S390_IO_ADAPTER_UNMAP
90 release a userspace page for the translated address specified in addr
91 from the list of mappings
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 734d302ba389..0d5235262707 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -19,6 +19,7 @@
19#include <linux/kvm.h> 19#include <linux/kvm.h>
20#include <asm/debug.h> 20#include <asm/debug.h>
21#include <asm/cpu.h> 21#include <asm/cpu.h>
22#include <asm/isc.h>
22 23
23#define KVM_MAX_VCPUS 64 24#define KVM_MAX_VCPUS 64
24#define KVM_USER_MEM_SLOTS 32 25#define KVM_USER_MEM_SLOTS 32
@@ -245,6 +246,27 @@ struct kvm_vm_stat {
245struct kvm_arch_memory_slot { 246struct kvm_arch_memory_slot {
246}; 247};
247 248
249struct s390_map_info {
250 struct list_head list;
251 __u64 guest_addr;
252 __u64 addr;
253 struct page *page;
254};
255
256struct s390_io_adapter {
257 unsigned int id;
258 int isc;
259 bool maskable;
260 bool masked;
261 bool swap;
262 struct rw_semaphore maps_lock;
263 struct list_head maps;
264 atomic_t nr_maps;
265};
266
267#define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8)
268#define MAX_S390_ADAPTER_MAPS 256
269
248struct kvm_arch{ 270struct kvm_arch{
249 struct sca_block *sca; 271 struct sca_block *sca;
250 debug_info_t *dbf; 272 debug_info_t *dbf;
@@ -252,6 +274,7 @@ struct kvm_arch{
252 struct kvm_device *flic; 274 struct kvm_device *flic;
253 struct gmap *gmap; 275 struct gmap *gmap;
254 int css_support; 276 int css_support;
277 struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
255}; 278};
256 279
257#define KVM_HVA_ERR_BAD (-1UL) 280#define KVM_HVA_ERR_BAD (-1UL)
diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h
index 2f0ade24f96a..c003c6a73b1e 100644
--- a/arch/s390/include/uapi/asm/kvm.h
+++ b/arch/s390/include/uapi/asm/kvm.h
@@ -22,6 +22,8 @@
22#define KVM_DEV_FLIC_CLEAR_IRQS 3 22#define KVM_DEV_FLIC_CLEAR_IRQS 3
23#define KVM_DEV_FLIC_APF_ENABLE 4 23#define KVM_DEV_FLIC_APF_ENABLE 4
24#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5 24#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5
25#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
26#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
25/* 27/*
26 * We can have up to 4*64k pending subchannels + 8 adapter interrupts, 28 * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
27 * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. 29 * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
@@ -32,6 +34,26 @@
32#define KVM_S390_MAX_FLOAT_IRQS 266250 34#define KVM_S390_MAX_FLOAT_IRQS 266250
33#define KVM_S390_FLIC_MAX_BUFFER 0x2000000 35#define KVM_S390_FLIC_MAX_BUFFER 0x2000000
34 36
37struct kvm_s390_io_adapter {
38 __u32 id;
39 __u8 isc;
40 __u8 maskable;
41 __u8 swap;
42 __u8 pad;
43};
44
45#define KVM_S390_IO_ADAPTER_MASK 1
46#define KVM_S390_IO_ADAPTER_MAP 2
47#define KVM_S390_IO_ADAPTER_UNMAP 3
48
49struct kvm_s390_io_adapter_req {
50 __u32 id;
51 __u8 type;
52 __u8 mask;
53 __u16 pad0;
54 __u64 addr;
55};
56
35/* for KVM_GET_REGS and KVM_SET_REGS */ 57/* for KVM_GET_REGS and KVM_SET_REGS */
36struct kvm_regs { 58struct kvm_regs {
37 /* general purpose regs for s390 */ 59 /* general purpose regs for s390 */
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 79d2e4fa9f9c..7ecef5a18e25 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * handling kvm guest interrupts 2 * handling kvm guest interrupts
3 * 3 *
4 * Copyright IBM Corp. 2008 4 * Copyright IBM Corp. 2008,2014
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License (version 2 only) 7 * it under the terms of the GNU General Public License (version 2 only)
@@ -1054,6 +1054,171 @@ static int enqueue_floating_irq(struct kvm_device *dev,
1054 return r; 1054 return r;
1055} 1055}
1056 1056
1057static struct s390_io_adapter *get_io_adapter(struct kvm *kvm, unsigned int id)
1058{
1059 if (id >= MAX_S390_IO_ADAPTERS)
1060 return NULL;
1061 return kvm->arch.adapters[id];
1062}
1063
1064static int register_io_adapter(struct kvm_device *dev,
1065 struct kvm_device_attr *attr)
1066{
1067 struct s390_io_adapter *adapter;
1068 struct kvm_s390_io_adapter adapter_info;
1069
1070 if (copy_from_user(&adapter_info,
1071 (void __user *)attr->addr, sizeof(adapter_info)))
1072 return -EFAULT;
1073
1074 if ((adapter_info.id >= MAX_S390_IO_ADAPTERS) ||
1075 (dev->kvm->arch.adapters[adapter_info.id] != NULL))
1076 return -EINVAL;
1077
1078 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
1079 if (!adapter)
1080 return -ENOMEM;
1081
1082 INIT_LIST_HEAD(&adapter->maps);
1083 init_rwsem(&adapter->maps_lock);
1084 atomic_set(&adapter->nr_maps, 0);
1085 adapter->id = adapter_info.id;
1086 adapter->isc = adapter_info.isc;
1087 adapter->maskable = adapter_info.maskable;
1088 adapter->masked = false;
1089 adapter->swap = adapter_info.swap;
1090 dev->kvm->arch.adapters[adapter->id] = adapter;
1091
1092 return 0;
1093}
1094
1095int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked)
1096{
1097 int ret;
1098 struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
1099
1100 if (!adapter || !adapter->maskable)
1101 return -EINVAL;
1102 ret = adapter->masked;
1103 adapter->masked = masked;
1104 return ret;
1105}
1106
1107static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
1108{
1109 struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
1110 struct s390_map_info *map;
1111 int ret;
1112
1113 if (!adapter || !addr)
1114 return -EINVAL;
1115
1116 map = kzalloc(sizeof(*map), GFP_KERNEL);
1117 if (!map) {
1118 ret = -ENOMEM;
1119 goto out;
1120 }
1121 INIT_LIST_HEAD(&map->list);
1122 map->guest_addr = addr;
1123 map->addr = gmap_translate(addr, kvm->arch.gmap);
1124 if (map->addr == -EFAULT) {
1125 ret = -EFAULT;
1126 goto out;
1127 }
1128 ret = get_user_pages_fast(map->addr, 1, 1, &map->page);
1129 if (ret < 0)
1130 goto out;
1131 BUG_ON(ret != 1);
1132 down_write(&adapter->maps_lock);
1133 if (atomic_inc_return(&adapter->nr_maps) < MAX_S390_ADAPTER_MAPS) {
1134 list_add_tail(&map->list, &adapter->maps);
1135 ret = 0;
1136 } else {
1137 put_page(map->page);
1138 ret = -EINVAL;
1139 }
1140 up_write(&adapter->maps_lock);
1141out:
1142 if (ret)
1143 kfree(map);
1144 return ret;
1145}
1146
1147static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
1148{
1149 struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
1150 struct s390_map_info *map, *tmp;
1151 int found = 0;
1152
1153 if (!adapter || !addr)
1154 return -EINVAL;
1155
1156 down_write(&adapter->maps_lock);
1157 list_for_each_entry_safe(map, tmp, &adapter->maps, list) {
1158 if (map->guest_addr == addr) {
1159 found = 1;
1160 atomic_dec(&adapter->nr_maps);
1161 list_del(&map->list);
1162 put_page(map->page);
1163 kfree(map);
1164 break;
1165 }
1166 }
1167 up_write(&adapter->maps_lock);
1168
1169 return found ? 0 : -EINVAL;
1170}
1171
1172void kvm_s390_destroy_adapters(struct kvm *kvm)
1173{
1174 int i;
1175 struct s390_map_info *map, *tmp;
1176
1177 for (i = 0; i < MAX_S390_IO_ADAPTERS; i++) {
1178 if (!kvm->arch.adapters[i])
1179 continue;
1180 list_for_each_entry_safe(map, tmp,
1181 &kvm->arch.adapters[i]->maps, list) {
1182 list_del(&map->list);
1183 put_page(map->page);
1184 kfree(map);
1185 }
1186 kfree(kvm->arch.adapters[i]);
1187 }
1188}
1189
1190static int modify_io_adapter(struct kvm_device *dev,
1191 struct kvm_device_attr *attr)
1192{
1193 struct kvm_s390_io_adapter_req req;
1194 struct s390_io_adapter *adapter;
1195 int ret;
1196
1197 if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req)))
1198 return -EFAULT;
1199
1200 adapter = get_io_adapter(dev->kvm, req.id);
1201 if (!adapter)
1202 return -EINVAL;
1203 switch (req.type) {
1204 case KVM_S390_IO_ADAPTER_MASK:
1205 ret = kvm_s390_mask_adapter(dev->kvm, req.id, req.mask);
1206 if (ret > 0)
1207 ret = 0;
1208 break;
1209 case KVM_S390_IO_ADAPTER_MAP:
1210 ret = kvm_s390_adapter_map(dev->kvm, req.id, req.addr);
1211 break;
1212 case KVM_S390_IO_ADAPTER_UNMAP:
1213 ret = kvm_s390_adapter_unmap(dev->kvm, req.id, req.addr);
1214 break;
1215 default:
1216 ret = -EINVAL;
1217 }
1218
1219 return ret;
1220}
1221
1057static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 1222static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
1058{ 1223{
1059 int r = 0; 1224 int r = 0;
@@ -1082,6 +1247,12 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
1082 kvm_for_each_vcpu(i, vcpu, dev->kvm) 1247 kvm_for_each_vcpu(i, vcpu, dev->kvm)
1083 kvm_clear_async_pf_completion_queue(vcpu); 1248 kvm_clear_async_pf_completion_queue(vcpu);
1084 break; 1249 break;
1250 case KVM_DEV_FLIC_ADAPTER_REGISTER:
1251 r = register_io_adapter(dev, attr);
1252 break;
1253 case KVM_DEV_FLIC_ADAPTER_MODIFY:
1254 r = modify_io_adapter(dev, attr);
1255 break;
1085 default: 1256 default:
1086 r = -EINVAL; 1257 r = -EINVAL;
1087 } 1258 }
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 9f1e99f12d4f..2e6fbb0b4f68 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -343,6 +343,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
343 debug_unregister(kvm->arch.dbf); 343 debug_unregister(kvm->arch.dbf);
344 if (!kvm_is_ucontrol(kvm)) 344 if (!kvm_is_ucontrol(kvm))
345 gmap_free(kvm->arch.gmap); 345 gmap_free(kvm->arch.gmap);
346 kvm_s390_destroy_adapters(kvm);
346} 347}
347 348
348/* Section: vcpu related */ 349/* Section: vcpu related */
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index ed4750a5bc3c..5502cc951868 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -136,6 +136,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
136int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); 136int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
137struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, 137struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
138 u64 cr6, u64 schid); 138 u64 cr6, u64 schid);
139int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
139 140
140/* implemented in priv.c */ 141/* implemented in priv.c */
141int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); 142int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
@@ -162,5 +163,6 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
162/* implemented in interrupt.c */ 163/* implemented in interrupt.c */
163int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); 164int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
164int psw_extint_disabled(struct kvm_vcpu *vcpu); 165int psw_extint_disabled(struct kvm_vcpu *vcpu);
166void kvm_s390_destroy_adapters(struct kvm *kvm);
165 167
166#endif 168#endif