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