3 * Signal Quiesce - trigger system powerdown request
5 * Copyright IBM, Corp. 2012
8 * Heinz Graalfs <graalfs@de.ibm.com>
10 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
11 * option) any later version. See the COPYING file in the top-level directory.
15 #include "qemu/osdep.h"
16 #include "hw/s390x/sclp.h"
17 #include "migration/vmstate.h"
18 #include "qemu/module.h"
19 #include "sysemu/runstate.h"
20 #include "hw/s390x/event-facility.h"
22 typedef struct SignalQuiesce
{
23 EventBufferHeader ebh
;
26 } QEMU_PACKED SignalQuiesce
;
28 static bool can_handle_event(uint8_t type
)
30 return type
== SCLP_EVENT_SIGNAL_QUIESCE
;
33 static sccb_mask_t
send_mask(void)
35 return SCLP_EVENT_MASK_SIGNAL_QUIESCE
;
38 static sccb_mask_t
receive_mask(void)
43 static int read_event_data(SCLPEvent
*event
, EventBufferHeader
*evt_buf_hdr
,
46 SignalQuiesce
*sq
= (SignalQuiesce
*) evt_buf_hdr
;
48 if (*slen
< sizeof(SignalQuiesce
)) {
52 if (!event
->event_pending
) {
55 event
->event_pending
= false;
57 sq
->ebh
.length
= cpu_to_be16(sizeof(SignalQuiesce
));
58 sq
->ebh
.type
= SCLP_EVENT_SIGNAL_QUIESCE
;
59 sq
->ebh
.flags
|= SCLP_EVENT_BUFFER_ACCEPTED
;
61 * system_powerdown does not have a timeout. Fortunately the
62 * timeout value is currently ignored by Linux, anyway
64 sq
->timeout
= cpu_to_be16(0);
65 sq
->unit
= cpu_to_be16(0);
66 *slen
-= sizeof(SignalQuiesce
);
71 static const VMStateDescription vmstate_sclpquiesce
= {
72 .name
= TYPE_SCLP_QUIESCE
,
74 .minimum_version_id
= 0,
75 .fields
= (VMStateField
[]) {
76 VMSTATE_BOOL(event_pending
, SCLPEvent
),
81 typedef struct QuiesceNotifier QuiesceNotifier
;
83 static struct QuiesceNotifier
{
88 static void quiesce_powerdown_req(Notifier
*n
, void *opaque
)
90 QuiesceNotifier
*qn
= container_of(n
, QuiesceNotifier
, notifier
);
91 SCLPEvent
*event
= qn
->event
;
93 event
->event_pending
= true;
94 /* trigger SCLP read operation */
95 sclp_service_interrupt(0);
98 static int quiesce_init(SCLPEvent
*event
)
100 qn
.notifier
.notify
= quiesce_powerdown_req
;
103 qemu_register_powerdown_notifier(&qn
.notifier
);
108 static void quiesce_reset(DeviceState
*dev
)
110 SCLPEvent
*event
= SCLP_EVENT(dev
);
112 event
->event_pending
= false;
115 static void quiesce_class_init(ObjectClass
*klass
, void *data
)
117 DeviceClass
*dc
= DEVICE_CLASS(klass
);
118 SCLPEventClass
*k
= SCLP_EVENT_CLASS(klass
);
120 dc
->reset
= quiesce_reset
;
121 dc
->vmsd
= &vmstate_sclpquiesce
;
122 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
124 * Reason: This is just an internal device - the notifier should
125 * not be registered multiple times in quiesce_init()
127 dc
->user_creatable
= false;
129 k
->init
= quiesce_init
;
130 k
->get_send_mask
= send_mask
;
131 k
->get_receive_mask
= receive_mask
;
132 k
->can_handle_event
= can_handle_event
;
133 k
->read_event_data
= read_event_data
;
134 k
->write_event_data
= NULL
;
137 static const TypeInfo sclp_quiesce_info
= {
138 .name
= TYPE_SCLP_QUIESCE
,
139 .parent
= TYPE_SCLP_EVENT
,
140 .instance_size
= sizeof(SCLPEvent
),
141 .class_init
= quiesce_class_init
,
142 .class_size
= sizeof(SCLPEventClass
),
145 static void register_types(void)
147 type_register_static(&sclp_quiesce_info
);
150 type_init(register_types
)