History

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.

Cornelia Huck committed 13 years ago

Commit 841b91c1 parent d938dc56 files · +265 −1Browse files

Unified · Split

6 files
  1. Documentation/virtual/kvm/devices/s390_flic.txt +45 −0
  2. arch/s390/include/asm/kvm_host.h +23 −0
  3. arch/s390/include/uapi/asm/kvm.h +22 −0
  4. arch/s390/kvm/interrupt.c +172 −1
  5. arch/s390/kvm/kvm-s390.c +1 −0
  6. arch/s390/kvm/kvm-s390.h +2 −0
Documentation/virtual/kvm/devices/s390_flic.txt+45−0
@@ -12,6 +12,7 @@ FLIC provides support to · 11 unmodified lines
1212 - inspect currently pending interrupts (KVM_FLIC_GET_ALL_IRQS)
1313 - purge all pending floating interrupts (KVM_DEV_FLIC_CLEAR_IRQS)
1414 - enable/disable for the guest transparent async page faults
15+- register and modify adapter interrupt sources (KVM_DEV_FLIC_ADAPTER_*)
1516
1617 Groups:
1718 KVM_DEV_FLIC_ENQUEUE
@@ -44,3 +45,47 @@ Groups: · 26 unmodified lines
4445 Disables async page faults for the guest and waits until already pending
4546 async page faults are done. This is necessary to trigger a completion interrupt
4647 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+
53+struct 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+
70+struct 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
arch/s390/include/asm/kvm_host.h+23−0
@@ -19,6 +19,7 @@ · 18 unmodified lines
1919 #include <linux/kvm.h>
2020 #include <asm/debug.h>
2121 #include <asm/cpu.h>
22+#include <asm/isc.h>
2223
2324 #define KVM_MAX_VCPUS 64
2425 #define KVM_USER_MEM_SLOTS 32
@@ -245,6 +246,27 @@ struct kvm_vm_stat { · 220 unmodified lines
245246 struct kvm_arch_memory_slot {
246247 };
247248
249+struct s390_map_info {
250+ struct list_head list;
251+ __u64 guest_addr;
252+ __u64 addr;
253+ struct page *page;
254+};
255+
256+struct 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+
248270 struct kvm_arch{
249271 struct sca_block *sca;
250272 debug_info_t *dbf;
@@ -252,6 +274,7 @@ struct kvm_arch{ · 1 unmodified line
252274 struct kvm_device *flic;
253275 struct gmap *gmap;
254276 int css_support;
277+ struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
255278 };
256279
257280 #define KVM_HVA_ERR_BAD (-1UL)
arch/s390/include/uapi/asm/kvm.h+22−0
@@ -22,6 +22,8 @@ · 21 unmodified lines
2222 #define KVM_DEV_FLIC_CLEAR_IRQS 3
2323 #define KVM_DEV_FLIC_APF_ENABLE 4
2424 #define KVM_DEV_FLIC_APF_DISABLE_WAIT 5
25+#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
26+#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
2527 /*
2628 * We can have up to 4*64k pending subchannels + 8 adapter interrupts,
2729 * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
@@ -32,6 +34,26 @@ · 4 unmodified lines
3234 #define KVM_S390_MAX_FLOAT_IRQS 266250
3335 #define KVM_S390_FLIC_MAX_BUFFER 0x2000000
3436
37+struct 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+
49+struct kvm_s390_io_adapter_req {
50+ __u32 id;
51+ __u8 type;
52+ __u8 mask;
53+ __u16 pad0;
54+ __u64 addr;
55+};
56+
3557 /* for KVM_GET_REGS and KVM_SET_REGS */
3658 struct kvm_regs {
3759 /* general purpose regs for s390 */
arch/s390/kvm/interrupt.c+172−1
@@ -1,7 +1,7 @@
11 /*
22 * handling kvm guest interrupts
33 *
4− * Copyright IBM Corp. 2008
4+ * Copyright IBM Corp. 2008,2014
55 *
66 * This program is free software; you can redistribute it and/or modify
77 * 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, · 1046 unmodified lines
10541054 return r;
10551055 }
10561056
1057+static 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+
1064+static 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+
1095+int 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+
1107+static 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);
1141+out:
1142+ if (ret)
1143+ kfree(map);
1144+ return ret;
1145+}
1146+
1147+static 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+
1172+void 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+
1190+static 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+
10571222 static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
10581223 {
10591224 int r = 0;
@@ -1082,6 +1247,12 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) · 22 unmodified lines
10821247 kvm_for_each_vcpu(i, vcpu, dev->kvm)
10831248 kvm_clear_async_pf_completion_queue(vcpu);
10841249 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;
10851256 default:
10861257 r = -EINVAL;
10871258 }
arch/s390/kvm/kvm-s390.c+1−0
@@ -343,6 +343,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) · 342 unmodified lines
343343 debug_unregister(kvm->arch.dbf);
344344 if (!kvm_is_ucontrol(kvm))
345345 gmap_free(kvm->arch.gmap);
346+ kvm_s390_destroy_adapters(kvm);
346347 }
347348
348349 /* Section: vcpu related */
arch/s390/kvm/kvm-s390.h+2−0
@@ -136,6 +136,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, · 135 unmodified lines
136136 int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
137137 struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
138138 u64 cr6, u64 schid);
139+int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
139140
140141 /* implemented in priv.c */
141142 int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
@@ -162,5 +163,6 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu); · 20 unmodified lines
162163 /* implemented in interrupt.c */
163164 int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
164165 int psw_extint_disabled(struct kvm_vcpu *vcpu);
166+void kvm_s390_destroy_adapters(struct kvm *kvm);
165167
166168 #endif