1 /* 2 * QEMU S390x KVM floating interrupt controller (flic) 3 * 4 * Copyright 2014 IBM Corp. 5 * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com> 6 * Cornelia Huck <cornelia.huck@de.ibm.com> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or (at 9 * your option) any later version. See the COPYING file in the top-level 10 * directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qemu-common.h" 15 #include "cpu.h" 16 #include <sys/ioctl.h> 17 #include "qemu/error-report.h" 18 #include "hw/sysbus.h" 19 #include "sysemu/kvm.h" 20 #include "migration/qemu-file.h" 21 #include "hw/s390x/s390_flic.h" 22 #include "hw/s390x/adapter.h" 23 #include "trace.h" 24 25 #define FLIC_SAVE_INITIAL_SIZE getpagesize() 26 #define FLIC_FAILED (-1UL) 27 #define FLIC_SAVEVM_VERSION 1 28 29 typedef struct KVMS390FLICState { 30 S390FLICState parent_obj; 31 32 uint32_t fd; 33 } KVMS390FLICState; 34 35 DeviceState *s390_flic_kvm_create(void) 36 { 37 DeviceState *dev = NULL; 38 39 if (kvm_enabled()) { 40 dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); 41 object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, 42 OBJECT(dev), NULL); 43 } 44 return dev; 45 } 46 47 /** 48 * flic_get_all_irqs - store all pending irqs in buffer 49 * @buf: pointer to buffer which is passed to kernel 50 * @len: length of buffer 51 * @flic: pointer to flic device state 52 * 53 * Returns: -ENOMEM if buffer is too small, 54 * -EINVAL if attr.group is invalid, 55 * -EFAULT if copying to userspace failed, 56 * on success return number of stored interrupts 57 */ 58 static int flic_get_all_irqs(KVMS390FLICState *flic, 59 void *buf, int len) 60 { 61 struct kvm_device_attr attr = { 62 .group = KVM_DEV_FLIC_GET_ALL_IRQS, 63 .addr = (uint64_t) buf, 64 .attr = len, 65 }; 66 int rc; 67 68 rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr); 69 70 return rc == -1 ? -errno : rc; 71 } 72 73 static void flic_enable_pfault(KVMS390FLICState *flic) 74 { 75 struct kvm_device_attr attr = { 76 .group = KVM_DEV_FLIC_APF_ENABLE, 77 }; 78 int rc; 79 80 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 81 82 if (rc) { 83 fprintf(stderr, "flic: couldn't enable pfault\n"); 84 } 85 } 86 87 static void flic_disable_wait_pfault(KVMS390FLICState *flic) 88 { 89 struct kvm_device_attr attr = { 90 .group = KVM_DEV_FLIC_APF_DISABLE_WAIT, 91 }; 92 int rc; 93 94 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 95 96 if (rc) { 97 fprintf(stderr, "flic: couldn't disable pfault\n"); 98 } 99 } 100 101 /** flic_enqueue_irqs - returns 0 on success 102 * @buf: pointer to buffer which is passed to kernel 103 * @len: length of buffer 104 * @flic: pointer to flic device state 105 * 106 * Returns: -EINVAL if attr.group is unknown 107 */ 108 static int flic_enqueue_irqs(void *buf, uint64_t len, 109 KVMS390FLICState *flic) 110 { 111 int rc; 112 struct kvm_device_attr attr = { 113 .group = KVM_DEV_FLIC_ENQUEUE, 114 .addr = (uint64_t) buf, 115 .attr = len, 116 }; 117 118 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 119 120 return rc ? -errno : 0; 121 } 122 123 int kvm_s390_inject_flic(struct kvm_s390_irq *irq) 124 { 125 static KVMS390FLICState *flic; 126 127 if (unlikely(!flic)) { 128 flic = KVM_S390_FLIC(s390_get_flic()); 129 } 130 return flic_enqueue_irqs(irq, sizeof(*irq), flic); 131 } 132 133 /** 134 * __get_all_irqs - store all pending irqs in buffer 135 * @flic: pointer to flic device state 136 * @buf: pointer to pointer to a buffer 137 * @len: length of buffer 138 * 139 * Returns: return value of flic_get_all_irqs 140 * Note: Retry and increase buffer size until flic_get_all_irqs 141 * either returns a value >= 0 or a negative error code. 142 * -ENOMEM is an exception, which means the buffer is too small 143 * and we should try again. Other negative error codes can be 144 * -EFAULT and -EINVAL which we ignore at this point 145 */ 146 static int __get_all_irqs(KVMS390FLICState *flic, 147 void **buf, int len) 148 { 149 int r; 150 151 do { 152 /* returns -ENOMEM if buffer is too small and number 153 * of queued interrupts on success */ 154 r = flic_get_all_irqs(flic, *buf, len); 155 if (r >= 0) { 156 break; 157 } 158 len *= 2; 159 *buf = g_try_realloc(*buf, len); 160 if (!buf) { 161 return -ENOMEM; 162 } 163 } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER); 164 165 return r; 166 } 167 168 static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id, 169 uint8_t isc, bool swap, 170 bool is_maskable) 171 { 172 struct kvm_s390_io_adapter adapter = { 173 .id = id, 174 .isc = isc, 175 .maskable = is_maskable, 176 .swap = swap, 177 }; 178 KVMS390FLICState *flic = KVM_S390_FLIC(fs); 179 int r, ret; 180 struct kvm_device_attr attr = { 181 .group = KVM_DEV_FLIC_ADAPTER_REGISTER, 182 .addr = (uint64_t)&adapter, 183 }; 184 185 if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { 186 /* nothing to do */ 187 return 0; 188 } 189 190 r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 191 192 ret = r ? -errno : 0; 193 return ret; 194 } 195 196 static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id, 197 uint64_t map_addr, bool do_map) 198 { 199 struct kvm_s390_io_adapter_req req = { 200 .id = id, 201 .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP, 202 .addr = map_addr, 203 }; 204 struct kvm_device_attr attr = { 205 .group = KVM_DEV_FLIC_ADAPTER_MODIFY, 206 .addr = (uint64_t)&req, 207 }; 208 KVMS390FLICState *flic = KVM_S390_FLIC(fs); 209 int r; 210 211 if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { 212 /* nothing to do */ 213 return 0; 214 } 215 216 r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 217 return r ? -errno : 0; 218 } 219 220 static int kvm_s390_add_adapter_routes(S390FLICState *fs, 221 AdapterRoutes *routes) 222 { 223 int ret, i; 224 uint64_t ind_offset = routes->adapter.ind_offset; 225 226 for (i = 0; i < routes->num_routes; i++) { 227 ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter); 228 if (ret < 0) { 229 goto out_undo; 230 } 231 routes->gsi[i] = ret; 232 routes->adapter.ind_offset++; 233 } 234 kvm_irqchip_commit_routes(kvm_state); 235 236 /* Restore passed-in structure to original state. */ 237 routes->adapter.ind_offset = ind_offset; 238 return 0; 239 out_undo: 240 while (--i >= 0) { 241 kvm_irqchip_release_virq(kvm_state, routes->gsi[i]); 242 routes->gsi[i] = -1; 243 } 244 routes->adapter.ind_offset = ind_offset; 245 return ret; 246 } 247 248 static void kvm_s390_release_adapter_routes(S390FLICState *fs, 249 AdapterRoutes *routes) 250 { 251 int i; 252 253 for (i = 0; i < routes->num_routes; i++) { 254 if (routes->gsi[i] >= 0) { 255 kvm_irqchip_release_virq(kvm_state, routes->gsi[i]); 256 routes->gsi[i] = -1; 257 } 258 } 259 } 260 261 /** 262 * kvm_flic_save - Save pending floating interrupts 263 * @f: QEMUFile containing migration state 264 * @opaque: pointer to flic device state 265 * 266 * Note: Pass buf and len to kernel. Start with one page and 267 * increase until buffer is sufficient or maxium size is 268 * reached 269 */ 270 static void kvm_flic_save(QEMUFile *f, void *opaque) 271 { 272 KVMS390FLICState *flic = opaque; 273 int len = FLIC_SAVE_INITIAL_SIZE; 274 void *buf; 275 int count; 276 277 flic_disable_wait_pfault((struct KVMS390FLICState *) opaque); 278 279 buf = g_try_malloc0(len); 280 if (!buf) { 281 /* Storing FLIC_FAILED into the count field here will cause the 282 * target system to fail when attempting to load irqs from the 283 * migration state */ 284 error_report("flic: couldn't allocate memory"); 285 qemu_put_be64(f, FLIC_FAILED); 286 return; 287 } 288 289 count = __get_all_irqs(flic, &buf, len); 290 if (count < 0) { 291 error_report("flic: couldn't retrieve irqs from kernel, rc %d", 292 count); 293 /* Storing FLIC_FAILED into the count field here will cause the 294 * target system to fail when attempting to load irqs from the 295 * migration state */ 296 qemu_put_be64(f, FLIC_FAILED); 297 } else { 298 qemu_put_be64(f, count); 299 qemu_put_buffer(f, (uint8_t *) buf, 300 count * sizeof(struct kvm_s390_irq)); 301 } 302 g_free(buf); 303 } 304 305 /** 306 * kvm_flic_load - Load pending floating interrupts 307 * @f: QEMUFile containing migration state 308 * @opaque: pointer to flic device state 309 * @version_id: version id for migration 310 * 311 * Returns: value of flic_enqueue_irqs, -EINVAL on error 312 * Note: Do nothing when no interrupts where stored 313 * in QEMUFile 314 */ 315 static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id) 316 { 317 uint64_t len = 0; 318 uint64_t count = 0; 319 void *buf = NULL; 320 int r = 0; 321 322 if (version_id != FLIC_SAVEVM_VERSION) { 323 r = -EINVAL; 324 goto out; 325 } 326 327 flic_enable_pfault((struct KVMS390FLICState *) opaque); 328 329 count = qemu_get_be64(f); 330 len = count * sizeof(struct kvm_s390_irq); 331 if (count == FLIC_FAILED) { 332 r = -EINVAL; 333 goto out; 334 } 335 if (count == 0) { 336 r = 0; 337 goto out; 338 } 339 buf = g_try_malloc0(len); 340 if (!buf) { 341 r = -ENOMEM; 342 goto out; 343 } 344 345 if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) { 346 r = -EINVAL; 347 goto out_free; 348 } 349 r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque); 350 351 out_free: 352 g_free(buf); 353 out: 354 return r; 355 } 356 357 static void kvm_s390_flic_realize(DeviceState *dev, Error **errp) 358 { 359 KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); 360 struct kvm_create_device cd = {0}; 361 int ret; 362 363 flic_state->fd = -1; 364 if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) { 365 trace_flic_no_device_api(errno); 366 return; 367 } 368 369 cd.type = KVM_DEV_TYPE_FLIC; 370 ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); 371 if (ret < 0) { 372 trace_flic_create_device(errno); 373 return; 374 } 375 flic_state->fd = cd.fd; 376 377 /* Register savevm handler for floating interrupts */ 378 register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save, 379 kvm_flic_load, (void *) flic_state); 380 } 381 382 static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp) 383 { 384 KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); 385 386 unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state); 387 } 388 389 static void kvm_s390_flic_reset(DeviceState *dev) 390 { 391 KVMS390FLICState *flic = KVM_S390_FLIC(dev); 392 struct kvm_device_attr attr = { 393 .group = KVM_DEV_FLIC_CLEAR_IRQS, 394 }; 395 int rc = 0; 396 397 if (flic->fd == -1) { 398 return; 399 } 400 401 flic_disable_wait_pfault(flic); 402 403 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 404 if (rc) { 405 trace_flic_reset_failed(errno); 406 } 407 408 flic_enable_pfault(flic); 409 } 410 411 static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) 412 { 413 DeviceClass *dc = DEVICE_CLASS(oc); 414 S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); 415 416 dc->realize = kvm_s390_flic_realize; 417 dc->unrealize = kvm_s390_flic_unrealize; 418 dc->reset = kvm_s390_flic_reset; 419 fsc->register_io_adapter = kvm_s390_register_io_adapter; 420 fsc->io_adapter_map = kvm_s390_io_adapter_map; 421 fsc->add_adapter_routes = kvm_s390_add_adapter_routes; 422 fsc->release_adapter_routes = kvm_s390_release_adapter_routes; 423 } 424 425 static const TypeInfo kvm_s390_flic_info = { 426 .name = TYPE_KVM_S390_FLIC, 427 .parent = TYPE_S390_FLIC_COMMON, 428 .instance_size = sizeof(KVMS390FLICState), 429 .class_init = kvm_s390_flic_class_init, 430 }; 431 432 static void kvm_s390_flic_register_types(void) 433 { 434 type_register_static(&kvm_s390_flic_info); 435 } 436 437 type_init(kvm_s390_flic_register_types) 438