2 * QEMU S390x KVM 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-common.h"
16 #include <sys/ioctl.h>
17 #include "qemu/error-report.h"
18 #include "hw/sysbus.h"
19 #include "sysemu/kvm.h"
20 #include "migration/qemu-file.h"
21 #include "hw/s390x/s390_flic.h"
22 #include "hw/s390x/adapter.h"
25 #define FLIC_SAVE_INITIAL_SIZE getpagesize()
26 #define FLIC_FAILED (-1UL)
27 #define FLIC_SAVEVM_VERSION 1
29 typedef struct KVMS390FLICState
{
30 S390FLICState parent_obj
;
35 DeviceState
*s390_flic_kvm_create(void)
37 DeviceState
*dev
= NULL
;
40 dev
= qdev_create(NULL
, TYPE_KVM_S390_FLIC
);
41 object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC
,
48 * flic_get_all_irqs - store all pending irqs in buffer
49 * @buf: pointer to buffer which is passed to kernel
50 * @len: length of buffer
51 * @flic: pointer to flic device state
53 * Returns: -ENOMEM if buffer is too small,
54 * -EINVAL if attr.group is invalid,
55 * -EFAULT if copying to userspace failed,
56 * on success return number of stored interrupts
58 static int flic_get_all_irqs(KVMS390FLICState
*flic
,
61 struct kvm_device_attr attr
= {
62 .group
= KVM_DEV_FLIC_GET_ALL_IRQS
,
63 .addr
= (uint64_t) buf
,
68 rc
= ioctl(flic
->fd
, KVM_GET_DEVICE_ATTR
, &attr
);
70 return rc
== -1 ? -errno
: rc
;
73 static void flic_enable_pfault(KVMS390FLICState
*flic
)
75 struct kvm_device_attr attr
= {
76 .group
= KVM_DEV_FLIC_APF_ENABLE
,
80 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
83 fprintf(stderr
, "flic: couldn't enable pfault\n");
87 static void flic_disable_wait_pfault(KVMS390FLICState
*flic
)
89 struct kvm_device_attr attr
= {
90 .group
= KVM_DEV_FLIC_APF_DISABLE_WAIT
,
94 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
97 fprintf(stderr
, "flic: couldn't disable pfault\n");
101 /** flic_enqueue_irqs - returns 0 on success
102 * @buf: pointer to buffer which is passed to kernel
103 * @len: length of buffer
104 * @flic: pointer to flic device state
106 * Returns: -EINVAL if attr.group is unknown
108 static int flic_enqueue_irqs(void *buf
, uint64_t len
,
109 KVMS390FLICState
*flic
)
112 struct kvm_device_attr attr
= {
113 .group
= KVM_DEV_FLIC_ENQUEUE
,
114 .addr
= (uint64_t) buf
,
118 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
120 return rc
? -errno
: 0;
123 int kvm_s390_inject_flic(struct kvm_s390_irq
*irq
)
125 static KVMS390FLICState
*flic
;
127 if (unlikely(!flic
)) {
128 flic
= KVM_S390_FLIC(s390_get_flic());
130 return flic_enqueue_irqs(irq
, sizeof(*irq
), flic
);
134 * __get_all_irqs - store all pending irqs in buffer
135 * @flic: pointer to flic device state
136 * @buf: pointer to pointer to a buffer
137 * @len: length of buffer
139 * Returns: return value of flic_get_all_irqs
140 * Note: Retry and increase buffer size until flic_get_all_irqs
141 * either returns a value >= 0 or a negative error code.
142 * -ENOMEM is an exception, which means the buffer is too small
143 * and we should try again. Other negative error codes can be
144 * -EFAULT and -EINVAL which we ignore at this point
146 static int __get_all_irqs(KVMS390FLICState
*flic
,
152 /* returns -ENOMEM if buffer is too small and number
153 * of queued interrupts on success */
154 r
= flic_get_all_irqs(flic
, *buf
, len
);
159 *buf
= g_try_realloc(*buf
, len
);
163 } while (r
== -ENOMEM
&& len
<= KVM_S390_FLIC_MAX_BUFFER
);
168 static int kvm_s390_register_io_adapter(S390FLICState
*fs
, uint32_t id
,
169 uint8_t isc
, bool swap
,
172 struct kvm_s390_io_adapter adapter
= {
175 .maskable
= is_maskable
,
178 KVMS390FLICState
*flic
= KVM_S390_FLIC(fs
);
180 struct kvm_device_attr attr
= {
181 .group
= KVM_DEV_FLIC_ADAPTER_REGISTER
,
182 .addr
= (uint64_t)&adapter
,
185 if (!kvm_check_extension(kvm_state
, KVM_CAP_IRQ_ROUTING
)) {
190 r
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
192 ret
= r
? -errno
: 0;
196 static int kvm_s390_io_adapter_map(S390FLICState
*fs
, uint32_t id
,
197 uint64_t map_addr
, bool do_map
)
199 struct kvm_s390_io_adapter_req req
= {
201 .type
= do_map
? KVM_S390_IO_ADAPTER_MAP
: KVM_S390_IO_ADAPTER_UNMAP
,
204 struct kvm_device_attr attr
= {
205 .group
= KVM_DEV_FLIC_ADAPTER_MODIFY
,
206 .addr
= (uint64_t)&req
,
208 KVMS390FLICState
*flic
= KVM_S390_FLIC(fs
);
211 if (!kvm_check_extension(kvm_state
, KVM_CAP_IRQ_ROUTING
)) {
216 r
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
217 return r
? -errno
: 0;
220 static int kvm_s390_add_adapter_routes(S390FLICState
*fs
,
221 AdapterRoutes
*routes
)
224 uint64_t ind_offset
= routes
->adapter
.ind_offset
;
226 for (i
= 0; i
< routes
->num_routes
; i
++) {
227 ret
= kvm_irqchip_add_adapter_route(kvm_state
, &routes
->adapter
);
231 routes
->gsi
[i
] = ret
;
232 routes
->adapter
.ind_offset
++;
234 kvm_irqchip_commit_routes(kvm_state
);
236 /* Restore passed-in structure to original state. */
237 routes
->adapter
.ind_offset
= ind_offset
;
241 kvm_irqchip_release_virq(kvm_state
, routes
->gsi
[i
]);
244 routes
->adapter
.ind_offset
= ind_offset
;
248 static void kvm_s390_release_adapter_routes(S390FLICState
*fs
,
249 AdapterRoutes
*routes
)
253 for (i
= 0; i
< routes
->num_routes
; i
++) {
254 if (routes
->gsi
[i
] >= 0) {
255 kvm_irqchip_release_virq(kvm_state
, routes
->gsi
[i
]);
262 * kvm_flic_save - Save pending floating interrupts
263 * @f: QEMUFile containing migration state
264 * @opaque: pointer to flic device state
266 * Note: Pass buf and len to kernel. Start with one page and
267 * increase until buffer is sufficient or maxium size is
270 static void kvm_flic_save(QEMUFile
*f
, void *opaque
)
272 KVMS390FLICState
*flic
= opaque
;
273 int len
= FLIC_SAVE_INITIAL_SIZE
;
277 flic_disable_wait_pfault((struct KVMS390FLICState
*) opaque
);
279 buf
= g_try_malloc0(len
);
281 /* Storing FLIC_FAILED into the count field here will cause the
282 * target system to fail when attempting to load irqs from the
284 error_report("flic: couldn't allocate memory");
285 qemu_put_be64(f
, FLIC_FAILED
);
289 count
= __get_all_irqs(flic
, &buf
, len
);
291 error_report("flic: couldn't retrieve irqs from kernel, rc %d",
293 /* Storing FLIC_FAILED into the count field here will cause the
294 * target system to fail when attempting to load irqs from the
296 qemu_put_be64(f
, FLIC_FAILED
);
298 qemu_put_be64(f
, count
);
299 qemu_put_buffer(f
, (uint8_t *) buf
,
300 count
* sizeof(struct kvm_s390_irq
));
306 * kvm_flic_load - Load pending floating interrupts
307 * @f: QEMUFile containing migration state
308 * @opaque: pointer to flic device state
309 * @version_id: version id for migration
311 * Returns: value of flic_enqueue_irqs, -EINVAL on error
312 * Note: Do nothing when no interrupts where stored
315 static int kvm_flic_load(QEMUFile
*f
, void *opaque
, int version_id
)
322 if (version_id
!= FLIC_SAVEVM_VERSION
) {
327 flic_enable_pfault((struct KVMS390FLICState
*) opaque
);
329 count
= qemu_get_be64(f
);
330 len
= count
* sizeof(struct kvm_s390_irq
);
331 if (count
== FLIC_FAILED
) {
339 buf
= g_try_malloc0(len
);
345 if (qemu_get_buffer(f
, (uint8_t *) buf
, len
) != len
) {
349 r
= flic_enqueue_irqs(buf
, len
, (struct KVMS390FLICState
*) opaque
);
357 static void kvm_s390_flic_realize(DeviceState
*dev
, Error
**errp
)
359 KVMS390FLICState
*flic_state
= KVM_S390_FLIC(dev
);
360 struct kvm_create_device cd
= {0};
364 if (!kvm_check_extension(kvm_state
, KVM_CAP_DEVICE_CTRL
)) {
365 trace_flic_no_device_api(errno
);
369 cd
.type
= KVM_DEV_TYPE_FLIC
;
370 ret
= kvm_vm_ioctl(kvm_state
, KVM_CREATE_DEVICE
, &cd
);
372 trace_flic_create_device(errno
);
375 flic_state
->fd
= cd
.fd
;
377 /* Register savevm handler for floating interrupts */
378 register_savevm(NULL
, "s390-flic", 0, 1, kvm_flic_save
,
379 kvm_flic_load
, (void *) flic_state
);
382 static void kvm_s390_flic_unrealize(DeviceState
*dev
, Error
**errp
)
384 KVMS390FLICState
*flic_state
= KVM_S390_FLIC(dev
);
386 unregister_savevm(DEVICE(flic_state
), "s390-flic", flic_state
);
389 static void kvm_s390_flic_reset(DeviceState
*dev
)
391 KVMS390FLICState
*flic
= KVM_S390_FLIC(dev
);
392 struct kvm_device_attr attr
= {
393 .group
= KVM_DEV_FLIC_CLEAR_IRQS
,
397 if (flic
->fd
== -1) {
401 flic_disable_wait_pfault(flic
);
403 rc
= ioctl(flic
->fd
, KVM_SET_DEVICE_ATTR
, &attr
);
405 trace_flic_reset_failed(errno
);
408 flic_enable_pfault(flic
);
411 static void kvm_s390_flic_class_init(ObjectClass
*oc
, void *data
)
413 DeviceClass
*dc
= DEVICE_CLASS(oc
);
414 S390FLICStateClass
*fsc
= S390_FLIC_COMMON_CLASS(oc
);
416 dc
->realize
= kvm_s390_flic_realize
;
417 dc
->unrealize
= kvm_s390_flic_unrealize
;
418 dc
->reset
= kvm_s390_flic_reset
;
419 fsc
->register_io_adapter
= kvm_s390_register_io_adapter
;
420 fsc
->io_adapter_map
= kvm_s390_io_adapter_map
;
421 fsc
->add_adapter_routes
= kvm_s390_add_adapter_routes
;
422 fsc
->release_adapter_routes
= kvm_s390_release_adapter_routes
;
425 static const TypeInfo kvm_s390_flic_info
= {
426 .name
= TYPE_KVM_S390_FLIC
,
427 .parent
= TYPE_S390_FLIC_COMMON
,
428 .instance_size
= sizeof(KVMS390FLICState
),
429 .class_init
= kvm_s390_flic_class_init
,
432 static void kvm_s390_flic_register_types(void)
434 type_register_static(&kvm_s390_flic_info
);
437 type_init(kvm_s390_flic_register_types
)