2 * QEMU S390x KVM floating interrupt controller (flic)
4 * Copyright 2014 IBM Corp.
5 * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
8 * your option) any later version. See the COPYING file in the top-level
12 #include <sys/ioctl.h>
13 #include "qemu/error-report.h"
14 #include "hw/sysbus.h"
15 #include "sysemu/kvm.h"
16 #include "migration/qemu-file.h"
17 #include "hw/s390x/s390_flic.h"
20 #define FLIC_SAVE_INITIAL_SIZE getpagesize()
21 #define FLIC_FAILED (-1UL)
22 #define FLIC_SAVEVM_VERSION 1
24 void s390_flic_init(void)
30 dev
= qdev_create(NULL
, "s390-flic");
31 object_property_add_child(qdev_get_machine(), "s390-flic",
35 error_report("flic: couldn't create qdev");
41 * flic_get_all_irqs - store all pending irqs in buffer
42 * @buf: pointer to buffer which is passed to kernel
43 * @len: length of buffer
44 * @flic: pointer to flic device state
46 * Returns: -ENOMEM if buffer is too small,
47 * -EINVAL if attr.group is invalid,
48 * -EFAULT if copying to userspace failed,
49 * on success return number of stored interrupts
51 static int flic_get_all_irqs(KVMS390FLICState
*flic
,
54 struct kvm_device_attr attr
= {
55 .group
= KVM_DEV_FLIC_GET_ALL_IRQS
,
56 .addr
= (uint64_t) buf
,
61 rc
= ioctl(flic
->fd
, KVM_GET_DEVICE_ATTR
, &attr
);
63 return rc
== -1 ? -errno
: rc
;
66 static void flic_enable_pfault(KVMS390FLICState
*flic
)
68 struct kvm_device_attr attr
= {
69 .group
= KVM_DEV_FLIC_APF_ENABLE
,
73 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
76 fprintf(stderr
, "flic: couldn't enable pfault\n");
80 static void flic_disable_wait_pfault(KVMS390FLICState
*flic
)
82 struct kvm_device_attr attr
= {
83 .group
= KVM_DEV_FLIC_APF_DISABLE_WAIT
,
87 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
90 fprintf(stderr
, "flic: couldn't disable pfault\n");
94 /** flic_enqueue_irqs - returns 0 on success
95 * @buf: pointer to buffer which is passed to kernel
96 * @len: length of buffer
97 * @flic: pointer to flic device state
99 * Returns: -EINVAL if attr.group is unknown
101 static int flic_enqueue_irqs(void *buf
, uint64_t len
,
102 KVMS390FLICState
*flic
)
105 struct kvm_device_attr attr
= {
106 .group
= KVM_DEV_FLIC_ENQUEUE
,
107 .addr
= (uint64_t) buf
,
111 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
113 return rc
? -errno
: 0;
117 * __get_all_irqs - store all pending irqs in buffer
118 * @flic: pointer to flic device state
119 * @buf: pointer to pointer to a buffer
120 * @len: length of buffer
122 * Returns: return value of flic_get_all_irqs
123 * Note: Retry and increase buffer size until flic_get_all_irqs
124 * either returns a value >= 0 or a negative error code.
125 * -ENOMEM is an exception, which means the buffer is too small
126 * and we should try again. Other negative error codes can be
127 * -EFAULT and -EINVAL which we ignore at this point
129 static int __get_all_irqs(KVMS390FLICState
*flic
,
135 /* returns -ENOMEM if buffer is too small and number
136 * of queued interrupts on success */
137 r
= flic_get_all_irqs(flic
, *buf
, len
);
142 *buf
= g_try_realloc(*buf
, len
);
146 } while (r
== -ENOMEM
&& len
<= KVM_S390_FLIC_MAX_BUFFER
);
152 * kvm_flic_save - Save pending floating interrupts
153 * @f: QEMUFile containing migration state
154 * @opaque: pointer to flic device state
156 * Note: Pass buf and len to kernel. Start with one page and
157 * increase until buffer is sufficient or maxium size is
160 static void kvm_flic_save(QEMUFile
*f
, void *opaque
)
162 KVMS390FLICState
*flic
= opaque
;
163 int len
= FLIC_SAVE_INITIAL_SIZE
;
167 flic_disable_wait_pfault((struct KVMS390FLICState
*) opaque
);
169 buf
= g_try_malloc0(len
);
171 /* Storing FLIC_FAILED into the count field here will cause the
172 * target system to fail when attempting to load irqs from the
174 error_report("flic: couldn't allocate memory");
175 qemu_put_be64(f
, FLIC_FAILED
);
179 count
= __get_all_irqs(flic
, &buf
, len
);
181 error_report("flic: couldn't retrieve irqs from kernel, rc %d",
183 /* Storing FLIC_FAILED into the count field here will cause the
184 * target system to fail when attempting to load irqs from the
186 qemu_put_be64(f
, FLIC_FAILED
);
188 qemu_put_be64(f
, count
);
189 qemu_put_buffer(f
, (uint8_t *) buf
,
190 count
* sizeof(struct kvm_s390_irq
));
196 * kvm_flic_load - Load pending floating interrupts
197 * @f: QEMUFile containing migration state
198 * @opaque: pointer to flic device state
199 * @version_id: version id for migration
201 * Returns: value of flic_enqueue_irqs, -EINVAL on error
202 * Note: Do nothing when no interrupts where stored
205 static int kvm_flic_load(QEMUFile
*f
, void *opaque
, int version_id
)
212 if (version_id
!= FLIC_SAVEVM_VERSION
) {
217 flic_enable_pfault((struct KVMS390FLICState
*) opaque
);
219 count
= qemu_get_be64(f
);
220 len
= count
* sizeof(struct kvm_s390_irq
);
221 if (count
== FLIC_FAILED
) {
229 buf
= g_try_malloc0(len
);
235 if (qemu_get_buffer(f
, (uint8_t *) buf
, len
) != len
) {
239 r
= flic_enqueue_irqs(buf
, len
, (struct KVMS390FLICState
*) opaque
);
247 static void kvm_s390_flic_realize(DeviceState
*dev
, Error
**errp
)
249 KVMS390FLICState
*flic_state
= KVM_S390_FLIC(dev
);
250 struct kvm_create_device cd
= {0};
254 if (!kvm_check_extension(kvm_state
, KVM_CAP_DEVICE_CTRL
)) {
255 trace_flic_no_device_api(errno
);
259 cd
.type
= KVM_DEV_TYPE_FLIC
;
260 ret
= kvm_vm_ioctl(kvm_state
, KVM_CREATE_DEVICE
, &cd
);
262 trace_flic_create_device(errno
);
265 flic_state
->fd
= cd
.fd
;
267 /* Register savevm handler for floating interrupts */
268 register_savevm(NULL
, "s390-flic", 0, 1, kvm_flic_save
,
269 kvm_flic_load
, (void *) flic_state
);
272 static void kvm_s390_flic_unrealize(DeviceState
*dev
, Error
**errp
)
274 KVMS390FLICState
*flic_state
= KVM_S390_FLIC(dev
);
276 unregister_savevm(DEVICE(flic_state
), "s390-flic", flic_state
);
279 static void kvm_s390_flic_reset(DeviceState
*dev
)
281 KVMS390FLICState
*flic
= KVM_S390_FLIC(dev
);
282 struct kvm_device_attr attr
= {
283 .group
= KVM_DEV_FLIC_CLEAR_IRQS
,
287 if (flic
->fd
== -1) {
291 flic_disable_wait_pfault(flic
);
293 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
295 trace_flic_reset_failed(errno
);
298 flic_enable_pfault(flic
);
301 static void kvm_s390_flic_class_init(ObjectClass
*oc
, void *data
)
303 DeviceClass
*dc
= DEVICE_CLASS(oc
);
305 dc
->realize
= kvm_s390_flic_realize
;
306 dc
->unrealize
= kvm_s390_flic_unrealize
;
307 dc
->reset
= kvm_s390_flic_reset
;
310 static const TypeInfo kvm_s390_flic_info
= {
311 .name
= TYPE_KVM_S390_FLIC
,
312 .parent
= TYPE_SYS_BUS_DEVICE
,
313 .instance_size
= sizeof(KVMS390FLICState
),
314 .class_init
= kvm_s390_flic_class_init
,
317 static void kvm_s390_flic_register_types(void)
319 type_register_static(&kvm_s390_flic_info
);
322 type_init(kvm_s390_flic_register_types
)