1*7b35d0c4SCornelia Huck /* 2*7b35d0c4SCornelia Huck * QEMU S390x KVM floating interrupt controller (flic) 3*7b35d0c4SCornelia Huck * 4*7b35d0c4SCornelia Huck * Copyright 2014 IBM Corp. 5*7b35d0c4SCornelia Huck * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com> 6*7b35d0c4SCornelia Huck * Cornelia Huck <cornelia.huck@de.ibm.com> 7*7b35d0c4SCornelia Huck * 8*7b35d0c4SCornelia Huck * This work is licensed under the terms of the GNU GPL, version 2 or (at 9*7b35d0c4SCornelia Huck * your option) any later version. See the COPYING file in the top-level 10*7b35d0c4SCornelia Huck * directory. 11*7b35d0c4SCornelia Huck */ 12*7b35d0c4SCornelia Huck 13*7b35d0c4SCornelia Huck #include <sys/ioctl.h> 14*7b35d0c4SCornelia Huck #include "qemu/error-report.h" 15*7b35d0c4SCornelia Huck #include "hw/sysbus.h" 16*7b35d0c4SCornelia Huck #include "sysemu/kvm.h" 17*7b35d0c4SCornelia Huck #include "migration/qemu-file.h" 18*7b35d0c4SCornelia Huck #include "hw/s390x/s390_flic.h" 19*7b35d0c4SCornelia Huck #include "trace.h" 20*7b35d0c4SCornelia Huck 21*7b35d0c4SCornelia Huck #define FLIC_SAVE_INITIAL_SIZE getpagesize() 22*7b35d0c4SCornelia Huck #define FLIC_FAILED (-1UL) 23*7b35d0c4SCornelia Huck #define FLIC_SAVEVM_VERSION 1 24*7b35d0c4SCornelia Huck 25*7b35d0c4SCornelia Huck typedef struct KVMS390FLICState { 26*7b35d0c4SCornelia Huck S390FLICState parent_obj; 27*7b35d0c4SCornelia Huck 28*7b35d0c4SCornelia Huck uint32_t fd; 29*7b35d0c4SCornelia Huck } KVMS390FLICState; 30*7b35d0c4SCornelia Huck 31*7b35d0c4SCornelia Huck DeviceState *s390_flic_kvm_create(void) 32*7b35d0c4SCornelia Huck { 33*7b35d0c4SCornelia Huck DeviceState *dev = NULL; 34*7b35d0c4SCornelia Huck 35*7b35d0c4SCornelia Huck if (kvm_enabled()) { 36*7b35d0c4SCornelia Huck dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); 37*7b35d0c4SCornelia Huck object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, 38*7b35d0c4SCornelia Huck OBJECT(dev), NULL); 39*7b35d0c4SCornelia Huck } 40*7b35d0c4SCornelia Huck return dev; 41*7b35d0c4SCornelia Huck } 42*7b35d0c4SCornelia Huck 43*7b35d0c4SCornelia Huck /** 44*7b35d0c4SCornelia Huck * flic_get_all_irqs - store all pending irqs in buffer 45*7b35d0c4SCornelia Huck * @buf: pointer to buffer which is passed to kernel 46*7b35d0c4SCornelia Huck * @len: length of buffer 47*7b35d0c4SCornelia Huck * @flic: pointer to flic device state 48*7b35d0c4SCornelia Huck * 49*7b35d0c4SCornelia Huck * Returns: -ENOMEM if buffer is too small, 50*7b35d0c4SCornelia Huck * -EINVAL if attr.group is invalid, 51*7b35d0c4SCornelia Huck * -EFAULT if copying to userspace failed, 52*7b35d0c4SCornelia Huck * on success return number of stored interrupts 53*7b35d0c4SCornelia Huck */ 54*7b35d0c4SCornelia Huck static int flic_get_all_irqs(KVMS390FLICState *flic, 55*7b35d0c4SCornelia Huck void *buf, int len) 56*7b35d0c4SCornelia Huck { 57*7b35d0c4SCornelia Huck struct kvm_device_attr attr = { 58*7b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_GET_ALL_IRQS, 59*7b35d0c4SCornelia Huck .addr = (uint64_t) buf, 60*7b35d0c4SCornelia Huck .attr = len, 61*7b35d0c4SCornelia Huck }; 62*7b35d0c4SCornelia Huck int rc; 63*7b35d0c4SCornelia Huck 64*7b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr); 65*7b35d0c4SCornelia Huck 66*7b35d0c4SCornelia Huck return rc == -1 ? -errno : rc; 67*7b35d0c4SCornelia Huck } 68*7b35d0c4SCornelia Huck 69*7b35d0c4SCornelia Huck static void flic_enable_pfault(KVMS390FLICState *flic) 70*7b35d0c4SCornelia Huck { 71*7b35d0c4SCornelia Huck struct kvm_device_attr attr = { 72*7b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_APF_ENABLE, 73*7b35d0c4SCornelia Huck }; 74*7b35d0c4SCornelia Huck int rc; 75*7b35d0c4SCornelia Huck 76*7b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 77*7b35d0c4SCornelia Huck 78*7b35d0c4SCornelia Huck if (rc) { 79*7b35d0c4SCornelia Huck fprintf(stderr, "flic: couldn't enable pfault\n"); 80*7b35d0c4SCornelia Huck } 81*7b35d0c4SCornelia Huck } 82*7b35d0c4SCornelia Huck 83*7b35d0c4SCornelia Huck static void flic_disable_wait_pfault(KVMS390FLICState *flic) 84*7b35d0c4SCornelia Huck { 85*7b35d0c4SCornelia Huck struct kvm_device_attr attr = { 86*7b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_APF_DISABLE_WAIT, 87*7b35d0c4SCornelia Huck }; 88*7b35d0c4SCornelia Huck int rc; 89*7b35d0c4SCornelia Huck 90*7b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 91*7b35d0c4SCornelia Huck 92*7b35d0c4SCornelia Huck if (rc) { 93*7b35d0c4SCornelia Huck fprintf(stderr, "flic: couldn't disable pfault\n"); 94*7b35d0c4SCornelia Huck } 95*7b35d0c4SCornelia Huck } 96*7b35d0c4SCornelia Huck 97*7b35d0c4SCornelia Huck /** flic_enqueue_irqs - returns 0 on success 98*7b35d0c4SCornelia Huck * @buf: pointer to buffer which is passed to kernel 99*7b35d0c4SCornelia Huck * @len: length of buffer 100*7b35d0c4SCornelia Huck * @flic: pointer to flic device state 101*7b35d0c4SCornelia Huck * 102*7b35d0c4SCornelia Huck * Returns: -EINVAL if attr.group is unknown 103*7b35d0c4SCornelia Huck */ 104*7b35d0c4SCornelia Huck static int flic_enqueue_irqs(void *buf, uint64_t len, 105*7b35d0c4SCornelia Huck KVMS390FLICState *flic) 106*7b35d0c4SCornelia Huck { 107*7b35d0c4SCornelia Huck int rc; 108*7b35d0c4SCornelia Huck struct kvm_device_attr attr = { 109*7b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_ENQUEUE, 110*7b35d0c4SCornelia Huck .addr = (uint64_t) buf, 111*7b35d0c4SCornelia Huck .attr = len, 112*7b35d0c4SCornelia Huck }; 113*7b35d0c4SCornelia Huck 114*7b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 115*7b35d0c4SCornelia Huck 116*7b35d0c4SCornelia Huck return rc ? -errno : 0; 117*7b35d0c4SCornelia Huck } 118*7b35d0c4SCornelia Huck 119*7b35d0c4SCornelia Huck /** 120*7b35d0c4SCornelia Huck * __get_all_irqs - store all pending irqs in buffer 121*7b35d0c4SCornelia Huck * @flic: pointer to flic device state 122*7b35d0c4SCornelia Huck * @buf: pointer to pointer to a buffer 123*7b35d0c4SCornelia Huck * @len: length of buffer 124*7b35d0c4SCornelia Huck * 125*7b35d0c4SCornelia Huck * Returns: return value of flic_get_all_irqs 126*7b35d0c4SCornelia Huck * Note: Retry and increase buffer size until flic_get_all_irqs 127*7b35d0c4SCornelia Huck * either returns a value >= 0 or a negative error code. 128*7b35d0c4SCornelia Huck * -ENOMEM is an exception, which means the buffer is too small 129*7b35d0c4SCornelia Huck * and we should try again. Other negative error codes can be 130*7b35d0c4SCornelia Huck * -EFAULT and -EINVAL which we ignore at this point 131*7b35d0c4SCornelia Huck */ 132*7b35d0c4SCornelia Huck static int __get_all_irqs(KVMS390FLICState *flic, 133*7b35d0c4SCornelia Huck void **buf, int len) 134*7b35d0c4SCornelia Huck { 135*7b35d0c4SCornelia Huck int r; 136*7b35d0c4SCornelia Huck 137*7b35d0c4SCornelia Huck do { 138*7b35d0c4SCornelia Huck /* returns -ENOMEM if buffer is too small and number 139*7b35d0c4SCornelia Huck * of queued interrupts on success */ 140*7b35d0c4SCornelia Huck r = flic_get_all_irqs(flic, *buf, len); 141*7b35d0c4SCornelia Huck if (r >= 0) { 142*7b35d0c4SCornelia Huck break; 143*7b35d0c4SCornelia Huck } 144*7b35d0c4SCornelia Huck len *= 2; 145*7b35d0c4SCornelia Huck *buf = g_try_realloc(*buf, len); 146*7b35d0c4SCornelia Huck if (!buf) { 147*7b35d0c4SCornelia Huck return -ENOMEM; 148*7b35d0c4SCornelia Huck } 149*7b35d0c4SCornelia Huck } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER); 150*7b35d0c4SCornelia Huck 151*7b35d0c4SCornelia Huck return r; 152*7b35d0c4SCornelia Huck } 153*7b35d0c4SCornelia Huck 154*7b35d0c4SCornelia Huck /** 155*7b35d0c4SCornelia Huck * kvm_flic_save - Save pending floating interrupts 156*7b35d0c4SCornelia Huck * @f: QEMUFile containing migration state 157*7b35d0c4SCornelia Huck * @opaque: pointer to flic device state 158*7b35d0c4SCornelia Huck * 159*7b35d0c4SCornelia Huck * Note: Pass buf and len to kernel. Start with one page and 160*7b35d0c4SCornelia Huck * increase until buffer is sufficient or maxium size is 161*7b35d0c4SCornelia Huck * reached 162*7b35d0c4SCornelia Huck */ 163*7b35d0c4SCornelia Huck static void kvm_flic_save(QEMUFile *f, void *opaque) 164*7b35d0c4SCornelia Huck { 165*7b35d0c4SCornelia Huck KVMS390FLICState *flic = opaque; 166*7b35d0c4SCornelia Huck int len = FLIC_SAVE_INITIAL_SIZE; 167*7b35d0c4SCornelia Huck void *buf; 168*7b35d0c4SCornelia Huck int count; 169*7b35d0c4SCornelia Huck 170*7b35d0c4SCornelia Huck flic_disable_wait_pfault((struct KVMS390FLICState *) opaque); 171*7b35d0c4SCornelia Huck 172*7b35d0c4SCornelia Huck buf = g_try_malloc0(len); 173*7b35d0c4SCornelia Huck if (!buf) { 174*7b35d0c4SCornelia Huck /* Storing FLIC_FAILED into the count field here will cause the 175*7b35d0c4SCornelia Huck * target system to fail when attempting to load irqs from the 176*7b35d0c4SCornelia Huck * migration state */ 177*7b35d0c4SCornelia Huck error_report("flic: couldn't allocate memory"); 178*7b35d0c4SCornelia Huck qemu_put_be64(f, FLIC_FAILED); 179*7b35d0c4SCornelia Huck return; 180*7b35d0c4SCornelia Huck } 181*7b35d0c4SCornelia Huck 182*7b35d0c4SCornelia Huck count = __get_all_irqs(flic, &buf, len); 183*7b35d0c4SCornelia Huck if (count < 0) { 184*7b35d0c4SCornelia Huck error_report("flic: couldn't retrieve irqs from kernel, rc %d", 185*7b35d0c4SCornelia Huck count); 186*7b35d0c4SCornelia Huck /* Storing FLIC_FAILED into the count field here will cause the 187*7b35d0c4SCornelia Huck * target system to fail when attempting to load irqs from the 188*7b35d0c4SCornelia Huck * migration state */ 189*7b35d0c4SCornelia Huck qemu_put_be64(f, FLIC_FAILED); 190*7b35d0c4SCornelia Huck } else { 191*7b35d0c4SCornelia Huck qemu_put_be64(f, count); 192*7b35d0c4SCornelia Huck qemu_put_buffer(f, (uint8_t *) buf, 193*7b35d0c4SCornelia Huck count * sizeof(struct kvm_s390_irq)); 194*7b35d0c4SCornelia Huck } 195*7b35d0c4SCornelia Huck g_free(buf); 196*7b35d0c4SCornelia Huck } 197*7b35d0c4SCornelia Huck 198*7b35d0c4SCornelia Huck /** 199*7b35d0c4SCornelia Huck * kvm_flic_load - Load pending floating interrupts 200*7b35d0c4SCornelia Huck * @f: QEMUFile containing migration state 201*7b35d0c4SCornelia Huck * @opaque: pointer to flic device state 202*7b35d0c4SCornelia Huck * @version_id: version id for migration 203*7b35d0c4SCornelia Huck * 204*7b35d0c4SCornelia Huck * Returns: value of flic_enqueue_irqs, -EINVAL on error 205*7b35d0c4SCornelia Huck * Note: Do nothing when no interrupts where stored 206*7b35d0c4SCornelia Huck * in QEMUFile 207*7b35d0c4SCornelia Huck */ 208*7b35d0c4SCornelia Huck static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id) 209*7b35d0c4SCornelia Huck { 210*7b35d0c4SCornelia Huck uint64_t len = 0; 211*7b35d0c4SCornelia Huck uint64_t count = 0; 212*7b35d0c4SCornelia Huck void *buf = NULL; 213*7b35d0c4SCornelia Huck int r = 0; 214*7b35d0c4SCornelia Huck 215*7b35d0c4SCornelia Huck if (version_id != FLIC_SAVEVM_VERSION) { 216*7b35d0c4SCornelia Huck r = -EINVAL; 217*7b35d0c4SCornelia Huck goto out; 218*7b35d0c4SCornelia Huck } 219*7b35d0c4SCornelia Huck 220*7b35d0c4SCornelia Huck flic_enable_pfault((struct KVMS390FLICState *) opaque); 221*7b35d0c4SCornelia Huck 222*7b35d0c4SCornelia Huck count = qemu_get_be64(f); 223*7b35d0c4SCornelia Huck len = count * sizeof(struct kvm_s390_irq); 224*7b35d0c4SCornelia Huck if (count == FLIC_FAILED) { 225*7b35d0c4SCornelia Huck r = -EINVAL; 226*7b35d0c4SCornelia Huck goto out; 227*7b35d0c4SCornelia Huck } 228*7b35d0c4SCornelia Huck if (count == 0) { 229*7b35d0c4SCornelia Huck r = 0; 230*7b35d0c4SCornelia Huck goto out; 231*7b35d0c4SCornelia Huck } 232*7b35d0c4SCornelia Huck buf = g_try_malloc0(len); 233*7b35d0c4SCornelia Huck if (!buf) { 234*7b35d0c4SCornelia Huck r = -ENOMEM; 235*7b35d0c4SCornelia Huck goto out; 236*7b35d0c4SCornelia Huck } 237*7b35d0c4SCornelia Huck 238*7b35d0c4SCornelia Huck if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) { 239*7b35d0c4SCornelia Huck r = -EINVAL; 240*7b35d0c4SCornelia Huck goto out_free; 241*7b35d0c4SCornelia Huck } 242*7b35d0c4SCornelia Huck r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque); 243*7b35d0c4SCornelia Huck 244*7b35d0c4SCornelia Huck out_free: 245*7b35d0c4SCornelia Huck g_free(buf); 246*7b35d0c4SCornelia Huck out: 247*7b35d0c4SCornelia Huck return r; 248*7b35d0c4SCornelia Huck } 249*7b35d0c4SCornelia Huck 250*7b35d0c4SCornelia Huck static void kvm_s390_flic_realize(DeviceState *dev, Error **errp) 251*7b35d0c4SCornelia Huck { 252*7b35d0c4SCornelia Huck KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); 253*7b35d0c4SCornelia Huck struct kvm_create_device cd = {0}; 254*7b35d0c4SCornelia Huck int ret; 255*7b35d0c4SCornelia Huck 256*7b35d0c4SCornelia Huck flic_state->fd = -1; 257*7b35d0c4SCornelia Huck if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) { 258*7b35d0c4SCornelia Huck trace_flic_no_device_api(errno); 259*7b35d0c4SCornelia Huck return; 260*7b35d0c4SCornelia Huck } 261*7b35d0c4SCornelia Huck 262*7b35d0c4SCornelia Huck cd.type = KVM_DEV_TYPE_FLIC; 263*7b35d0c4SCornelia Huck ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd); 264*7b35d0c4SCornelia Huck if (ret < 0) { 265*7b35d0c4SCornelia Huck trace_flic_create_device(errno); 266*7b35d0c4SCornelia Huck return; 267*7b35d0c4SCornelia Huck } 268*7b35d0c4SCornelia Huck flic_state->fd = cd.fd; 269*7b35d0c4SCornelia Huck 270*7b35d0c4SCornelia Huck /* Register savevm handler for floating interrupts */ 271*7b35d0c4SCornelia Huck register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save, 272*7b35d0c4SCornelia Huck kvm_flic_load, (void *) flic_state); 273*7b35d0c4SCornelia Huck } 274*7b35d0c4SCornelia Huck 275*7b35d0c4SCornelia Huck static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp) 276*7b35d0c4SCornelia Huck { 277*7b35d0c4SCornelia Huck KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); 278*7b35d0c4SCornelia Huck 279*7b35d0c4SCornelia Huck unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state); 280*7b35d0c4SCornelia Huck } 281*7b35d0c4SCornelia Huck 282*7b35d0c4SCornelia Huck static void kvm_s390_flic_reset(DeviceState *dev) 283*7b35d0c4SCornelia Huck { 284*7b35d0c4SCornelia Huck KVMS390FLICState *flic = KVM_S390_FLIC(dev); 285*7b35d0c4SCornelia Huck struct kvm_device_attr attr = { 286*7b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_CLEAR_IRQS, 287*7b35d0c4SCornelia Huck }; 288*7b35d0c4SCornelia Huck int rc = 0; 289*7b35d0c4SCornelia Huck 290*7b35d0c4SCornelia Huck if (flic->fd == -1) { 291*7b35d0c4SCornelia Huck return; 292*7b35d0c4SCornelia Huck } 293*7b35d0c4SCornelia Huck 294*7b35d0c4SCornelia Huck flic_disable_wait_pfault(flic); 295*7b35d0c4SCornelia Huck 296*7b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); 297*7b35d0c4SCornelia Huck if (rc) { 298*7b35d0c4SCornelia Huck trace_flic_reset_failed(errno); 299*7b35d0c4SCornelia Huck } 300*7b35d0c4SCornelia Huck 301*7b35d0c4SCornelia Huck flic_enable_pfault(flic); 302*7b35d0c4SCornelia Huck } 303*7b35d0c4SCornelia Huck 304*7b35d0c4SCornelia Huck static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) 305*7b35d0c4SCornelia Huck { 306*7b35d0c4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(oc); 307*7b35d0c4SCornelia Huck 308*7b35d0c4SCornelia Huck dc->realize = kvm_s390_flic_realize; 309*7b35d0c4SCornelia Huck dc->unrealize = kvm_s390_flic_unrealize; 310*7b35d0c4SCornelia Huck dc->reset = kvm_s390_flic_reset; 311*7b35d0c4SCornelia Huck } 312*7b35d0c4SCornelia Huck 313*7b35d0c4SCornelia Huck static const TypeInfo kvm_s390_flic_info = { 314*7b35d0c4SCornelia Huck .name = TYPE_KVM_S390_FLIC, 315*7b35d0c4SCornelia Huck .parent = TYPE_S390_FLIC_COMMON, 316*7b35d0c4SCornelia Huck .instance_size = sizeof(KVMS390FLICState), 317*7b35d0c4SCornelia Huck .class_init = kvm_s390_flic_class_init, 318*7b35d0c4SCornelia Huck }; 319*7b35d0c4SCornelia Huck 320*7b35d0c4SCornelia Huck static void kvm_s390_flic_register_types(void) 321*7b35d0c4SCornelia Huck { 322*7b35d0c4SCornelia Huck type_register_static(&kvm_s390_flic_info); 323*7b35d0c4SCornelia Huck } 324*7b35d0c4SCornelia Huck 325*7b35d0c4SCornelia Huck type_init(kvm_s390_flic_register_types) 326