xref: /openbmc/qemu/hw/intc/s390_flic_kvm.c (revision 2d7fedeb)
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