2 * QEMU S390x floating interrupt controller (flic)
4 * Copyright 2014 IBM Corp.
5 * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
6 * Cornelia Huck <cornelia.huck@de.ibm.com>
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
13 #include "qemu/osdep.h"
14 #include "qemu/error-report.h"
15 #include "qemu/main-loop.h"
16 #include "qemu/module.h"
17 #include "hw/sysbus.h"
18 #include "hw/s390x/ioinst.h"
19 #include "hw/s390x/s390_flic.h"
20 #include "hw/qdev-properties.h"
21 #include "hw/s390x/css.h"
23 #include "qapi/error.h"
24 #include "hw/s390x/s390-virtio-ccw.h"
26 S390FLICStateClass
*s390_get_flic_class(S390FLICState
*fs
)
28 static S390FLICStateClass
*class;
31 /* we only have one flic device, so this is fine to cache */
32 class = S390_FLIC_COMMON_GET_CLASS(fs
);
37 QEMUS390FLICState
*s390_get_qemu_flic(S390FLICState
*fs
)
39 static QEMUS390FLICState
*flic
;
42 /* we only have one flic device, so this is fine to cache */
43 flic
= QEMU_S390_FLIC(fs
);
48 S390FLICState
*s390_get_flic(void)
50 static S390FLICState
*fs
;
53 fs
= S390_FLIC_COMMON(object_resolve_path_type("",
54 TYPE_S390_FLIC_COMMON
,
60 void s390_flic_init(void)
65 dev
= qdev_new(TYPE_KVM_S390_FLIC
);
66 object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC
,
69 dev
= qdev_new(TYPE_QEMU_S390_FLIC
);
70 object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC
,
73 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev
), &error_fatal
);
76 static int qemu_s390_register_io_adapter(S390FLICState
*fs
, uint32_t id
,
77 uint8_t isc
, bool swap
,
78 bool is_maskable
, uint8_t flags
)
84 static int qemu_s390_io_adapter_map(S390FLICState
*fs
, uint32_t id
,
85 uint64_t map_addr
, bool do_map
)
91 static int qemu_s390_add_adapter_routes(S390FLICState
*fs
,
92 AdapterRoutes
*routes
)
97 static void qemu_s390_release_adapter_routes(S390FLICState
*fs
,
98 AdapterRoutes
*routes
)
102 static int qemu_s390_clear_io_flic(S390FLICState
*fs
, uint16_t subchannel_id
,
103 uint16_t subchannel_nr
)
105 QEMUS390FLICState
*flic
= s390_get_qemu_flic(fs
);
106 QEMUS390FlicIO
*cur
, *next
;
109 g_assert(bql_locked());
110 if (!(flic
->pending
& FLIC_PENDING_IO
)) {
115 for (isc
= 0; isc
< 8; isc
++) {
116 if (QLIST_EMPTY(&flic
->io
[isc
])) {
120 /* search and delete any matching one */
121 QLIST_FOREACH_SAFE(cur
, &flic
->io
[isc
], next
, next
) {
122 if (cur
->id
== subchannel_id
&& cur
->nr
== subchannel_nr
) {
123 QLIST_REMOVE(cur
, next
);
128 /* update our indicator bit */
129 if (QLIST_EMPTY(&flic
->io
[isc
])) {
130 flic
->pending
&= ~ISC_TO_PENDING_IO(isc
);
136 static int qemu_s390_modify_ais_mode(S390FLICState
*fs
, uint8_t isc
,
139 QEMUS390FLICState
*flic
= s390_get_qemu_flic(fs
);
142 case SIC_IRQ_MODE_ALL
:
143 flic
->simm
&= ~AIS_MODE_MASK(isc
);
144 flic
->nimm
&= ~AIS_MODE_MASK(isc
);
146 case SIC_IRQ_MODE_SINGLE
:
147 flic
->simm
|= AIS_MODE_MASK(isc
);
148 flic
->nimm
&= ~AIS_MODE_MASK(isc
);
157 static int qemu_s390_inject_airq(S390FLICState
*fs
, uint8_t type
,
158 uint8_t isc
, uint8_t flags
)
160 QEMUS390FLICState
*flic
= s390_get_qemu_flic(fs
);
161 S390FLICStateClass
*fsc
= s390_get_flic_class(fs
);
162 bool flag
= flags
& S390_ADAPTER_SUPPRESSIBLE
;
163 uint32_t io_int_word
= (isc
<< 27) | IO_INT_WORD_AI
;
165 if (flag
&& (flic
->nimm
& AIS_MODE_MASK(isc
))) {
166 trace_qemu_s390_airq_suppressed(type
, isc
);
170 fsc
->inject_io(fs
, 0, 0, 0, io_int_word
);
172 if (flag
&& (flic
->simm
& AIS_MODE_MASK(isc
))) {
173 flic
->nimm
|= AIS_MODE_MASK(isc
);
174 trace_qemu_s390_suppress_airq(isc
, "Single-Interruption Mode",
175 "NO-Interruptions Mode");
181 static void qemu_s390_flic_notify(uint32_t type
)
186 * We have to make all CPUs see CPU_INTERRUPT_HARD, so they might
187 * consider it. We will kick all running CPUs and only relevant
191 S390CPU
*cpu
= S390_CPU(cs
);
193 cs
->interrupt_request
|= CPU_INTERRUPT_HARD
;
195 /* ignore CPUs that are not sleeping */
196 if (s390_cpu_get_state(cpu
) != S390_CPU_STATE_OPERATING
&&
197 s390_cpu_get_state(cpu
) != S390_CPU_STATE_LOAD
) {
201 /* we always kick running CPUs for now, this is tricky */
203 /* don't check for subclasses, CPUs double check when waking up */
204 if (type
& FLIC_PENDING_SERVICE
) {
205 if (!(cpu
->env
.psw
.mask
& PSW_MASK_EXT
)) {
208 } else if (type
& FLIC_PENDING_IO
) {
209 if (!(cpu
->env
.psw
.mask
& PSW_MASK_IO
)) {
212 } else if (type
& FLIC_PENDING_MCHK_CR
) {
213 if (!(cpu
->env
.psw
.mask
& PSW_MASK_MCHECK
)) {
218 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
222 uint32_t qemu_s390_flic_dequeue_service(QEMUS390FLICState
*flic
)
226 g_assert(bql_locked());
227 g_assert(flic
->pending
& FLIC_PENDING_SERVICE
);
228 tmp
= flic
->service_param
;
229 flic
->service_param
= 0;
230 flic
->pending
&= ~FLIC_PENDING_SERVICE
;
235 /* caller has to free the returned object */
236 QEMUS390FlicIO
*qemu_s390_flic_dequeue_io(QEMUS390FLICState
*flic
, uint64_t cr6
)
241 g_assert(bql_locked());
242 if (!(flic
->pending
& CR6_TO_PENDING_IO(cr6
))) {
246 for (isc
= 0; isc
< 8; isc
++) {
247 if (QLIST_EMPTY(&flic
->io
[isc
]) || !(cr6
& ISC_TO_ISC_BITS(isc
))) {
250 io
= QLIST_FIRST(&flic
->io
[isc
]);
251 QLIST_REMOVE(io
, next
);
253 /* update our indicator bit */
254 if (QLIST_EMPTY(&flic
->io
[isc
])) {
255 flic
->pending
&= ~ISC_TO_PENDING_IO(isc
);
263 void qemu_s390_flic_dequeue_crw_mchk(QEMUS390FLICState
*flic
)
265 g_assert(bql_locked());
266 g_assert(flic
->pending
& FLIC_PENDING_MCHK_CR
);
267 flic
->pending
&= ~FLIC_PENDING_MCHK_CR
;
270 static void qemu_s390_inject_service(S390FLICState
*fs
, uint32_t parm
)
272 QEMUS390FLICState
*flic
= s390_get_qemu_flic(fs
);
274 g_assert(bql_locked());
275 /* multiplexing is good enough for sclp - kvm does it internally as well */
276 flic
->service_param
|= parm
;
277 flic
->pending
|= FLIC_PENDING_SERVICE
;
279 qemu_s390_flic_notify(FLIC_PENDING_SERVICE
);
282 static void qemu_s390_inject_io(S390FLICState
*fs
, uint16_t subchannel_id
,
283 uint16_t subchannel_nr
, uint32_t io_int_parm
,
284 uint32_t io_int_word
)
286 const uint8_t isc
= IO_INT_WORD_ISC(io_int_word
);
287 QEMUS390FLICState
*flic
= s390_get_qemu_flic(fs
);
290 g_assert(bql_locked());
291 io
= g_new0(QEMUS390FlicIO
, 1);
292 io
->id
= subchannel_id
;
293 io
->nr
= subchannel_nr
;
294 io
->parm
= io_int_parm
;
295 io
->word
= io_int_word
;
297 QLIST_INSERT_HEAD(&flic
->io
[isc
], io
, next
);
298 flic
->pending
|= ISC_TO_PENDING_IO(isc
);
300 qemu_s390_flic_notify(ISC_TO_PENDING_IO(isc
));
303 static void qemu_s390_inject_crw_mchk(S390FLICState
*fs
)
305 QEMUS390FLICState
*flic
= s390_get_qemu_flic(fs
);
307 g_assert(bql_locked());
308 flic
->pending
|= FLIC_PENDING_MCHK_CR
;
310 qemu_s390_flic_notify(FLIC_PENDING_MCHK_CR
);
313 bool qemu_s390_flic_has_service(QEMUS390FLICState
*flic
)
315 /* called without lock via cc->has_work, will be validated under lock */
316 return !!(flic
->pending
& FLIC_PENDING_SERVICE
);
319 bool qemu_s390_flic_has_io(QEMUS390FLICState
*flic
, uint64_t cr6
)
321 /* called without lock via cc->has_work, will be validated under lock */
322 return !!(flic
->pending
& CR6_TO_PENDING_IO(cr6
));
325 bool qemu_s390_flic_has_crw_mchk(QEMUS390FLICState
*flic
)
327 /* called without lock via cc->has_work, will be validated under lock */
328 return !!(flic
->pending
& FLIC_PENDING_MCHK_CR
);
331 bool qemu_s390_flic_has_any(QEMUS390FLICState
*flic
)
333 g_assert(bql_locked());
334 return !!flic
->pending
;
337 static void qemu_s390_flic_reset(DeviceState
*dev
)
339 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(dev
);
340 QEMUS390FlicIO
*cur
, *next
;
343 g_assert(bql_locked());
348 /* remove all pending io interrupts */
349 for (isc
= 0; isc
< 8; isc
++) {
350 QLIST_FOREACH_SAFE(cur
, &flic
->io
[isc
], next
, next
) {
351 QLIST_REMOVE(cur
, next
);
357 bool ais_needed(void *opaque
)
359 S390FLICState
*s
= opaque
;
361 return s
->ais_supported
;
364 static bool ais_needed_v(void *opaque
, int version_id
)
366 return ais_needed(opaque
);
369 static bool qemu_s390_flic_full_state_needed(void *opaque
)
371 QEMUS390FLICState
*s
= opaque
;
373 return s
->migrate_all_state
;
376 static bool qemu_s390_flic_state_needed(void *opaque
)
378 return ais_needed(opaque
) || qemu_s390_flic_full_state_needed(opaque
);
381 static const VMStateDescription vmstate_qemu_s390_flic_io
= {
382 .name
= "qemu-s390-flic-io",
384 .minimum_version_id
= 1,
385 .fields
= (const VMStateField
[]) {
386 VMSTATE_UINT16(id
, QEMUS390FlicIO
),
387 VMSTATE_UINT16(nr
, QEMUS390FlicIO
),
388 VMSTATE_UINT32(parm
, QEMUS390FlicIO
),
389 VMSTATE_UINT32(word
, QEMUS390FlicIO
),
390 VMSTATE_END_OF_LIST()
394 static const VMStateDescription vmstate_qemu_s390_flic_full
= {
395 .name
= "qemu-s390-flic-full",
397 .minimum_version_id
= 1,
398 .needed
= qemu_s390_flic_full_state_needed
,
399 .fields
= (const VMStateField
[]) {
400 VMSTATE_UINT32(pending
, QEMUS390FLICState
),
401 VMSTATE_UINT32(service_param
, QEMUS390FLICState
),
402 VMSTATE_QLIST_V(io
[0], QEMUS390FLICState
, 1,
403 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
404 VMSTATE_QLIST_V(io
[1], QEMUS390FLICState
, 1,
405 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
406 VMSTATE_QLIST_V(io
[2], QEMUS390FLICState
, 1,
407 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
408 VMSTATE_QLIST_V(io
[3], QEMUS390FLICState
, 1,
409 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
410 VMSTATE_QLIST_V(io
[4], QEMUS390FLICState
, 1,
411 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
412 VMSTATE_QLIST_V(io
[5], QEMUS390FLICState
, 1,
413 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
414 VMSTATE_QLIST_V(io
[6], QEMUS390FLICState
, 1,
415 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
416 VMSTATE_QLIST_V(io
[7], QEMUS390FLICState
, 1,
417 vmstate_qemu_s390_flic_io
, QEMUS390FlicIO
, next
),
418 VMSTATE_END_OF_LIST()
422 static const VMStateDescription qemu_s390_flic_vmstate
= {
423 .name
= "qemu-s390-flic",
425 .minimum_version_id
= 1,
426 .needed
= qemu_s390_flic_state_needed
,
427 .fields
= (const VMStateField
[]) {
428 VMSTATE_UINT8_TEST(simm
, QEMUS390FLICState
, ais_needed_v
),
429 VMSTATE_UINT8_TEST(nimm
, QEMUS390FLICState
, ais_needed_v
),
430 VMSTATE_END_OF_LIST()
432 .subsections
= (const VMStateDescription
* const []) {
433 &vmstate_qemu_s390_flic_full
,
438 static void qemu_s390_flic_instance_init(Object
*obj
)
440 QEMUS390FLICState
*flic
= QEMU_S390_FLIC(obj
);
443 for (isc
= 0; isc
< 8; isc
++) {
444 QLIST_INIT(&flic
->io
[isc
]);
448 static Property qemu_s390_flic_properties
[] = {
449 DEFINE_PROP_BOOL("migrate-all-state", QEMUS390FLICState
,
450 migrate_all_state
, true),
451 DEFINE_PROP_END_OF_LIST(),
454 static void qemu_s390_flic_class_init(ObjectClass
*oc
, void *data
)
456 DeviceClass
*dc
= DEVICE_CLASS(oc
);
457 S390FLICStateClass
*fsc
= S390_FLIC_COMMON_CLASS(oc
);
459 device_class_set_props(dc
, qemu_s390_flic_properties
);
460 device_class_set_legacy_reset(dc
, qemu_s390_flic_reset
);
461 dc
->vmsd
= &qemu_s390_flic_vmstate
;
462 fsc
->register_io_adapter
= qemu_s390_register_io_adapter
;
463 fsc
->io_adapter_map
= qemu_s390_io_adapter_map
;
464 fsc
->add_adapter_routes
= qemu_s390_add_adapter_routes
;
465 fsc
->release_adapter_routes
= qemu_s390_release_adapter_routes
;
466 fsc
->clear_io_irq
= qemu_s390_clear_io_flic
;
467 fsc
->modify_ais_mode
= qemu_s390_modify_ais_mode
;
468 fsc
->inject_airq
= qemu_s390_inject_airq
;
469 fsc
->inject_service
= qemu_s390_inject_service
;
470 fsc
->inject_io
= qemu_s390_inject_io
;
471 fsc
->inject_crw_mchk
= qemu_s390_inject_crw_mchk
;
474 static Property s390_flic_common_properties
[] = {
475 DEFINE_PROP_UINT32("adapter_routes_max_batch", S390FLICState
,
476 adapter_routes_max_batch
, ADAPTER_ROUTES_MAX_GSI
),
477 DEFINE_PROP_BOOL("migration-enabled", S390FLICState
,
478 migration_enabled
, true),
479 DEFINE_PROP_END_OF_LIST(),
482 static void s390_flic_common_realize(DeviceState
*dev
, Error
**errp
)
484 S390FLICState
*fs
= S390_FLIC_COMMON(dev
);
485 uint32_t max_batch
= fs
->adapter_routes_max_batch
;
487 if (max_batch
> ADAPTER_ROUTES_MAX_GSI
) {
488 error_setg(errp
, "flic property adapter_routes_max_batch too big"
489 " (%d > %d)", max_batch
, ADAPTER_ROUTES_MAX_GSI
);
493 fs
->ais_supported
= s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION
);
496 static void s390_flic_class_init(ObjectClass
*oc
, void *data
)
498 DeviceClass
*dc
= DEVICE_CLASS(oc
);
500 device_class_set_props(dc
, s390_flic_common_properties
);
501 dc
->realize
= s390_flic_common_realize
;
504 static const TypeInfo qemu_s390_flic_info
= {
505 .name
= TYPE_QEMU_S390_FLIC
,
506 .parent
= TYPE_S390_FLIC_COMMON
,
507 .instance_size
= sizeof(QEMUS390FLICState
),
508 .instance_init
= qemu_s390_flic_instance_init
,
509 .class_init
= qemu_s390_flic_class_init
,
513 static const TypeInfo s390_flic_common_info
= {
514 .name
= TYPE_S390_FLIC_COMMON
,
515 .parent
= TYPE_SYS_BUS_DEVICE
,
516 .instance_size
= sizeof(S390FLICState
),
517 .class_init
= s390_flic_class_init
,
518 .class_size
= sizeof(S390FLICStateClass
),
521 static void qemu_s390_flic_register_types(void)
523 type_register_static(&s390_flic_common_info
);
524 type_register_static(&qemu_s390_flic_info
);
527 type_init(qemu_s390_flic_register_types
)
529 static bool adapter_info_so_needed(void *opaque
)
531 S390FLICState
*fs
= s390_get_flic();
533 return fs
->migration_enabled
;
536 const VMStateDescription vmstate_adapter_info_so
= {
537 .name
= "s390_adapter_info/summary_offset",
539 .minimum_version_id
= 1,
540 .needed
= adapter_info_so_needed
,
541 .fields
= (const VMStateField
[]) {
542 VMSTATE_UINT32(summary_offset
, AdapterInfo
),
543 VMSTATE_END_OF_LIST()
547 const VMStateDescription vmstate_adapter_info
= {
548 .name
= "s390_adapter_info",
550 .minimum_version_id
= 1,
551 .fields
= (const VMStateField
[]) {
552 VMSTATE_UINT64(ind_offset
, AdapterInfo
),
554 * We do not have to migrate neither the id nor the addresses.
555 * The id is set by css_register_io_adapter and the addresses
556 * are set based on the IndAddr objects after those get mapped.
558 VMSTATE_END_OF_LIST()
560 .subsections
= (const VMStateDescription
* const []) {
561 &vmstate_adapter_info_so
,
566 const VMStateDescription vmstate_adapter_routes
= {
568 .name
= "s390_adapter_routes",
570 .minimum_version_id
= 1,
571 .fields
= (const VMStateField
[]) {
572 VMSTATE_STRUCT(adapter
, AdapterRoutes
, 1, vmstate_adapter_info
,
574 VMSTATE_END_OF_LIST()