1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14#include "cpu.h"
15#include "kvm_s390x.h"
16#include <sys/ioctl.h>
17#include "qemu/error-report.h"
18#include "qemu/module.h"
19#include "qapi/error.h"
20#include "hw/sysbus.h"
21#include "sysemu/kvm.h"
22#include "hw/s390x/s390_flic.h"
23#include "hw/s390x/adapter.h"
24#include "hw/s390x/css.h"
25#include "migration/qemu-file-types.h"
26#include "trace.h"
27#include "qom/object.h"
28
29#define FLIC_SAVE_INITIAL_SIZE qemu_real_host_page_size
30#define FLIC_FAILED (-1UL)
31#define FLIC_SAVEVM_VERSION 1
32
33struct KVMS390FLICState{
34 S390FLICState parent_obj;
35
36 uint32_t fd;
37 bool clear_io_supported;
38};
39
40static KVMS390FLICState *s390_get_kvm_flic(S390FLICState *fs)
41{
42 static KVMS390FLICState *flic;
43
44 if (!flic) {
45
46 flic = KVM_S390_FLIC(fs);
47 }
48 return flic;
49}
50
51
52
53
54
55
56
57
58
59
60
61
62static int flic_get_all_irqs(KVMS390FLICState *flic,
63 void *buf, int len)
64{
65 struct kvm_device_attr attr = {
66 .group = KVM_DEV_FLIC_GET_ALL_IRQS,
67 .addr = (uint64_t) buf,
68 .attr = len,
69 };
70 int rc;
71
72 rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
73
74 return rc == -1 ? -errno : rc;
75}
76
77static void flic_enable_pfault(KVMS390FLICState *flic)
78{
79 struct kvm_device_attr attr = {
80 .group = KVM_DEV_FLIC_APF_ENABLE,
81 };
82 int rc;
83
84 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
85
86 if (rc) {
87 fprintf(stderr, "flic: couldn't enable pfault\n");
88 }
89}
90
91static void flic_disable_wait_pfault(KVMS390FLICState *flic)
92{
93 struct kvm_device_attr attr = {
94 .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
95 };
96 int rc;
97
98 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
99
100 if (rc) {
101 fprintf(stderr, "flic: couldn't disable pfault\n");
102 }
103}
104
105
106
107
108
109
110
111
112static int flic_enqueue_irqs(void *buf, uint64_t len,
113 KVMS390FLICState *flic)
114{
115 int rc;
116 struct kvm_device_attr attr = {
117 .group = KVM_DEV_FLIC_ENQUEUE,
118 .addr = (uint64_t) buf,
119 .attr = len,
120 };
121
122 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
123
124 return rc ? -errno : 0;
125}
126
127static void kvm_s390_inject_flic(S390FLICState *fs, struct kvm_s390_irq *irq)
128{
129 static bool use_flic = true;
130 int r;
131
132 if (use_flic) {
133 r = flic_enqueue_irqs(irq, sizeof(*irq), s390_get_kvm_flic(fs));
134 if (r == -ENOSYS) {
135 use_flic = false;
136 }
137 if (!r) {
138 return;
139 }
140 }
141
142 kvm_s390_floating_interrupt_legacy(irq);
143}
144
145static void kvm_s390_inject_service(S390FLICState *fs, uint32_t parm)
146{
147 struct kvm_s390_irq irq = {
148 .type = KVM_S390_INT_SERVICE,
149 .u.ext.ext_params = parm,
150 };
151
152 kvm_s390_inject_flic(fs, &irq);
153}
154
155static void kvm_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id,
156 uint16_t subchannel_nr, uint32_t io_int_parm,
157 uint32_t io_int_word)
158{
159 struct kvm_s390_irq irq = {
160 .u.io.subchannel_id = subchannel_id,
161 .u.io.subchannel_nr = subchannel_nr,
162 .u.io.io_int_parm = io_int_parm,
163 .u.io.io_int_word = io_int_word,
164 };
165
166 if (io_int_word & IO_INT_WORD_AI) {
167 irq.type = KVM_S390_INT_IO(1, 0, 0, 0);
168 } else {
169 irq.type = KVM_S390_INT_IO(0, (subchannel_id & 0xff00) >> 8,
170 (subchannel_id & 0x0006),
171 subchannel_nr);
172 }
173 kvm_s390_inject_flic(fs, &irq);
174}
175
176static void kvm_s390_inject_crw_mchk(S390FLICState *fs)
177{
178 struct kvm_s390_irq irq = {
179 .type = KVM_S390_MCHK,
180 .u.mchk.cr14 = CR14_CHANNEL_REPORT_SC,
181 .u.mchk.mcic = s390_build_validity_mcic() | MCIC_SC_CP,
182 };
183
184 kvm_s390_inject_flic(fs, &irq);
185}
186
187static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
188 uint16_t subchannel_nr)
189{
190 KVMS390FLICState *flic = s390_get_kvm_flic(fs);
191 int rc;
192 uint32_t sid = subchannel_id << 16 | subchannel_nr;
193 struct kvm_device_attr attr = {
194 .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
195 .addr = (uint64_t) &sid,
196 .attr = sizeof(sid),
197 };
198 if (unlikely(!flic->clear_io_supported)) {
199 return -ENOSYS;
200 }
201 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
202 return rc ? -errno : 0;
203}
204
205static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
206 uint16_t mode)
207{
208 KVMS390FLICState *flic = s390_get_kvm_flic(fs);
209 struct kvm_s390_ais_req req = {
210 .isc = isc,
211 .mode = mode,
212 };
213 struct kvm_device_attr attr = {
214 .group = KVM_DEV_FLIC_AISM,
215 .addr = (uint64_t)&req,
216 };
217
218 if (!fs->ais_supported) {
219 return -ENOSYS;
220 }
221
222 return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
223}
224
225static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
226 uint8_t isc, uint8_t flags)
227{
228 KVMS390FLICState *flic = s390_get_kvm_flic(fs);
229 uint32_t id = css_get_adapter_id(type, isc);
230 struct kvm_device_attr attr = {
231 .group = KVM_DEV_FLIC_AIRQ_INJECT,
232 .attr = id,
233 };
234
235 if (!fs->ais_supported) {
236 return -ENOSYS;
237 }
238
239 return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
240}
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255static int __get_all_irqs(KVMS390FLICState *flic,
256 void **buf, int len)
257{
258 int r;
259
260 do {
261
262
263 r = flic_get_all_irqs(flic, *buf, len);
264 if (r >= 0) {
265 break;
266 }
267 len *= 2;
268 *buf = g_try_realloc(*buf, len);
269 if (!buf) {
270 return -ENOMEM;
271 }
272 } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
273
274 return r;
275}
276
277static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
278 uint8_t isc, bool swap,
279 bool is_maskable, uint8_t flags)
280{
281 struct kvm_s390_io_adapter adapter = {
282 .id = id,
283 .isc = isc,
284 .maskable = is_maskable,
285 .swap = swap,
286 .flags = flags,
287 };
288 KVMS390FLICState *flic = KVM_S390_FLIC(fs);
289 int r;
290 struct kvm_device_attr attr = {
291 .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
292 .addr = (uint64_t)&adapter,
293 };
294
295 if (!kvm_gsi_routing_enabled()) {
296
297 return 0;
298 }
299
300 r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
301
302 return r ? -errno : 0;
303}
304
305static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
306 uint64_t map_addr, bool do_map)
307{
308 struct kvm_s390_io_adapter_req req = {
309 .id = id,
310 .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
311 .addr = map_addr,
312 };
313 struct kvm_device_attr attr = {
314 .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
315 .addr = (uint64_t)&req,
316 };
317 KVMS390FLICState *flic = s390_get_kvm_flic(fs);
318 int r;
319
320 if (!kvm_gsi_routing_enabled()) {
321
322 return 0;
323 }
324
325 r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
326 return r ? -errno : 0;
327}
328
329static int kvm_s390_add_adapter_routes(S390FLICState *fs,
330 AdapterRoutes *routes)
331{
332 int ret, i;
333 uint64_t ind_offset = routes->adapter.ind_offset;
334
335 if (!kvm_gsi_routing_enabled()) {
336 return -ENOSYS;
337 }
338
339 for (i = 0; i < routes->num_routes; i++) {
340 ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
341 if (ret < 0) {
342 goto out_undo;
343 }
344 routes->gsi[i] = ret;
345 routes->adapter.ind_offset++;
346 }
347 kvm_irqchip_commit_routes(kvm_state);
348
349
350 routes->adapter.ind_offset = ind_offset;
351 return 0;
352out_undo:
353 while (--i >= 0) {
354 kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
355 routes->gsi[i] = -1;
356 }
357 routes->adapter.ind_offset = ind_offset;
358 return ret;
359}
360
361static void kvm_s390_release_adapter_routes(S390FLICState *fs,
362 AdapterRoutes *routes)
363{
364 int i;
365
366 if (!kvm_gsi_routing_enabled()) {
367 return;
368 }
369
370 for (i = 0; i < routes->num_routes; i++) {
371 if (routes->gsi[i] >= 0) {
372 kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
373 routes->gsi[i] = -1;
374 }
375 }
376}
377
378
379
380
381
382
383
384
385
386
387
388static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
389 const VMStateField *field, JSONWriter *vmdesc)
390{
391 KVMS390FLICState *flic = opaque;
392 int len = FLIC_SAVE_INITIAL_SIZE;
393 void *buf;
394 int count;
395 int r = 0;
396
397 flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
398
399 buf = g_try_malloc0(len);
400 if (!buf) {
401
402
403
404 error_report("flic: couldn't allocate memory");
405 qemu_put_be64(f, FLIC_FAILED);
406 return -ENOMEM;
407 }
408
409 count = __get_all_irqs(flic, &buf, len);
410 if (count < 0) {
411 error_report("flic: couldn't retrieve irqs from kernel, rc %d",
412 count);
413
414
415
416 qemu_put_be64(f, FLIC_FAILED);
417 r = count;
418 } else {
419 qemu_put_be64(f, count);
420 qemu_put_buffer(f, (uint8_t *) buf,
421 count * sizeof(struct kvm_s390_irq));
422 }
423 g_free(buf);
424
425 return r;
426}
427
428
429
430
431
432
433
434
435
436
437
438static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size,
439 const VMStateField *field)
440{
441 uint64_t len = 0;
442 uint64_t count = 0;
443 void *buf = NULL;
444 int r = 0;
445
446 flic_enable_pfault((struct KVMS390FLICState *) opaque);
447
448 count = qemu_get_be64(f);
449 len = count * sizeof(struct kvm_s390_irq);
450 if (count == FLIC_FAILED) {
451 return -EINVAL;
452 }
453 if (count == 0) {
454 return 0;
455 }
456 buf = g_try_malloc0(len);
457 if (!buf) {
458 return -ENOMEM;
459 }
460
461 if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
462 r = -EINVAL;
463 goto out_free;
464 }
465 r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
466
467out_free:
468 g_free(buf);
469 return r;
470}
471
472typedef struct KVMS390FLICStateMigTmp {
473 KVMS390FLICState *parent;
474 uint8_t simm;
475 uint8_t nimm;
476} KVMS390FLICStateMigTmp;
477
478static int kvm_flic_ais_pre_save(void *opaque)
479{
480 KVMS390FLICStateMigTmp *tmp = opaque;
481 KVMS390FLICState *flic = tmp->parent;
482 struct kvm_s390_ais_all ais;
483 struct kvm_device_attr attr = {
484 .group = KVM_DEV_FLIC_AISM_ALL,
485 .addr = (uint64_t)&ais,
486 .attr = sizeof(ais),
487 };
488
489 if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
490 error_report("Failed to retrieve kvm flic ais states");
491 return -EINVAL;
492 }
493
494 tmp->simm = ais.simm;
495 tmp->nimm = ais.nimm;
496
497 return 0;
498}
499
500static int kvm_flic_ais_post_load(void *opaque, int version_id)
501{
502 KVMS390FLICStateMigTmp *tmp = opaque;
503 KVMS390FLICState *flic = tmp->parent;
504 struct kvm_s390_ais_all ais = {
505 .simm = tmp->simm,
506 .nimm = tmp->nimm,
507 };
508 struct kvm_device_attr attr = {
509 .group = KVM_DEV_FLIC_AISM_ALL,
510 .addr = (uint64_t)&ais,
511 };
512
513
514
515
516
517
518
519 if (!ais_needed(flic)) {
520 return -ENOSYS;
521 }
522
523 return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
524}
525
526static const VMStateDescription kvm_s390_flic_ais_tmp = {
527 .name = "s390-flic-ais-tmp",
528 .pre_save = kvm_flic_ais_pre_save,
529 .post_load = kvm_flic_ais_post_load,
530 .fields = (VMStateField[]) {
531 VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
532 VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
533 VMSTATE_END_OF_LIST()
534 }
535};
536
537static const VMStateDescription kvm_s390_flic_vmstate_ais = {
538 .name = "s390-flic/ais",
539 .version_id = 1,
540 .minimum_version_id = 1,
541 .needed = ais_needed,
542 .fields = (VMStateField[]) {
543 VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
544 kvm_s390_flic_ais_tmp),
545 VMSTATE_END_OF_LIST()
546 }
547};
548
549static const VMStateDescription kvm_s390_flic_vmstate = {
550
551
552 .name = "s390-flic",
553 .version_id = FLIC_SAVEVM_VERSION,
554 .minimum_version_id = FLIC_SAVEVM_VERSION,
555 .fields = (VMStateField[]) {
556 {
557 .name = "irqs",
558 .info = &(const VMStateInfo) {
559 .name = "irqs",
560 .get = kvm_flic_load,
561 .put = kvm_flic_save,
562 },
563 .flags = VMS_SINGLE,
564 },
565 VMSTATE_END_OF_LIST()
566 },
567 .subsections = (const VMStateDescription * []) {
568 &kvm_s390_flic_vmstate_ais,
569 NULL
570 }
571};
572
573struct KVMS390FLICStateClass {
574 S390FLICStateClass parent_class;
575 DeviceRealize parent_realize;
576};
577typedef struct KVMS390FLICStateClass KVMS390FLICStateClass;
578
579DECLARE_CLASS_CHECKERS(KVMS390FLICStateClass, KVM_S390_FLIC,
580 TYPE_KVM_S390_FLIC)
581
582
583static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
584{
585 KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
586 struct kvm_create_device cd = {0};
587 struct kvm_device_attr test_attr = {0};
588 int ret;
589 Error *err = NULL;
590
591 KVM_S390_FLIC_GET_CLASS(dev)->parent_realize(dev, &err);
592 if (err) {
593 error_propagate(errp, err);
594 return;
595 }
596 flic_state->fd = -1;
597
598 cd.type = KVM_DEV_TYPE_FLIC;
599 ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
600 if (ret < 0) {
601 error_setg_errno(errp, errno, "Creating the KVM device failed");
602 trace_flic_create_device(errno);
603 return;
604 }
605 flic_state->fd = cd.fd;
606
607
608 test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
609 flic_state->clear_io_supported = !ioctl(flic_state->fd,
610 KVM_HAS_DEVICE_ATTR, test_attr);
611}
612
613static void kvm_s390_flic_reset(DeviceState *dev)
614{
615 KVMS390FLICState *flic = KVM_S390_FLIC(dev);
616 S390FLICState *fs = S390_FLIC_COMMON(dev);
617 struct kvm_device_attr attr = {
618 .group = KVM_DEV_FLIC_CLEAR_IRQS,
619 };
620 int rc = 0;
621 uint8_t isc;
622
623 if (flic->fd == -1) {
624 return;
625 }
626
627 flic_disable_wait_pfault(flic);
628
629 if (fs->ais_supported) {
630 for (isc = 0; isc <= MAX_ISC; isc++) {
631 rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
632 if (rc) {
633 error_report("Failed to reset ais mode for isc %d: %s",
634 isc, strerror(-rc));
635 }
636 }
637 }
638
639 rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
640 if (rc) {
641 trace_flic_reset_failed(errno);
642 }
643
644 flic_enable_pfault(flic);
645}
646
647static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
648{
649 DeviceClass *dc = DEVICE_CLASS(oc);
650 S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
651
652 KVM_S390_FLIC_CLASS(oc)->parent_realize = dc->realize;
653 dc->realize = kvm_s390_flic_realize;
654 dc->vmsd = &kvm_s390_flic_vmstate;
655 dc->reset = kvm_s390_flic_reset;
656 fsc->register_io_adapter = kvm_s390_register_io_adapter;
657 fsc->io_adapter_map = kvm_s390_io_adapter_map;
658 fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
659 fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
660 fsc->clear_io_irq = kvm_s390_clear_io_flic;
661 fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
662 fsc->inject_airq = kvm_s390_inject_airq;
663 fsc->inject_service = kvm_s390_inject_service;
664 fsc->inject_io = kvm_s390_inject_io;
665 fsc->inject_crw_mchk = kvm_s390_inject_crw_mchk;
666}
667
668static const TypeInfo kvm_s390_flic_info = {
669 .name = TYPE_KVM_S390_FLIC,
670 .parent = TYPE_S390_FLIC_COMMON,
671 .instance_size = sizeof(KVMS390FLICState),
672 .class_size = sizeof(KVMS390FLICStateClass),
673 .class_init = kvm_s390_flic_class_init,
674};
675
676static void kvm_s390_flic_register_types(void)
677{
678 type_register_static(&kvm_s390_flic_info);
679}
680
681type_init(kvm_s390_flic_register_types)
682