xref: /openbmc/qemu/hw/intc/s390_flic_kvm.c (revision acb0ef58)
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     /* Restore passed-in structure to original state. */
232     routes->adapter.ind_offset = ind_offset;
233     return 0;
234 out_undo:
235     while (--i >= 0) {
236         kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
237         routes->gsi[i] = -1;
238     }
239     routes->adapter.ind_offset = ind_offset;
240     return ret;
241 }
242 
243 static void kvm_s390_release_adapter_routes(S390FLICState *fs,
244                                             AdapterRoutes *routes)
245 {
246     int i;
247 
248     for (i = 0; i < routes->num_routes; i++) {
249         if (routes->gsi[i] >= 0) {
250             kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
251             routes->gsi[i] = -1;
252         }
253     }
254 }
255 
256 /**
257  * kvm_flic_save - Save pending floating interrupts
258  * @f: QEMUFile containing migration state
259  * @opaque: pointer to flic device state
260  *
261  * Note: Pass buf and len to kernel. Start with one page and
262  * increase until buffer is sufficient or maxium size is
263  * reached
264  */
265 static void kvm_flic_save(QEMUFile *f, void *opaque)
266 {
267     KVMS390FLICState *flic = opaque;
268     int len = FLIC_SAVE_INITIAL_SIZE;
269     void *buf;
270     int count;
271 
272     flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
273 
274     buf = g_try_malloc0(len);
275     if (!buf) {
276         /* Storing FLIC_FAILED into the count field here will cause the
277          * target system to fail when attempting to load irqs from the
278          * migration state */
279         error_report("flic: couldn't allocate memory");
280         qemu_put_be64(f, FLIC_FAILED);
281         return;
282     }
283 
284     count = __get_all_irqs(flic, &buf, len);
285     if (count < 0) {
286         error_report("flic: couldn't retrieve irqs from kernel, rc %d",
287                      count);
288         /* Storing FLIC_FAILED into the count field here will cause the
289          * target system to fail when attempting to load irqs from the
290          * migration state */
291         qemu_put_be64(f, FLIC_FAILED);
292     } else {
293         qemu_put_be64(f, count);
294         qemu_put_buffer(f, (uint8_t *) buf,
295                         count * sizeof(struct kvm_s390_irq));
296     }
297     g_free(buf);
298 }
299 
300 /**
301  * kvm_flic_load - Load pending floating interrupts
302  * @f: QEMUFile containing migration state
303  * @opaque: pointer to flic device state
304  * @version_id: version id for migration
305  *
306  * Returns: value of flic_enqueue_irqs, -EINVAL on error
307  * Note: Do nothing when no interrupts where stored
308  * in QEMUFile
309  */
310 static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
311 {
312     uint64_t len = 0;
313     uint64_t count = 0;
314     void *buf = NULL;
315     int r = 0;
316 
317     if (version_id != FLIC_SAVEVM_VERSION) {
318         r = -EINVAL;
319         goto out;
320     }
321 
322     flic_enable_pfault((struct KVMS390FLICState *) opaque);
323 
324     count = qemu_get_be64(f);
325     len = count * sizeof(struct kvm_s390_irq);
326     if (count == FLIC_FAILED) {
327         r = -EINVAL;
328         goto out;
329     }
330     if (count == 0) {
331         r = 0;
332         goto out;
333     }
334     buf = g_try_malloc0(len);
335     if (!buf) {
336         r = -ENOMEM;
337         goto out;
338     }
339 
340     if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
341         r = -EINVAL;
342         goto out_free;
343     }
344     r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
345 
346 out_free:
347     g_free(buf);
348 out:
349     return r;
350 }
351 
352 static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
353 {
354     KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
355     struct kvm_create_device cd = {0};
356     int ret;
357 
358     flic_state->fd = -1;
359     if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
360         trace_flic_no_device_api(errno);
361         return;
362     }
363 
364     cd.type = KVM_DEV_TYPE_FLIC;
365     ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
366     if (ret < 0) {
367         trace_flic_create_device(errno);
368         return;
369     }
370     flic_state->fd = cd.fd;
371 
372     /* Register savevm handler for floating interrupts */
373     register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
374                     kvm_flic_load, (void *) flic_state);
375 }
376 
377 static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
378 {
379     KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
380 
381     unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
382 }
383 
384 static void kvm_s390_flic_reset(DeviceState *dev)
385 {
386     KVMS390FLICState *flic = KVM_S390_FLIC(dev);
387     struct kvm_device_attr attr = {
388         .group = KVM_DEV_FLIC_CLEAR_IRQS,
389     };
390     int rc = 0;
391 
392     if (flic->fd == -1) {
393         return;
394     }
395 
396     flic_disable_wait_pfault(flic);
397 
398     rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
399     if (rc) {
400         trace_flic_reset_failed(errno);
401     }
402 
403     flic_enable_pfault(flic);
404 }
405 
406 static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
407 {
408     DeviceClass *dc = DEVICE_CLASS(oc);
409     S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
410 
411     dc->realize = kvm_s390_flic_realize;
412     dc->unrealize = kvm_s390_flic_unrealize;
413     dc->reset = kvm_s390_flic_reset;
414     fsc->register_io_adapter = kvm_s390_register_io_adapter;
415     fsc->io_adapter_map = kvm_s390_io_adapter_map;
416     fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
417     fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
418 }
419 
420 static const TypeInfo kvm_s390_flic_info = {
421     .name          = TYPE_KVM_S390_FLIC,
422     .parent        = TYPE_S390_FLIC_COMMON,
423     .instance_size = sizeof(KVMS390FLICState),
424     .class_init    = kvm_s390_flic_class_init,
425 };
426 
427 static void kvm_s390_flic_register_types(void)
428 {
429     type_register_static(&kvm_s390_flic_info);
430 }
431 
432 type_init(kvm_s390_flic_register_types)
433