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