xref: /qemu/hw/intc/s390_flic_kvm.c (revision 7e018385)
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 "hw/s390x/s390_flic.h"
21 #include "hw/s390x/adapter.h"
22 #include "trace.h"
23 
24 #define FLIC_SAVE_INITIAL_SIZE getpagesize()
25 #define FLIC_FAILED (-1UL)
26 #define FLIC_SAVEVM_VERSION 1
27 
28 typedef struct KVMS390FLICState {
29     S390FLICState parent_obj;
30 
31     uint32_t fd;
32     bool clear_io_supported;
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 static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
134                            uint16_t subchannel_nr)
135 {
136     KVMS390FLICState *flic = KVM_S390_FLIC(fs);
137     int rc;
138     uint32_t sid = subchannel_id << 16 | subchannel_nr;
139     struct kvm_device_attr attr = {
140         .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
141         .addr = (uint64_t) &sid,
142         .attr = sizeof(sid),
143     };
144     if (unlikely(!flic->clear_io_supported)) {
145         return -ENOSYS;
146     }
147     rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
148     return rc ? -errno : 0;
149 }
150 
151 /**
152  * __get_all_irqs - store all pending irqs in buffer
153  * @flic: pointer to flic device state
154  * @buf: pointer to pointer to a buffer
155  * @len: length of buffer
156  *
157  * Returns: return value of flic_get_all_irqs
158  * Note: Retry and increase buffer size until flic_get_all_irqs
159  * either returns a value >= 0 or a negative error code.
160  * -ENOMEM is an exception, which means the buffer is too small
161  * and we should try again. Other negative error codes can be
162  * -EFAULT and -EINVAL which we ignore at this point
163  */
164 static int __get_all_irqs(KVMS390FLICState *flic,
165                           void **buf, int len)
166 {
167     int r;
168 
169     do {
170         /* returns -ENOMEM if buffer is too small and number
171          * of queued interrupts on success */
172         r = flic_get_all_irqs(flic, *buf, len);
173         if (r >= 0) {
174             break;
175         }
176         len *= 2;
177         *buf = g_try_realloc(*buf, len);
178         if (!buf) {
179             return -ENOMEM;
180         }
181     } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
182 
183     return r;
184 }
185 
186 static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
187                                         uint8_t isc, bool swap,
188                                         bool is_maskable)
189 {
190     struct kvm_s390_io_adapter adapter = {
191         .id = id,
192         .isc = isc,
193         .maskable = is_maskable,
194         .swap = swap,
195     };
196     KVMS390FLICState *flic = KVM_S390_FLIC(fs);
197     int r;
198     struct kvm_device_attr attr = {
199         .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
200         .addr = (uint64_t)&adapter,
201     };
202 
203     if (!kvm_gsi_routing_enabled()) {
204         /* nothing to do */
205         return 0;
206     }
207 
208     r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
209 
210     return r ? -errno : 0;
211 }
212 
213 static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
214                                    uint64_t map_addr, bool do_map)
215 {
216     struct kvm_s390_io_adapter_req req = {
217         .id = id,
218         .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
219         .addr = map_addr,
220     };
221     struct kvm_device_attr attr = {
222         .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
223         .addr = (uint64_t)&req,
224     };
225     KVMS390FLICState *flic = KVM_S390_FLIC(fs);
226     int r;
227 
228     if (!kvm_gsi_routing_enabled()) {
229         /* nothing to do */
230         return 0;
231     }
232 
233     r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
234     return r ? -errno : 0;
235 }
236 
237 static int kvm_s390_add_adapter_routes(S390FLICState *fs,
238                                        AdapterRoutes *routes)
239 {
240     int ret, i;
241     uint64_t ind_offset = routes->adapter.ind_offset;
242 
243     for (i = 0; i < routes->num_routes; i++) {
244         ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
245         if (ret < 0) {
246             goto out_undo;
247         }
248         routes->gsi[i] = ret;
249         routes->adapter.ind_offset++;
250     }
251     kvm_irqchip_commit_routes(kvm_state);
252 
253     /* Restore passed-in structure to original state. */
254     routes->adapter.ind_offset = ind_offset;
255     return 0;
256 out_undo:
257     while (--i >= 0) {
258         kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
259         routes->gsi[i] = -1;
260     }
261     routes->adapter.ind_offset = ind_offset;
262     return ret;
263 }
264 
265 static void kvm_s390_release_adapter_routes(S390FLICState *fs,
266                                             AdapterRoutes *routes)
267 {
268     int i;
269 
270     for (i = 0; i < routes->num_routes; i++) {
271         if (routes->gsi[i] >= 0) {
272             kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
273             routes->gsi[i] = -1;
274         }
275     }
276 }
277 
278 /**
279  * kvm_flic_save - Save pending floating interrupts
280  * @f: QEMUFile containing migration state
281  * @opaque: pointer to flic device state
282  * @size: ignored
283  *
284  * Note: Pass buf and len to kernel. Start with one page and
285  * increase until buffer is sufficient or maxium size is
286  * reached
287  */
288 static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
289                          VMStateField *field, QJSON *vmdesc)
290 {
291     KVMS390FLICState *flic = opaque;
292     int len = FLIC_SAVE_INITIAL_SIZE;
293     void *buf;
294     int count;
295     int r = 0;
296 
297     flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
298 
299     buf = g_try_malloc0(len);
300     if (!buf) {
301         /* Storing FLIC_FAILED into the count field here will cause the
302          * target system to fail when attempting to load irqs from the
303          * migration state */
304         error_report("flic: couldn't allocate memory");
305         qemu_put_be64(f, FLIC_FAILED);
306         return -ENOMEM;
307     }
308 
309     count = __get_all_irqs(flic, &buf, len);
310     if (count < 0) {
311         error_report("flic: couldn't retrieve irqs from kernel, rc %d",
312                      count);
313         /* Storing FLIC_FAILED into the count field here will cause the
314          * target system to fail when attempting to load irqs from the
315          * migration state */
316         qemu_put_be64(f, FLIC_FAILED);
317         r = count;
318     } else {
319         qemu_put_be64(f, count);
320         qemu_put_buffer(f, (uint8_t *) buf,
321                         count * sizeof(struct kvm_s390_irq));
322     }
323     g_free(buf);
324 
325     return r;
326 }
327 
328 /**
329  * kvm_flic_load - Load pending floating interrupts
330  * @f: QEMUFile containing migration state
331  * @opaque: pointer to flic device state
332  * @size: ignored
333  *
334  * Returns: value of flic_enqueue_irqs, -EINVAL on error
335  * Note: Do nothing when no interrupts where stored
336  * in QEMUFile
337  */
338 static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size,
339                          VMStateField *field)
340 {
341     uint64_t len = 0;
342     uint64_t count = 0;
343     void *buf = NULL;
344     int r = 0;
345 
346     flic_enable_pfault((struct KVMS390FLICState *) opaque);
347 
348     count = qemu_get_be64(f);
349     len = count * sizeof(struct kvm_s390_irq);
350     if (count == FLIC_FAILED) {
351         r = -EINVAL;
352         goto out;
353     }
354     if (count == 0) {
355         r = 0;
356         goto out;
357     }
358     buf = g_try_malloc0(len);
359     if (!buf) {
360         r = -ENOMEM;
361         goto out;
362     }
363 
364     if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
365         r = -EINVAL;
366         goto out_free;
367     }
368     r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
369 
370 out_free:
371     g_free(buf);
372 out:
373     return r;
374 }
375 
376 static const VMStateDescription kvm_s390_flic_vmstate = {
377     .name = "s390-flic",
378     .version_id = FLIC_SAVEVM_VERSION,
379     .minimum_version_id = FLIC_SAVEVM_VERSION,
380     .fields = (VMStateField[]) {
381         {
382             .name = "irqs",
383             .info = &(const VMStateInfo) {
384                 .name = "irqs",
385                 .get = kvm_flic_load,
386                 .put = kvm_flic_save,
387             },
388             .flags = VMS_SINGLE,
389         },
390         VMSTATE_END_OF_LIST()
391     }
392 };
393 
394 static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
395 {
396     KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
397     struct kvm_create_device cd = {0};
398     struct kvm_device_attr test_attr = {0};
399     int ret;
400 
401     flic_state->fd = -1;
402     if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
403         trace_flic_no_device_api(errno);
404         return;
405     }
406 
407     cd.type = KVM_DEV_TYPE_FLIC;
408     ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
409     if (ret < 0) {
410         trace_flic_create_device(errno);
411         return;
412     }
413     flic_state->fd = cd.fd;
414 
415     /* Check clear_io_irq support */
416     test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
417     flic_state->clear_io_supported = !ioctl(flic_state->fd,
418                                             KVM_HAS_DEVICE_ATTR, test_attr);
419 
420 }
421 
422 static void kvm_s390_flic_reset(DeviceState *dev)
423 {
424     KVMS390FLICState *flic = KVM_S390_FLIC(dev);
425     struct kvm_device_attr attr = {
426         .group = KVM_DEV_FLIC_CLEAR_IRQS,
427     };
428     int rc = 0;
429 
430     if (flic->fd == -1) {
431         return;
432     }
433 
434     flic_disable_wait_pfault(flic);
435 
436     rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
437     if (rc) {
438         trace_flic_reset_failed(errno);
439     }
440 
441     flic_enable_pfault(flic);
442 }
443 
444 static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
445 {
446     DeviceClass *dc = DEVICE_CLASS(oc);
447     S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
448 
449     dc->realize = kvm_s390_flic_realize;
450     dc->vmsd = &kvm_s390_flic_vmstate;
451     dc->reset = kvm_s390_flic_reset;
452     fsc->register_io_adapter = kvm_s390_register_io_adapter;
453     fsc->io_adapter_map = kvm_s390_io_adapter_map;
454     fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
455     fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
456     fsc->clear_io_irq = kvm_s390_clear_io_flic;
457 }
458 
459 static const TypeInfo kvm_s390_flic_info = {
460     .name          = TYPE_KVM_S390_FLIC,
461     .parent        = TYPE_S390_FLIC_COMMON,
462     .instance_size = sizeof(KVMS390FLICState),
463     .class_init    = kvm_s390_flic_class_init,
464 };
465 
466 static void kvm_s390_flic_register_types(void)
467 {
468     type_register_static(&kvm_s390_flic_info);
469 }
470 
471 type_init(kvm_s390_flic_register_types)
472