]> Git Repo - qemu.git/blame - hw/intc/s390_flic_kvm.c
s390x/tcg: simplify machine check handling
[qemu.git] / hw / intc / s390_flic_kvm.c
CommitLineData
7b35d0c4
CH
1/*
2 * QEMU S390x KVM floating interrupt controller (flic)
3 *
4 * Copyright 2014 IBM Corp.
5 * Author(s): Jens Freimann <[email protected]>
6 * Cornelia Huck <[email protected]>
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
90191d07 13#include "qemu/osdep.h"
33c11879
PB
14#include "qemu-common.h"
15#include "cpu.h"
f16bbb9b 16#include "kvm_s390x.h"
7b35d0c4
CH
17#include <sys/ioctl.h>
18#include "qemu/error-report.h"
f62f2109 19#include "qapi/error.h"
7b35d0c4
CH
20#include "hw/sysbus.h"
21#include "sysemu/kvm.h"
7b35d0c4 22#include "hw/s390x/s390_flic.h"
d426d9fb 23#include "hw/s390x/adapter.h"
6c1dd652 24#include "hw/s390x/css.h"
7b35d0c4
CH
25#include "trace.h"
26
27#define FLIC_SAVE_INITIAL_SIZE getpagesize()
28#define FLIC_FAILED (-1UL)
29#define FLIC_SAVEVM_VERSION 1
30
31typedef struct KVMS390FLICState {
32 S390FLICState parent_obj;
33
34 uint32_t fd;
9eccb862 35 bool clear_io_supported;
7b35d0c4
CH
36} KVMS390FLICState;
37
7b35d0c4
CH
38/**
39 * flic_get_all_irqs - store all pending irqs in buffer
40 * @buf: pointer to buffer which is passed to kernel
41 * @len: length of buffer
42 * @flic: pointer to flic device state
43 *
44 * Returns: -ENOMEM if buffer is too small,
45 * -EINVAL if attr.group is invalid,
46 * -EFAULT if copying to userspace failed,
47 * on success return number of stored interrupts
48 */
49static int flic_get_all_irqs(KVMS390FLICState *flic,
50 void *buf, int len)
51{
52 struct kvm_device_attr attr = {
53 .group = KVM_DEV_FLIC_GET_ALL_IRQS,
54 .addr = (uint64_t) buf,
55 .attr = len,
56 };
57 int rc;
58
59 rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
60
61 return rc == -1 ? -errno : rc;
62}
63
64static void flic_enable_pfault(KVMS390FLICState *flic)
65{
66 struct kvm_device_attr attr = {
67 .group = KVM_DEV_FLIC_APF_ENABLE,
68 };
69 int rc;
70
71 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
72
73 if (rc) {
74 fprintf(stderr, "flic: couldn't enable pfault\n");
75 }
76}
77
78static void flic_disable_wait_pfault(KVMS390FLICState *flic)
79{
80 struct kvm_device_attr attr = {
81 .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
82 };
83 int rc;
84
85 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
86
87 if (rc) {
88 fprintf(stderr, "flic: couldn't disable pfault\n");
89 }
90}
91
92/** flic_enqueue_irqs - returns 0 on success
93 * @buf: pointer to buffer which is passed to kernel
94 * @len: length of buffer
95 * @flic: pointer to flic device state
96 *
97 * Returns: -EINVAL if attr.group is unknown
98 */
99static int flic_enqueue_irqs(void *buf, uint64_t len,
100 KVMS390FLICState *flic)
101{
102 int rc;
103 struct kvm_device_attr attr = {
104 .group = KVM_DEV_FLIC_ENQUEUE,
105 .addr = (uint64_t) buf,
106 .attr = len,
107 };
108
109 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
110
111 return rc ? -errno : 0;
112}
113
bbd8bb8e
CH
114int kvm_s390_inject_flic(struct kvm_s390_irq *irq)
115{
116 static KVMS390FLICState *flic;
117
118 if (unlikely(!flic)) {
119 flic = KVM_S390_FLIC(s390_get_flic());
120 }
121 return flic_enqueue_irqs(irq, sizeof(*irq), flic);
122}
123
9eccb862
HP
124static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
125 uint16_t subchannel_nr)
126{
127 KVMS390FLICState *flic = KVM_S390_FLIC(fs);
128 int rc;
129 uint32_t sid = subchannel_id << 16 | subchannel_nr;
130 struct kvm_device_attr attr = {
131 .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
132 .addr = (uint64_t) &sid,
133 .attr = sizeof(sid),
134 };
135 if (unlikely(!flic->clear_io_supported)) {
136 return -ENOSYS;
137 }
138 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
139 return rc ? -errno : 0;
140}
141
6c1dd652
FL
142static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
143 uint16_t mode)
144{
145 KVMS390FLICState *flic = KVM_S390_FLIC(fs);
146 struct kvm_s390_ais_req req = {
147 .isc = isc,
148 .mode = mode,
149 };
150 struct kvm_device_attr attr = {
151 .group = KVM_DEV_FLIC_AISM,
152 .addr = (uint64_t)&req,
153 };
154
155 if (!fs->ais_supported) {
156 return -ENOSYS;
157 }
158
159 return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
160}
161
1622ffd5
YMZ
162static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
163 uint8_t isc, uint8_t flags)
164{
165 KVMS390FLICState *flic = KVM_S390_FLIC(fs);
166 uint32_t id = css_get_adapter_id(type, isc);
167 struct kvm_device_attr attr = {
168 .group = KVM_DEV_FLIC_AIRQ_INJECT,
169 .attr = id,
170 };
171
172 if (!fs->ais_supported) {
173 return -ENOSYS;
174 }
175
176 return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
177}
178
7b35d0c4
CH
179/**
180 * __get_all_irqs - store all pending irqs in buffer
181 * @flic: pointer to flic device state
182 * @buf: pointer to pointer to a buffer
183 * @len: length of buffer
184 *
185 * Returns: return value of flic_get_all_irqs
186 * Note: Retry and increase buffer size until flic_get_all_irqs
187 * either returns a value >= 0 or a negative error code.
188 * -ENOMEM is an exception, which means the buffer is too small
189 * and we should try again. Other negative error codes can be
190 * -EFAULT and -EINVAL which we ignore at this point
191 */
192static int __get_all_irqs(KVMS390FLICState *flic,
193 void **buf, int len)
194{
195 int r;
196
197 do {
198 /* returns -ENOMEM if buffer is too small and number
199 * of queued interrupts on success */
200 r = flic_get_all_irqs(flic, *buf, len);
201 if (r >= 0) {
202 break;
203 }
204 len *= 2;
205 *buf = g_try_realloc(*buf, len);
206 if (!buf) {
207 return -ENOMEM;
208 }
209 } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
210
211 return r;
212}
213
03cf077a
CH
214static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
215 uint8_t isc, bool swap,
1497c160 216 bool is_maskable, uint8_t flags)
03cf077a
CH
217{
218 struct kvm_s390_io_adapter adapter = {
219 .id = id,
220 .isc = isc,
221 .maskable = is_maskable,
222 .swap = swap,
1497c160 223 .flags = flags,
03cf077a
CH
224 };
225 KVMS390FLICState *flic = KVM_S390_FLIC(fs);
9be38598 226 int r;
03cf077a
CH
227 struct kvm_device_attr attr = {
228 .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
229 .addr = (uint64_t)&adapter,
230 };
231
4cbd6c41 232 if (!kvm_gsi_routing_enabled()) {
08da527f
CH
233 /* nothing to do */
234 return 0;
03cf077a
CH
235 }
236
237 r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
238
9be38598 239 return r ? -errno : 0;
03cf077a
CH
240}
241
d426d9fb
CH
242static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
243 uint64_t map_addr, bool do_map)
244{
245 struct kvm_s390_io_adapter_req req = {
246 .id = id,
247 .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
248 .addr = map_addr,
249 };
250 struct kvm_device_attr attr = {
251 .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
252 .addr = (uint64_t)&req,
253 };
254 KVMS390FLICState *flic = KVM_S390_FLIC(fs);
255 int r;
256
4cbd6c41 257 if (!kvm_gsi_routing_enabled()) {
08da527f
CH
258 /* nothing to do */
259 return 0;
d426d9fb
CH
260 }
261
262 r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
263 return r ? -errno : 0;
264}
265
266static int kvm_s390_add_adapter_routes(S390FLICState *fs,
267 AdapterRoutes *routes)
268{
269 int ret, i;
270 uint64_t ind_offset = routes->adapter.ind_offset;
271
272 for (i = 0; i < routes->num_routes; i++) {
273 ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
274 if (ret < 0) {
275 goto out_undo;
276 }
277 routes->gsi[i] = ret;
278 routes->adapter.ind_offset++;
279 }
c0194a00
JF
280 kvm_irqchip_commit_routes(kvm_state);
281
d426d9fb
CH
282 /* Restore passed-in structure to original state. */
283 routes->adapter.ind_offset = ind_offset;
284 return 0;
285out_undo:
286 while (--i >= 0) {
287 kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
288 routes->gsi[i] = -1;
289 }
290 routes->adapter.ind_offset = ind_offset;
291 return ret;
292}
293
294static void kvm_s390_release_adapter_routes(S390FLICState *fs,
295 AdapterRoutes *routes)
296{
297 int i;
298
299 for (i = 0; i < routes->num_routes; i++) {
300 if (routes->gsi[i] >= 0) {
301 kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
302 routes->gsi[i] = -1;
303 }
304 }
305}
306
7b35d0c4
CH
307/**
308 * kvm_flic_save - Save pending floating interrupts
309 * @f: QEMUFile containing migration state
310 * @opaque: pointer to flic device state
f2cab7f1 311 * @size: ignored
7b35d0c4
CH
312 *
313 * Note: Pass buf and len to kernel. Start with one page and
314 * increase until buffer is sufficient or maxium size is
315 * reached
316 */
2c21ee76
JD
317static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
318 VMStateField *field, QJSON *vmdesc)
7b35d0c4
CH
319{
320 KVMS390FLICState *flic = opaque;
321 int len = FLIC_SAVE_INITIAL_SIZE;
322 void *buf;
323 int count;
ba690c71 324 int r = 0;
7b35d0c4
CH
325
326 flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
327
328 buf = g_try_malloc0(len);
329 if (!buf) {
330 /* Storing FLIC_FAILED into the count field here will cause the
331 * target system to fail when attempting to load irqs from the
332 * migration state */
333 error_report("flic: couldn't allocate memory");
334 qemu_put_be64(f, FLIC_FAILED);
ba690c71 335 return -ENOMEM;
7b35d0c4
CH
336 }
337
338 count = __get_all_irqs(flic, &buf, len);
339 if (count < 0) {
340 error_report("flic: couldn't retrieve irqs from kernel, rc %d",
341 count);
342 /* Storing FLIC_FAILED into the count field here will cause the
343 * target system to fail when attempting to load irqs from the
344 * migration state */
345 qemu_put_be64(f, FLIC_FAILED);
ba690c71 346 r = count;
7b35d0c4
CH
347 } else {
348 qemu_put_be64(f, count);
349 qemu_put_buffer(f, (uint8_t *) buf,
350 count * sizeof(struct kvm_s390_irq));
351 }
352 g_free(buf);
2c21ee76 353
ba690c71 354 return r;
7b35d0c4
CH
355}
356
357/**
358 * kvm_flic_load - Load pending floating interrupts
359 * @f: QEMUFile containing migration state
360 * @opaque: pointer to flic device state
f2cab7f1 361 * @size: ignored
7b35d0c4
CH
362 *
363 * Returns: value of flic_enqueue_irqs, -EINVAL on error
364 * Note: Do nothing when no interrupts where stored
365 * in QEMUFile
366 */
2c21ee76
JD
367static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size,
368 VMStateField *field)
7b35d0c4
CH
369{
370 uint64_t len = 0;
371 uint64_t count = 0;
372 void *buf = NULL;
373 int r = 0;
374
7b35d0c4
CH
375 flic_enable_pfault((struct KVMS390FLICState *) opaque);
376
377 count = qemu_get_be64(f);
378 len = count * sizeof(struct kvm_s390_irq);
379 if (count == FLIC_FAILED) {
380 r = -EINVAL;
381 goto out;
382 }
383 if (count == 0) {
384 r = 0;
385 goto out;
386 }
387 buf = g_try_malloc0(len);
388 if (!buf) {
389 r = -ENOMEM;
390 goto out;
391 }
392
393 if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
394 r = -EINVAL;
395 goto out_free;
396 }
397 r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
398
399out_free:
400 g_free(buf);
401out:
402 return r;
403}
404
e7be8d49
YMZ
405typedef struct KVMS390FLICStateMigTmp {
406 KVMS390FLICState *parent;
407 uint8_t simm;
408 uint8_t nimm;
409} KVMS390FLICStateMigTmp;
410
44b1ff31 411static int kvm_flic_ais_pre_save(void *opaque)
e7be8d49
YMZ
412{
413 KVMS390FLICStateMigTmp *tmp = opaque;
414 KVMS390FLICState *flic = tmp->parent;
415 struct kvm_s390_ais_all ais;
416 struct kvm_device_attr attr = {
417 .group = KVM_DEV_FLIC_AISM_ALL,
418 .addr = (uint64_t)&ais,
419 .attr = sizeof(ais),
420 };
421
422 if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
423 error_report("Failed to retrieve kvm flic ais states");
44b1ff31 424 return -EINVAL;
e7be8d49
YMZ
425 }
426
427 tmp->simm = ais.simm;
428 tmp->nimm = ais.nimm;
44b1ff31
DDAG
429
430 return 0;
e7be8d49
YMZ
431}
432
433static int kvm_flic_ais_post_load(void *opaque, int version_id)
434{
435 KVMS390FLICStateMigTmp *tmp = opaque;
436 KVMS390FLICState *flic = tmp->parent;
437 struct kvm_s390_ais_all ais = {
438 .simm = tmp->simm,
439 .nimm = tmp->nimm,
440 };
441 struct kvm_device_attr attr = {
442 .group = KVM_DEV_FLIC_AISM_ALL,
443 .addr = (uint64_t)&ais,
444 };
445
446 /* This can happen when the user mis-configures its guests in an
447 * incompatible fashion or without a CPU model. For example using
448 * qemu with -cpu host (which is not migration safe) and do a
449 * migration from a host that has AIS to a host that has no AIS.
450 * In that case the target system will reject the migration here.
451 */
452 if (!ais_needed(flic)) {
453 return -ENOSYS;
454 }
455
456 return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
457}
458
459static const VMStateDescription kvm_s390_flic_ais_tmp = {
460 .name = "s390-flic-ais-tmp",
461 .pre_save = kvm_flic_ais_pre_save,
462 .post_load = kvm_flic_ais_post_load,
463 .fields = (VMStateField[]) {
464 VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
465 VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
466 VMSTATE_END_OF_LIST()
467 }
468};
469
470static const VMStateDescription kvm_s390_flic_vmstate_ais = {
471 .name = "s390-flic/ais",
472 .version_id = 1,
473 .minimum_version_id = 1,
474 .needed = ais_needed,
475 .fields = (VMStateField[]) {
476 VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
477 kvm_s390_flic_ais_tmp),
478 VMSTATE_END_OF_LIST()
479 }
480};
481
f2cab7f1 482static const VMStateDescription kvm_s390_flic_vmstate = {
e7be8d49
YMZ
483 /* should have been like kvm-s390-flic,
484 * can't change without breaking compat */
f2cab7f1
CH
485 .name = "s390-flic",
486 .version_id = FLIC_SAVEVM_VERSION,
487 .minimum_version_id = FLIC_SAVEVM_VERSION,
488 .fields = (VMStateField[]) {
489 {
490 .name = "irqs",
491 .info = &(const VMStateInfo) {
492 .name = "irqs",
493 .get = kvm_flic_load,
494 .put = kvm_flic_save,
495 },
496 .flags = VMS_SINGLE,
497 },
498 VMSTATE_END_OF_LIST()
e7be8d49
YMZ
499 },
500 .subsections = (const VMStateDescription * []) {
501 &kvm_s390_flic_vmstate_ais,
502 NULL
f2cab7f1
CH
503 }
504};
505
5cbab1bf
HP
506typedef struct KVMS390FLICStateClass {
507 S390FLICStateClass parent_class;
508 DeviceRealize parent_realize;
509} KVMS390FLICStateClass;
510
511#define KVM_S390_FLIC_GET_CLASS(obj) \
512 OBJECT_GET_CLASS(KVMS390FLICStateClass, (obj), TYPE_KVM_S390_FLIC)
513
514#define KVM_S390_FLIC_CLASS(klass) \
515 OBJECT_CLASS_CHECK(KVMS390FLICStateClass, (klass), TYPE_KVM_S390_FLIC)
516
7b35d0c4
CH
517static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
518{
519 KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
520 struct kvm_create_device cd = {0};
9eccb862 521 struct kvm_device_attr test_attr = {0};
7b35d0c4 522 int ret;
f62f2109 523 Error *errp_local = NULL;
7b35d0c4 524
5cbab1bf
HP
525 KVM_S390_FLIC_GET_CLASS(dev)->parent_realize(dev, &errp_local);
526 if (errp_local) {
527 goto fail;
528 }
7b35d0c4
CH
529 flic_state->fd = -1;
530 if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
f62f2109
HP
531 error_setg_errno(&errp_local, errno, "KVM is missing capability"
532 " KVM_CAP_DEVICE_CTRL");
7b35d0c4 533 trace_flic_no_device_api(errno);
f62f2109 534 goto fail;
7b35d0c4
CH
535 }
536
537 cd.type = KVM_DEV_TYPE_FLIC;
538 ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
539 if (ret < 0) {
f62f2109 540 error_setg_errno(&errp_local, errno, "Creating the KVM device failed");
7b35d0c4 541 trace_flic_create_device(errno);
f62f2109 542 goto fail;
7b35d0c4
CH
543 }
544 flic_state->fd = cd.fd;
545
9eccb862
HP
546 /* Check clear_io_irq support */
547 test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
548 flic_state->clear_io_supported = !ioctl(flic_state->fd,
549 KVM_HAS_DEVICE_ATTR, test_attr);
f62f2109
HP
550 return;
551fail:
552 error_propagate(errp, errp_local);
7b35d0c4
CH
553}
554
555static void kvm_s390_flic_reset(DeviceState *dev)
556{
557 KVMS390FLICState *flic = KVM_S390_FLIC(dev);
6c1dd652 558 S390FLICState *fs = S390_FLIC_COMMON(dev);
7b35d0c4
CH
559 struct kvm_device_attr attr = {
560 .group = KVM_DEV_FLIC_CLEAR_IRQS,
561 };
562 int rc = 0;
6c1dd652 563 uint8_t isc;
7b35d0c4
CH
564
565 if (flic->fd == -1) {
566 return;
567 }
568
569 flic_disable_wait_pfault(flic);
570
6c1dd652
FL
571 if (fs->ais_supported) {
572 for (isc = 0; isc <= MAX_ISC; isc++) {
573 rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
574 if (rc) {
575 error_report("Failed to reset ais mode for isc %d: %s",
576 isc, strerror(-rc));
577 }
578 }
579 }
580
7b35d0c4
CH
581 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
582 if (rc) {
583 trace_flic_reset_failed(errno);
584 }
585
586 flic_enable_pfault(flic);
587}
588
589static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
590{
591 DeviceClass *dc = DEVICE_CLASS(oc);
03cf077a 592 S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
7b35d0c4 593
5cbab1bf 594 KVM_S390_FLIC_CLASS(oc)->parent_realize = dc->realize;
7b35d0c4 595 dc->realize = kvm_s390_flic_realize;
f2cab7f1 596 dc->vmsd = &kvm_s390_flic_vmstate;
7b35d0c4 597 dc->reset = kvm_s390_flic_reset;
03cf077a 598 fsc->register_io_adapter = kvm_s390_register_io_adapter;
d426d9fb
CH
599 fsc->io_adapter_map = kvm_s390_io_adapter_map;
600 fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
601 fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
9eccb862 602 fsc->clear_io_irq = kvm_s390_clear_io_flic;
6c1dd652 603 fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
1622ffd5 604 fsc->inject_airq = kvm_s390_inject_airq;
7b35d0c4
CH
605}
606
607static const TypeInfo kvm_s390_flic_info = {
608 .name = TYPE_KVM_S390_FLIC,
609 .parent = TYPE_S390_FLIC_COMMON,
610 .instance_size = sizeof(KVMS390FLICState),
5cbab1bf 611 .class_size = sizeof(KVMS390FLICStateClass),
7b35d0c4
CH
612 .class_init = kvm_s390_flic_class_init,
613};
614
615static void kvm_s390_flic_register_types(void)
616{
617 type_register_static(&kvm_s390_flic_info);
618}
619
620type_init(kvm_s390_flic_register_types)
This page took 0.28368 seconds and 4 git commands to generate.