Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+265 -1
+45
Documentation/virtual/kvm/devices/s390_flic.txt
··· 12 12 - inspect currently pending interrupts (KVM_FLIC_GET_ALL_IRQS) 13 13 - purge all pending floating interrupts (KVM_DEV_FLIC_CLEAR_IRQS) 14 14 - enable/disable for the guest transparent async page faults 15 + - register and modify adapter interrupt sources (KVM_DEV_FLIC_ADAPTER_*) 15 16 16 17 Groups: 17 18 KVM_DEV_FLIC_ENQUEUE ··· 45 44 Disables async page faults for the guest and waits until already pending 46 45 async page faults are done. This is necessary to trigger a completion interrupt 47 46 for every init interrupt before migrating the interrupt list. 47 + 48 + KVM_DEV_FLIC_ADAPTER_REGISTER 49 + Register an I/O adapter interrupt source. Takes a kvm_s390_io_adapter 50 + describing the adapter to register: 51 + 52 + struct kvm_s390_io_adapter { 53 + __u32 id; 54 + __u8 isc; 55 + __u8 maskable; 56 + __u8 swap; 57 + __u8 pad; 58 + }; 59 + 60 + id contains the unique id for the adapter, isc the I/O interruption subclass 61 + to use, maskable whether this adapter may be masked (interrupts turned off) 62 + and swap whether the indicators need to be byte swapped. 63 + 64 + 65 + KVM_DEV_FLIC_ADAPTER_MODIFY 66 + Modifies attributes of an existing I/O adapter interrupt source. Takes 67 + a kvm_s390_io_adapter_req specifiying the adapter and the operation: 68 + 69 + struct kvm_s390_io_adapter_req { 70 + __u32 id; 71 + __u8 type; 72 + __u8 mask; 73 + __u16 pad0; 74 + __u64 addr; 75 + }; 76 + 77 + id specifies the adapter and type the operation. The supported operations 78 + are: 79 + 80 + KVM_S390_IO_ADAPTER_MASK 81 + mask or unmask the adapter, as specified in mask 82 + 83 + KVM_S390_IO_ADAPTER_MAP 84 + perform a gmap translation for the guest address provided in addr, 85 + pin a userspace page for the translated address and add it to the 86 + list of mappings 87 + 88 + KVM_S390_IO_ADAPTER_UNMAP 89 + release a userspace page for the translated address specified in addr 90 + from the list of mappings
+23
arch/s390/include/asm/kvm_host.h
··· 19 19 #include <linux/kvm.h> 20 20 #include <asm/debug.h> 21 21 #include <asm/cpu.h> 22 + #include <asm/isc.h> 22 23 23 24 #define KVM_MAX_VCPUS 64 24 25 #define KVM_USER_MEM_SLOTS 32 ··· 246 245 struct kvm_arch_memory_slot { 247 246 }; 248 247 248 + struct s390_map_info { 249 + struct list_head list; 250 + __u64 guest_addr; 251 + __u64 addr; 252 + struct page *page; 253 + }; 254 + 255 + struct s390_io_adapter { 256 + unsigned int id; 257 + int isc; 258 + bool maskable; 259 + bool masked; 260 + bool swap; 261 + struct rw_semaphore maps_lock; 262 + struct list_head maps; 263 + atomic_t nr_maps; 264 + }; 265 + 266 + #define MAX_S390_IO_ADAPTERS ((MAX_ISC + 1) * 8) 267 + #define MAX_S390_ADAPTER_MAPS 256 268 + 249 269 struct kvm_arch{ 250 270 struct sca_block *sca; 251 271 debug_info_t *dbf; ··· 274 252 struct kvm_device *flic; 275 253 struct gmap *gmap; 276 254 int css_support; 255 + struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; 277 256 }; 278 257 279 258 #define KVM_HVA_ERR_BAD (-1UL)
+22
arch/s390/include/uapi/asm/kvm.h
··· 22 22 #define KVM_DEV_FLIC_CLEAR_IRQS 3 23 23 #define KVM_DEV_FLIC_APF_ENABLE 4 24 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 28 * We can have up to 4*64k pending subchannels + 8 adapter interrupts, 27 29 * as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts. ··· 33 31 */ 34 32 #define KVM_S390_MAX_FLOAT_IRQS 266250 35 33 #define KVM_S390_FLIC_MAX_BUFFER 0x2000000 34 + 35 + struct kvm_s390_io_adapter { 36 + __u32 id; 37 + __u8 isc; 38 + __u8 maskable; 39 + __u8 swap; 40 + __u8 pad; 41 + }; 42 + 43 + #define KVM_S390_IO_ADAPTER_MASK 1 44 + #define KVM_S390_IO_ADAPTER_MAP 2 45 + #define KVM_S390_IO_ADAPTER_UNMAP 3 46 + 47 + struct kvm_s390_io_adapter_req { 48 + __u32 id; 49 + __u8 type; 50 + __u8 mask; 51 + __u16 pad0; 52 + __u64 addr; 53 + }; 36 54 37 55 /* for KVM_GET_REGS and KVM_SET_REGS */ 38 56 struct kvm_regs {
+172 -1
arch/s390/kvm/interrupt.c
··· 1 1 /* 2 2 * handling kvm guest interrupts 3 3 * 4 - * Copyright IBM Corp. 2008 4 + * Copyright IBM Corp. 2008,2014 5 5 * 6 6 * This program is free software; you can redistribute it and/or modify 7 7 * it under the terms of the GNU General Public License (version 2 only) ··· 1054 1054 return r; 1055 1055 } 1056 1056 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 + 1057 1222 static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 1058 1223 { 1059 1224 int r = 0; ··· 1246 1081 synchronize_srcu(&dev->kvm->srcu); 1247 1082 kvm_for_each_vcpu(i, vcpu, dev->kvm) 1248 1083 kvm_clear_async_pf_completion_queue(vcpu); 1084 + break; 1085 + case KVM_DEV_FLIC_ADAPTER_REGISTER: 1086 + r = register_io_adapter(dev, attr); 1087 + break; 1088 + case KVM_DEV_FLIC_ADAPTER_MODIFY: 1089 + r = modify_io_adapter(dev, attr); 1249 1090 break; 1250 1091 default: 1251 1092 r = -EINVAL;
+1
arch/s390/kvm/kvm-s390.c
··· 343 343 debug_unregister(kvm->arch.dbf); 344 344 if (!kvm_is_ucontrol(kvm)) 345 345 gmap_free(kvm->arch.gmap); 346 + kvm_s390_destroy_adapters(kvm); 346 347 } 347 348 348 349 /* Section: vcpu related */
+2
arch/s390/kvm/kvm-s390.h
··· 136 136 int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); 137 137 struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, 138 138 u64 cr6, u64 schid); 139 + int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked); 139 140 140 141 /* implemented in priv.c */ 141 142 int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); ··· 163 162 /* implemented in interrupt.c */ 164 163 int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); 165 164 int psw_extint_disabled(struct kvm_vcpu *vcpu); 165 + void kvm_s390_destroy_adapters(struct kvm *kvm); 166 166 167 167 #endif