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