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