17b35d0c4SCornelia Huck /*
27b35d0c4SCornelia Huck * QEMU S390x KVM floating interrupt controller (flic)
37b35d0c4SCornelia Huck *
47b35d0c4SCornelia Huck * Copyright 2014 IBM Corp.
57b35d0c4SCornelia Huck * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
67b35d0c4SCornelia Huck * Cornelia Huck <cornelia.huck@de.ibm.com>
77b35d0c4SCornelia Huck *
87b35d0c4SCornelia Huck * This work is licensed under the terms of the GNU GPL, version 2 or (at
97b35d0c4SCornelia Huck * your option) any later version. See the COPYING file in the top-level
107b35d0c4SCornelia Huck * directory.
117b35d0c4SCornelia Huck */
127b35d0c4SCornelia Huck
1390191d07SPeter Maydell #include "qemu/osdep.h"
1467043607SCho, Yu-Chen #include "kvm/kvm_s390x.h"
157b35d0c4SCornelia Huck #include <sys/ioctl.h>
167b35d0c4SCornelia Huck #include "qemu/error-report.h"
170b8fa32fSMarkus Armbruster #include "qemu/module.h"
18f62f2109SHalil Pasic #include "qapi/error.h"
197b35d0c4SCornelia Huck #include "sysemu/kvm.h"
207b35d0c4SCornelia Huck #include "hw/s390x/s390_flic.h"
21d426d9fbSCornelia Huck #include "hw/s390x/adapter.h"
226c1dd652SFei Li #include "hw/s390x/css.h"
23ca77ee28SMarkus Armbruster #include "migration/qemu-file-types.h"
247b35d0c4SCornelia Huck #include "trace.h"
25db1015e9SEduardo Habkost #include "qom/object.h"
267b35d0c4SCornelia Huck
278e3b0cbbSMarc-André Lureau #define FLIC_SAVE_INITIAL_SIZE qemu_real_host_page_size()
287b35d0c4SCornelia Huck #define FLIC_FAILED (-1UL)
297b35d0c4SCornelia Huck #define FLIC_SAVEVM_VERSION 1
307b35d0c4SCornelia Huck
31b13f9bdfSEduardo Habkost struct KVMS390FLICState{
327b35d0c4SCornelia Huck S390FLICState parent_obj;
337b35d0c4SCornelia Huck
347b35d0c4SCornelia Huck uint32_t fd;
359eccb862SHalil Pasic bool clear_io_supported;
36b13f9bdfSEduardo Habkost };
377b35d0c4SCornelia Huck
s390_get_kvm_flic(S390FLICState * fs)38c21a6106SDavid Hildenbrand static KVMS390FLICState *s390_get_kvm_flic(S390FLICState *fs)
39c21a6106SDavid Hildenbrand {
40c21a6106SDavid Hildenbrand static KVMS390FLICState *flic;
41c21a6106SDavid Hildenbrand
42c21a6106SDavid Hildenbrand if (!flic) {
43c21a6106SDavid Hildenbrand /* we only have one flic device, so this is fine to cache */
44c21a6106SDavid Hildenbrand flic = KVM_S390_FLIC(fs);
45c21a6106SDavid Hildenbrand }
46c21a6106SDavid Hildenbrand return flic;
47c21a6106SDavid Hildenbrand }
48c21a6106SDavid Hildenbrand
497b35d0c4SCornelia Huck /**
507b35d0c4SCornelia Huck * flic_get_all_irqs - store all pending irqs in buffer
517b35d0c4SCornelia Huck * @buf: pointer to buffer which is passed to kernel
527b35d0c4SCornelia Huck * @len: length of buffer
537b35d0c4SCornelia Huck * @flic: pointer to flic device state
547b35d0c4SCornelia Huck *
557b35d0c4SCornelia Huck * Returns: -ENOMEM if buffer is too small,
567b35d0c4SCornelia Huck * -EINVAL if attr.group is invalid,
577b35d0c4SCornelia Huck * -EFAULT if copying to userspace failed,
587b35d0c4SCornelia Huck * on success return number of stored interrupts
597b35d0c4SCornelia Huck */
flic_get_all_irqs(KVMS390FLICState * flic,void * buf,int len)607b35d0c4SCornelia Huck static int flic_get_all_irqs(KVMS390FLICState *flic,
617b35d0c4SCornelia Huck void *buf, int len)
627b35d0c4SCornelia Huck {
637b35d0c4SCornelia Huck struct kvm_device_attr attr = {
647b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_GET_ALL_IRQS,
657b35d0c4SCornelia Huck .addr = (uint64_t) buf,
667b35d0c4SCornelia Huck .attr = len,
677b35d0c4SCornelia Huck };
687b35d0c4SCornelia Huck int rc;
697b35d0c4SCornelia Huck
707b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
717b35d0c4SCornelia Huck
727b35d0c4SCornelia Huck return rc == -1 ? -errno : rc;
737b35d0c4SCornelia Huck }
747b35d0c4SCornelia Huck
flic_enable_pfault(KVMS390FLICState * flic)757b35d0c4SCornelia Huck static void flic_enable_pfault(KVMS390FLICState *flic)
767b35d0c4SCornelia Huck {
777b35d0c4SCornelia Huck struct kvm_device_attr attr = {
787b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_APF_ENABLE,
797b35d0c4SCornelia Huck };
807b35d0c4SCornelia Huck int rc;
817b35d0c4SCornelia Huck
827b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
837b35d0c4SCornelia Huck
847b35d0c4SCornelia Huck if (rc) {
857b35d0c4SCornelia Huck fprintf(stderr, "flic: couldn't enable pfault\n");
867b35d0c4SCornelia Huck }
877b35d0c4SCornelia Huck }
887b35d0c4SCornelia Huck
flic_disable_wait_pfault(KVMS390FLICState * flic)897b35d0c4SCornelia Huck static void flic_disable_wait_pfault(KVMS390FLICState *flic)
907b35d0c4SCornelia Huck {
917b35d0c4SCornelia Huck struct kvm_device_attr attr = {
927b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
937b35d0c4SCornelia Huck };
947b35d0c4SCornelia Huck int rc;
957b35d0c4SCornelia Huck
967b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
977b35d0c4SCornelia Huck
987b35d0c4SCornelia Huck if (rc) {
997b35d0c4SCornelia Huck fprintf(stderr, "flic: couldn't disable pfault\n");
1007b35d0c4SCornelia Huck }
1017b35d0c4SCornelia Huck }
1027b35d0c4SCornelia Huck
1037b35d0c4SCornelia Huck /** flic_enqueue_irqs - returns 0 on success
1047b35d0c4SCornelia Huck * @buf: pointer to buffer which is passed to kernel
1057b35d0c4SCornelia Huck * @len: length of buffer
1067b35d0c4SCornelia Huck * @flic: pointer to flic device state
1077b35d0c4SCornelia Huck *
1087b35d0c4SCornelia Huck * Returns: -EINVAL if attr.group is unknown
1097b35d0c4SCornelia Huck */
flic_enqueue_irqs(void * buf,uint64_t len,KVMS390FLICState * flic)1107b35d0c4SCornelia Huck static int flic_enqueue_irqs(void *buf, uint64_t len,
1117b35d0c4SCornelia Huck KVMS390FLICState *flic)
1127b35d0c4SCornelia Huck {
1137b35d0c4SCornelia Huck int rc;
1147b35d0c4SCornelia Huck struct kvm_device_attr attr = {
1157b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_ENQUEUE,
1167b35d0c4SCornelia Huck .addr = (uint64_t) buf,
1177b35d0c4SCornelia Huck .attr = len,
1187b35d0c4SCornelia Huck };
1197b35d0c4SCornelia Huck
1207b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
1217b35d0c4SCornelia Huck
1227b35d0c4SCornelia Huck return rc ? -errno : 0;
1237b35d0c4SCornelia Huck }
1247b35d0c4SCornelia Huck
kvm_s390_inject_flic(S390FLICState * fs,struct kvm_s390_irq * irq)125e6505d53SDavid Hildenbrand static void kvm_s390_inject_flic(S390FLICState *fs, struct kvm_s390_irq *irq)
126bbd8bb8eSCornelia Huck {
127e6505d53SDavid Hildenbrand static bool use_flic = true;
128e6505d53SDavid Hildenbrand int r;
129bbd8bb8eSCornelia Huck
130e6505d53SDavid Hildenbrand if (use_flic) {
131c21a6106SDavid Hildenbrand r = flic_enqueue_irqs(irq, sizeof(*irq), s390_get_kvm_flic(fs));
132e6505d53SDavid Hildenbrand if (r == -ENOSYS) {
133e6505d53SDavid Hildenbrand use_flic = false;
134bbd8bb8eSCornelia Huck }
135e6505d53SDavid Hildenbrand if (!r) {
136e6505d53SDavid Hildenbrand return;
137e6505d53SDavid Hildenbrand }
138e6505d53SDavid Hildenbrand }
139e6505d53SDavid Hildenbrand /* fallback to legacy KVM IOCTL in case FLIC fails */
140e6505d53SDavid Hildenbrand kvm_s390_floating_interrupt_legacy(irq);
141e6505d53SDavid Hildenbrand }
142e6505d53SDavid Hildenbrand
kvm_s390_inject_service(S390FLICState * fs,uint32_t parm)143e6505d53SDavid Hildenbrand static void kvm_s390_inject_service(S390FLICState *fs, uint32_t parm)
144e6505d53SDavid Hildenbrand {
145e6505d53SDavid Hildenbrand struct kvm_s390_irq irq = {
146e6505d53SDavid Hildenbrand .type = KVM_S390_INT_SERVICE,
147e6505d53SDavid Hildenbrand .u.ext.ext_params = parm,
148e6505d53SDavid Hildenbrand };
149e6505d53SDavid Hildenbrand
150e6505d53SDavid Hildenbrand kvm_s390_inject_flic(fs, &irq);
151e6505d53SDavid Hildenbrand }
152e6505d53SDavid Hildenbrand
kvm_s390_inject_io(S390FLICState * fs,uint16_t subchannel_id,uint16_t subchannel_nr,uint32_t io_int_parm,uint32_t io_int_word)153e6505d53SDavid Hildenbrand static void kvm_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id,
154e6505d53SDavid Hildenbrand uint16_t subchannel_nr, uint32_t io_int_parm,
155e6505d53SDavid Hildenbrand uint32_t io_int_word)
156e6505d53SDavid Hildenbrand {
157e6505d53SDavid Hildenbrand struct kvm_s390_irq irq = {
158e6505d53SDavid Hildenbrand .u.io.subchannel_id = subchannel_id,
159e6505d53SDavid Hildenbrand .u.io.subchannel_nr = subchannel_nr,
160e6505d53SDavid Hildenbrand .u.io.io_int_parm = io_int_parm,
161e6505d53SDavid Hildenbrand .u.io.io_int_word = io_int_word,
162e6505d53SDavid Hildenbrand };
163e6505d53SDavid Hildenbrand
164e6505d53SDavid Hildenbrand if (io_int_word & IO_INT_WORD_AI) {
165e6505d53SDavid Hildenbrand irq.type = KVM_S390_INT_IO(1, 0, 0, 0);
166e6505d53SDavid Hildenbrand } else {
167e6505d53SDavid Hildenbrand irq.type = KVM_S390_INT_IO(0, (subchannel_id & 0xff00) >> 8,
168e6505d53SDavid Hildenbrand (subchannel_id & 0x0006),
169e6505d53SDavid Hildenbrand subchannel_nr);
170e6505d53SDavid Hildenbrand }
171e6505d53SDavid Hildenbrand kvm_s390_inject_flic(fs, &irq);
172e6505d53SDavid Hildenbrand }
173e6505d53SDavid Hildenbrand
kvm_s390_inject_crw_mchk(S390FLICState * fs)174e6505d53SDavid Hildenbrand static void kvm_s390_inject_crw_mchk(S390FLICState *fs)
175e6505d53SDavid Hildenbrand {
176e6505d53SDavid Hildenbrand struct kvm_s390_irq irq = {
177e6505d53SDavid Hildenbrand .type = KVM_S390_MCHK,
178e6505d53SDavid Hildenbrand .u.mchk.cr14 = CR14_CHANNEL_REPORT_SC,
179e6505d53SDavid Hildenbrand .u.mchk.mcic = s390_build_validity_mcic() | MCIC_SC_CP,
180e6505d53SDavid Hildenbrand };
181e6505d53SDavid Hildenbrand
182e6505d53SDavid Hildenbrand kvm_s390_inject_flic(fs, &irq);
183bbd8bb8eSCornelia Huck }
184bbd8bb8eSCornelia Huck
kvm_s390_clear_io_flic(S390FLICState * fs,uint16_t subchannel_id,uint16_t subchannel_nr)1859eccb862SHalil Pasic static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
1869eccb862SHalil Pasic uint16_t subchannel_nr)
1879eccb862SHalil Pasic {
188c21a6106SDavid Hildenbrand KVMS390FLICState *flic = s390_get_kvm_flic(fs);
1899eccb862SHalil Pasic int rc;
1909eccb862SHalil Pasic uint32_t sid = subchannel_id << 16 | subchannel_nr;
1919eccb862SHalil Pasic struct kvm_device_attr attr = {
1929eccb862SHalil Pasic .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
1939eccb862SHalil Pasic .addr = (uint64_t) &sid,
1949eccb862SHalil Pasic .attr = sizeof(sid),
1959eccb862SHalil Pasic };
1969eccb862SHalil Pasic if (unlikely(!flic->clear_io_supported)) {
1979eccb862SHalil Pasic return -ENOSYS;
1989eccb862SHalil Pasic }
1999eccb862SHalil Pasic rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
2009eccb862SHalil Pasic return rc ? -errno : 0;
2019eccb862SHalil Pasic }
2029eccb862SHalil Pasic
kvm_s390_modify_ais_mode(S390FLICState * fs,uint8_t isc,uint16_t mode)2036c1dd652SFei Li static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc,
2046c1dd652SFei Li uint16_t mode)
2056c1dd652SFei Li {
206c21a6106SDavid Hildenbrand KVMS390FLICState *flic = s390_get_kvm_flic(fs);
2076c1dd652SFei Li struct kvm_s390_ais_req req = {
2086c1dd652SFei Li .isc = isc,
2096c1dd652SFei Li .mode = mode,
2106c1dd652SFei Li };
2116c1dd652SFei Li struct kvm_device_attr attr = {
2126c1dd652SFei Li .group = KVM_DEV_FLIC_AISM,
2136c1dd652SFei Li .addr = (uint64_t)&req,
2146c1dd652SFei Li };
2156c1dd652SFei Li
2166c1dd652SFei Li if (!fs->ais_supported) {
2176c1dd652SFei Li return -ENOSYS;
2186c1dd652SFei Li }
2196c1dd652SFei Li
2206c1dd652SFei Li return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
2216c1dd652SFei Li }
2226c1dd652SFei Li
kvm_s390_inject_airq(S390FLICState * fs,uint8_t type,uint8_t isc,uint8_t flags)2231622ffd5SYi Min Zhao static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type,
2241622ffd5SYi Min Zhao uint8_t isc, uint8_t flags)
2251622ffd5SYi Min Zhao {
226c21a6106SDavid Hildenbrand KVMS390FLICState *flic = s390_get_kvm_flic(fs);
2271622ffd5SYi Min Zhao uint32_t id = css_get_adapter_id(type, isc);
2281622ffd5SYi Min Zhao struct kvm_device_attr attr = {
2291622ffd5SYi Min Zhao .group = KVM_DEV_FLIC_AIRQ_INJECT,
2301622ffd5SYi Min Zhao .attr = id,
2311622ffd5SYi Min Zhao };
2321622ffd5SYi Min Zhao
2331622ffd5SYi Min Zhao if (!fs->ais_supported) {
2341622ffd5SYi Min Zhao return -ENOSYS;
2351622ffd5SYi Min Zhao }
2361622ffd5SYi Min Zhao
2371622ffd5SYi Min Zhao return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
2381622ffd5SYi Min Zhao }
2391622ffd5SYi Min Zhao
2407b35d0c4SCornelia Huck /**
2417b35d0c4SCornelia Huck * __get_all_irqs - store all pending irqs in buffer
2427b35d0c4SCornelia Huck * @flic: pointer to flic device state
2437b35d0c4SCornelia Huck * @buf: pointer to pointer to a buffer
2447b35d0c4SCornelia Huck * @len: length of buffer
2457b35d0c4SCornelia Huck *
2467b35d0c4SCornelia Huck * Returns: return value of flic_get_all_irqs
2477b35d0c4SCornelia Huck * Note: Retry and increase buffer size until flic_get_all_irqs
2487b35d0c4SCornelia Huck * either returns a value >= 0 or a negative error code.
2497b35d0c4SCornelia Huck * -ENOMEM is an exception, which means the buffer is too small
2507b35d0c4SCornelia Huck * and we should try again. Other negative error codes can be
2517b35d0c4SCornelia Huck * -EFAULT and -EINVAL which we ignore at this point
2527b35d0c4SCornelia Huck */
__get_all_irqs(KVMS390FLICState * flic,void ** buf,int len)2537b35d0c4SCornelia Huck static int __get_all_irqs(KVMS390FLICState *flic,
2547b35d0c4SCornelia Huck void **buf, int len)
2557b35d0c4SCornelia Huck {
2567b35d0c4SCornelia Huck int r;
2577b35d0c4SCornelia Huck
2587b35d0c4SCornelia Huck do {
2597b35d0c4SCornelia Huck /* returns -ENOMEM if buffer is too small and number
2607b35d0c4SCornelia Huck * of queued interrupts on success */
2617b35d0c4SCornelia Huck r = flic_get_all_irqs(flic, *buf, len);
2627b35d0c4SCornelia Huck if (r >= 0) {
2637b35d0c4SCornelia Huck break;
2647b35d0c4SCornelia Huck }
2657b35d0c4SCornelia Huck len *= 2;
2667b35d0c4SCornelia Huck *buf = g_try_realloc(*buf, len);
2677b35d0c4SCornelia Huck if (!buf) {
2687b35d0c4SCornelia Huck return -ENOMEM;
2697b35d0c4SCornelia Huck }
2707b35d0c4SCornelia Huck } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
2717b35d0c4SCornelia Huck
2727b35d0c4SCornelia Huck return r;
2737b35d0c4SCornelia Huck }
2747b35d0c4SCornelia Huck
kvm_s390_register_io_adapter(S390FLICState * fs,uint32_t id,uint8_t isc,bool swap,bool is_maskable,uint8_t flags)27503cf077aSCornelia Huck static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
27603cf077aSCornelia Huck uint8_t isc, bool swap,
2771497c160SFei Li bool is_maskable, uint8_t flags)
27803cf077aSCornelia Huck {
27903cf077aSCornelia Huck struct kvm_s390_io_adapter adapter = {
28003cf077aSCornelia Huck .id = id,
28103cf077aSCornelia Huck .isc = isc,
28203cf077aSCornelia Huck .maskable = is_maskable,
28303cf077aSCornelia Huck .swap = swap,
2841497c160SFei Li .flags = flags,
28503cf077aSCornelia Huck };
28603cf077aSCornelia Huck KVMS390FLICState *flic = KVM_S390_FLIC(fs);
2879be38598SEduardo Habkost int r;
28803cf077aSCornelia Huck struct kvm_device_attr attr = {
28903cf077aSCornelia Huck .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
29003cf077aSCornelia Huck .addr = (uint64_t)&adapter,
29103cf077aSCornelia Huck };
29203cf077aSCornelia Huck
2934cbd6c41SFei Li if (!kvm_gsi_routing_enabled()) {
29408da527fSCornelia Huck /* nothing to do */
29508da527fSCornelia Huck return 0;
29603cf077aSCornelia Huck }
29703cf077aSCornelia Huck
29803cf077aSCornelia Huck r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
29903cf077aSCornelia Huck
3009be38598SEduardo Habkost return r ? -errno : 0;
30103cf077aSCornelia Huck }
30203cf077aSCornelia Huck
kvm_s390_io_adapter_map(S390FLICState * fs,uint32_t id,uint64_t map_addr,bool do_map)303d426d9fbSCornelia Huck static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
304d426d9fbSCornelia Huck uint64_t map_addr, bool do_map)
305d426d9fbSCornelia Huck {
306d426d9fbSCornelia Huck struct kvm_s390_io_adapter_req req = {
307d426d9fbSCornelia Huck .id = id,
308d426d9fbSCornelia Huck .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
309d426d9fbSCornelia Huck .addr = map_addr,
310d426d9fbSCornelia Huck };
311d426d9fbSCornelia Huck struct kvm_device_attr attr = {
312d426d9fbSCornelia Huck .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
313d426d9fbSCornelia Huck .addr = (uint64_t)&req,
314d426d9fbSCornelia Huck };
315c21a6106SDavid Hildenbrand KVMS390FLICState *flic = s390_get_kvm_flic(fs);
316d426d9fbSCornelia Huck int r;
317d426d9fbSCornelia Huck
3184cbd6c41SFei Li if (!kvm_gsi_routing_enabled()) {
31908da527fSCornelia Huck /* nothing to do */
32008da527fSCornelia Huck return 0;
321d426d9fbSCornelia Huck }
322d426d9fbSCornelia Huck
323d426d9fbSCornelia Huck r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
324d426d9fbSCornelia Huck return r ? -errno : 0;
325d426d9fbSCornelia Huck }
326d426d9fbSCornelia Huck
kvm_irqchip_add_adapter_route(KVMState * s,AdapterInfo * adapter)32748663349SPaolo Bonzini static int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
32848663349SPaolo Bonzini {
32948663349SPaolo Bonzini struct kvm_irq_routing_entry kroute = {};
33048663349SPaolo Bonzini int virq;
33148663349SPaolo Bonzini
33248663349SPaolo Bonzini if (!kvm_gsi_routing_enabled()) {
33348663349SPaolo Bonzini return -ENOSYS;
33448663349SPaolo Bonzini }
33548663349SPaolo Bonzini
33648663349SPaolo Bonzini virq = kvm_irqchip_get_virq(s);
33748663349SPaolo Bonzini if (virq < 0) {
33848663349SPaolo Bonzini return virq;
33948663349SPaolo Bonzini }
34048663349SPaolo Bonzini
34148663349SPaolo Bonzini kroute.gsi = virq;
34248663349SPaolo Bonzini kroute.type = KVM_IRQ_ROUTING_S390_ADAPTER;
34348663349SPaolo Bonzini kroute.flags = 0;
34448663349SPaolo Bonzini kroute.u.adapter.summary_addr = adapter->summary_addr;
34548663349SPaolo Bonzini kroute.u.adapter.ind_addr = adapter->ind_addr;
34648663349SPaolo Bonzini kroute.u.adapter.summary_offset = adapter->summary_offset;
34748663349SPaolo Bonzini kroute.u.adapter.ind_offset = adapter->ind_offset;
34848663349SPaolo Bonzini kroute.u.adapter.adapter_id = adapter->adapter_id;
34948663349SPaolo Bonzini
35048663349SPaolo Bonzini kvm_add_routing_entry(s, &kroute);
35148663349SPaolo Bonzini
35248663349SPaolo Bonzini return virq;
35348663349SPaolo Bonzini }
35448663349SPaolo Bonzini
kvm_s390_add_adapter_routes(S390FLICState * fs,AdapterRoutes * routes)355d426d9fbSCornelia Huck static int kvm_s390_add_adapter_routes(S390FLICState *fs,
356d426d9fbSCornelia Huck AdapterRoutes *routes)
357d426d9fbSCornelia Huck {
358d426d9fbSCornelia Huck int ret, i;
359d426d9fbSCornelia Huck uint64_t ind_offset = routes->adapter.ind_offset;
360d426d9fbSCornelia Huck
3613c5fd807SCornelia Huck if (!kvm_gsi_routing_enabled()) {
3623c5fd807SCornelia Huck return -ENOSYS;
3633c5fd807SCornelia Huck }
3643c5fd807SCornelia Huck
365d426d9fbSCornelia Huck for (i = 0; i < routes->num_routes; i++) {
366d426d9fbSCornelia Huck ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
367d426d9fbSCornelia Huck if (ret < 0) {
368d426d9fbSCornelia Huck goto out_undo;
369d426d9fbSCornelia Huck }
370d426d9fbSCornelia Huck routes->gsi[i] = ret;
371d426d9fbSCornelia Huck routes->adapter.ind_offset++;
372d426d9fbSCornelia Huck }
373c0194a00SJens Freimann kvm_irqchip_commit_routes(kvm_state);
374c0194a00SJens Freimann
375d426d9fbSCornelia Huck /* Restore passed-in structure to original state. */
376d426d9fbSCornelia Huck routes->adapter.ind_offset = ind_offset;
377d426d9fbSCornelia Huck return 0;
378d426d9fbSCornelia Huck out_undo:
379d426d9fbSCornelia Huck while (--i >= 0) {
380d426d9fbSCornelia Huck kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
381d426d9fbSCornelia Huck routes->gsi[i] = -1;
382d426d9fbSCornelia Huck }
383d426d9fbSCornelia Huck routes->adapter.ind_offset = ind_offset;
384d426d9fbSCornelia Huck return ret;
385d426d9fbSCornelia Huck }
386d426d9fbSCornelia Huck
kvm_s390_release_adapter_routes(S390FLICState * fs,AdapterRoutes * routes)387d426d9fbSCornelia Huck static void kvm_s390_release_adapter_routes(S390FLICState *fs,
388d426d9fbSCornelia Huck AdapterRoutes *routes)
389d426d9fbSCornelia Huck {
390d426d9fbSCornelia Huck int i;
391d426d9fbSCornelia Huck
3923c5fd807SCornelia Huck if (!kvm_gsi_routing_enabled()) {
3933c5fd807SCornelia Huck return;
3943c5fd807SCornelia Huck }
3953c5fd807SCornelia Huck
396d426d9fbSCornelia Huck for (i = 0; i < routes->num_routes; i++) {
397d426d9fbSCornelia Huck if (routes->gsi[i] >= 0) {
398d426d9fbSCornelia Huck kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
399d426d9fbSCornelia Huck routes->gsi[i] = -1;
400d426d9fbSCornelia Huck }
401d426d9fbSCornelia Huck }
402d426d9fbSCornelia Huck }
403d426d9fbSCornelia Huck
4047b35d0c4SCornelia Huck /**
4057b35d0c4SCornelia Huck * kvm_flic_save - Save pending floating interrupts
4067b35d0c4SCornelia Huck * @f: QEMUFile containing migration state
4077b35d0c4SCornelia Huck * @opaque: pointer to flic device state
408f2cab7f1SCornelia Huck * @size: ignored
4097b35d0c4SCornelia Huck *
4107b35d0c4SCornelia Huck * Note: Pass buf and len to kernel. Start with one page and
411cced0d65SMichael Tokarev * increase until buffer is sufficient or maximum size is
4127b35d0c4SCornelia Huck * reached
4137b35d0c4SCornelia Huck */
kvm_flic_save(QEMUFile * f,void * opaque,size_t size,const VMStateField * field,JSONWriter * vmdesc)4142c21ee76SJianjun Duan static int kvm_flic_save(QEMUFile *f, void *opaque, size_t size,
4153ddba9a9SMarkus Armbruster const VMStateField *field, JSONWriter *vmdesc)
4167b35d0c4SCornelia Huck {
4177b35d0c4SCornelia Huck KVMS390FLICState *flic = opaque;
4187b35d0c4SCornelia Huck int len = FLIC_SAVE_INITIAL_SIZE;
4197b35d0c4SCornelia Huck void *buf;
4207b35d0c4SCornelia Huck int count;
421ba690c71SCornelia Huck int r = 0;
4227b35d0c4SCornelia Huck
4237b35d0c4SCornelia Huck flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
4247b35d0c4SCornelia Huck
4257b35d0c4SCornelia Huck buf = g_try_malloc0(len);
4267b35d0c4SCornelia Huck if (!buf) {
4277b35d0c4SCornelia Huck /* Storing FLIC_FAILED into the count field here will cause the
4287b35d0c4SCornelia Huck * target system to fail when attempting to load irqs from the
4297b35d0c4SCornelia Huck * migration state */
4307b35d0c4SCornelia Huck error_report("flic: couldn't allocate memory");
4317b35d0c4SCornelia Huck qemu_put_be64(f, FLIC_FAILED);
432ba690c71SCornelia Huck return -ENOMEM;
4337b35d0c4SCornelia Huck }
4347b35d0c4SCornelia Huck
4357b35d0c4SCornelia Huck count = __get_all_irqs(flic, &buf, len);
4367b35d0c4SCornelia Huck if (count < 0) {
4377b35d0c4SCornelia Huck error_report("flic: couldn't retrieve irqs from kernel, rc %d",
4387b35d0c4SCornelia Huck count);
4397b35d0c4SCornelia Huck /* Storing FLIC_FAILED into the count field here will cause the
4407b35d0c4SCornelia Huck * target system to fail when attempting to load irqs from the
4417b35d0c4SCornelia Huck * migration state */
4427b35d0c4SCornelia Huck qemu_put_be64(f, FLIC_FAILED);
443ba690c71SCornelia Huck r = count;
4447b35d0c4SCornelia Huck } else {
4457b35d0c4SCornelia Huck qemu_put_be64(f, count);
4467b35d0c4SCornelia Huck qemu_put_buffer(f, (uint8_t *) buf,
4477b35d0c4SCornelia Huck count * sizeof(struct kvm_s390_irq));
4487b35d0c4SCornelia Huck }
4497b35d0c4SCornelia Huck g_free(buf);
4502c21ee76SJianjun Duan
451ba690c71SCornelia Huck return r;
4527b35d0c4SCornelia Huck }
4537b35d0c4SCornelia Huck
4547b35d0c4SCornelia Huck /**
4557b35d0c4SCornelia Huck * kvm_flic_load - Load pending floating interrupts
4567b35d0c4SCornelia Huck * @f: QEMUFile containing migration state
4577b35d0c4SCornelia Huck * @opaque: pointer to flic device state
458f2cab7f1SCornelia Huck * @size: ignored
4597b35d0c4SCornelia Huck *
4607b35d0c4SCornelia Huck * Returns: value of flic_enqueue_irqs, -EINVAL on error
4617b35d0c4SCornelia Huck * Note: Do nothing when no interrupts where stored
4627b35d0c4SCornelia Huck * in QEMUFile
4637b35d0c4SCornelia Huck */
kvm_flic_load(QEMUFile * f,void * opaque,size_t size,const VMStateField * field)4642c21ee76SJianjun Duan static int kvm_flic_load(QEMUFile *f, void *opaque, size_t size,
46503fee66fSMarc-André Lureau const VMStateField *field)
4667b35d0c4SCornelia Huck {
4677b35d0c4SCornelia Huck uint64_t len = 0;
4687b35d0c4SCornelia Huck uint64_t count = 0;
4697b35d0c4SCornelia Huck void *buf = NULL;
4707b35d0c4SCornelia Huck int r = 0;
4717b35d0c4SCornelia Huck
4727b35d0c4SCornelia Huck flic_enable_pfault((struct KVMS390FLICState *) opaque);
4737b35d0c4SCornelia Huck
4747b35d0c4SCornelia Huck count = qemu_get_be64(f);
4757b35d0c4SCornelia Huck len = count * sizeof(struct kvm_s390_irq);
4767b35d0c4SCornelia Huck if (count == FLIC_FAILED) {
47765569bbfSDaniel Henrique Barboza return -EINVAL;
4787b35d0c4SCornelia Huck }
4797b35d0c4SCornelia Huck if (count == 0) {
48065569bbfSDaniel Henrique Barboza return 0;
4817b35d0c4SCornelia Huck }
4827b35d0c4SCornelia Huck buf = g_try_malloc0(len);
4837b35d0c4SCornelia Huck if (!buf) {
48465569bbfSDaniel Henrique Barboza return -ENOMEM;
4857b35d0c4SCornelia Huck }
4867b35d0c4SCornelia Huck
4877b35d0c4SCornelia Huck if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
4887b35d0c4SCornelia Huck r = -EINVAL;
4897b35d0c4SCornelia Huck goto out_free;
4907b35d0c4SCornelia Huck }
4917b35d0c4SCornelia Huck r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
4927b35d0c4SCornelia Huck
4937b35d0c4SCornelia Huck out_free:
4947b35d0c4SCornelia Huck g_free(buf);
4957b35d0c4SCornelia Huck return r;
4967b35d0c4SCornelia Huck }
4977b35d0c4SCornelia Huck
498e7be8d49SYi Min Zhao typedef struct KVMS390FLICStateMigTmp {
499e7be8d49SYi Min Zhao KVMS390FLICState *parent;
500e7be8d49SYi Min Zhao uint8_t simm;
501e7be8d49SYi Min Zhao uint8_t nimm;
502e7be8d49SYi Min Zhao } KVMS390FLICStateMigTmp;
503e7be8d49SYi Min Zhao
kvm_flic_ais_pre_save(void * opaque)50444b1ff31SDr. David Alan Gilbert static int kvm_flic_ais_pre_save(void *opaque)
505e7be8d49SYi Min Zhao {
506e7be8d49SYi Min Zhao KVMS390FLICStateMigTmp *tmp = opaque;
507e7be8d49SYi Min Zhao KVMS390FLICState *flic = tmp->parent;
508e7be8d49SYi Min Zhao struct kvm_s390_ais_all ais;
509e7be8d49SYi Min Zhao struct kvm_device_attr attr = {
510e7be8d49SYi Min Zhao .group = KVM_DEV_FLIC_AISM_ALL,
511e7be8d49SYi Min Zhao .addr = (uint64_t)&ais,
512e7be8d49SYi Min Zhao .attr = sizeof(ais),
513e7be8d49SYi Min Zhao };
514e7be8d49SYi Min Zhao
515e7be8d49SYi Min Zhao if (ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr)) {
516e7be8d49SYi Min Zhao error_report("Failed to retrieve kvm flic ais states");
51744b1ff31SDr. David Alan Gilbert return -EINVAL;
518e7be8d49SYi Min Zhao }
519e7be8d49SYi Min Zhao
520e7be8d49SYi Min Zhao tmp->simm = ais.simm;
521e7be8d49SYi Min Zhao tmp->nimm = ais.nimm;
52244b1ff31SDr. David Alan Gilbert
52344b1ff31SDr. David Alan Gilbert return 0;
524e7be8d49SYi Min Zhao }
525e7be8d49SYi Min Zhao
kvm_flic_ais_post_load(void * opaque,int version_id)526e7be8d49SYi Min Zhao static int kvm_flic_ais_post_load(void *opaque, int version_id)
527e7be8d49SYi Min Zhao {
528e7be8d49SYi Min Zhao KVMS390FLICStateMigTmp *tmp = opaque;
529e7be8d49SYi Min Zhao KVMS390FLICState *flic = tmp->parent;
530e7be8d49SYi Min Zhao struct kvm_s390_ais_all ais = {
531e7be8d49SYi Min Zhao .simm = tmp->simm,
532e7be8d49SYi Min Zhao .nimm = tmp->nimm,
533e7be8d49SYi Min Zhao };
534e7be8d49SYi Min Zhao struct kvm_device_attr attr = {
535e7be8d49SYi Min Zhao .group = KVM_DEV_FLIC_AISM_ALL,
536e7be8d49SYi Min Zhao .addr = (uint64_t)&ais,
537e7be8d49SYi Min Zhao };
538e7be8d49SYi Min Zhao
539e7be8d49SYi Min Zhao /* This can happen when the user mis-configures its guests in an
540e7be8d49SYi Min Zhao * incompatible fashion or without a CPU model. For example using
541e7be8d49SYi Min Zhao * qemu with -cpu host (which is not migration safe) and do a
542e7be8d49SYi Min Zhao * migration from a host that has AIS to a host that has no AIS.
543e7be8d49SYi Min Zhao * In that case the target system will reject the migration here.
544e7be8d49SYi Min Zhao */
545e7be8d49SYi Min Zhao if (!ais_needed(flic)) {
546e7be8d49SYi Min Zhao return -ENOSYS;
547e7be8d49SYi Min Zhao }
548e7be8d49SYi Min Zhao
549e7be8d49SYi Min Zhao return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0;
550e7be8d49SYi Min Zhao }
551e7be8d49SYi Min Zhao
552e7be8d49SYi Min Zhao static const VMStateDescription kvm_s390_flic_ais_tmp = {
553e7be8d49SYi Min Zhao .name = "s390-flic-ais-tmp",
554e7be8d49SYi Min Zhao .pre_save = kvm_flic_ais_pre_save,
555e7be8d49SYi Min Zhao .post_load = kvm_flic_ais_post_load,
55645b1f81dSRichard Henderson .fields = (const VMStateField[]) {
557e7be8d49SYi Min Zhao VMSTATE_UINT8(simm, KVMS390FLICStateMigTmp),
558e7be8d49SYi Min Zhao VMSTATE_UINT8(nimm, KVMS390FLICStateMigTmp),
559e7be8d49SYi Min Zhao VMSTATE_END_OF_LIST()
560e7be8d49SYi Min Zhao }
561e7be8d49SYi Min Zhao };
562e7be8d49SYi Min Zhao
563e7be8d49SYi Min Zhao static const VMStateDescription kvm_s390_flic_vmstate_ais = {
564e7be8d49SYi Min Zhao .name = "s390-flic/ais",
565e7be8d49SYi Min Zhao .version_id = 1,
566e7be8d49SYi Min Zhao .minimum_version_id = 1,
567e7be8d49SYi Min Zhao .needed = ais_needed,
56845b1f81dSRichard Henderson .fields = (const VMStateField[]) {
569e7be8d49SYi Min Zhao VMSTATE_WITH_TMP(KVMS390FLICState, KVMS390FLICStateMigTmp,
570e7be8d49SYi Min Zhao kvm_s390_flic_ais_tmp),
571e7be8d49SYi Min Zhao VMSTATE_END_OF_LIST()
572e7be8d49SYi Min Zhao }
573e7be8d49SYi Min Zhao };
574e7be8d49SYi Min Zhao
575f2cab7f1SCornelia Huck static const VMStateDescription kvm_s390_flic_vmstate = {
576e7be8d49SYi Min Zhao /* should have been like kvm-s390-flic,
577e7be8d49SYi Min Zhao * can't change without breaking compat */
578f2cab7f1SCornelia Huck .name = "s390-flic",
579f2cab7f1SCornelia Huck .version_id = FLIC_SAVEVM_VERSION,
580f2cab7f1SCornelia Huck .minimum_version_id = FLIC_SAVEVM_VERSION,
58145b1f81dSRichard Henderson .fields = (const VMStateField[]) {
582f2cab7f1SCornelia Huck {
583f2cab7f1SCornelia Huck .name = "irqs",
584f2cab7f1SCornelia Huck .info = &(const VMStateInfo) {
585f2cab7f1SCornelia Huck .name = "irqs",
586f2cab7f1SCornelia Huck .get = kvm_flic_load,
587f2cab7f1SCornelia Huck .put = kvm_flic_save,
588f2cab7f1SCornelia Huck },
589f2cab7f1SCornelia Huck .flags = VMS_SINGLE,
590f2cab7f1SCornelia Huck },
591f2cab7f1SCornelia Huck VMSTATE_END_OF_LIST()
592e7be8d49SYi Min Zhao },
59345b1f81dSRichard Henderson .subsections = (const VMStateDescription * const []) {
594e7be8d49SYi Min Zhao &kvm_s390_flic_vmstate_ais,
595e7be8d49SYi Min Zhao NULL
596f2cab7f1SCornelia Huck }
597f2cab7f1SCornelia Huck };
598f2cab7f1SCornelia Huck
599db1015e9SEduardo Habkost struct KVMS390FLICStateClass {
6005cbab1bfSHalil Pasic S390FLICStateClass parent_class;
6015cbab1bfSHalil Pasic DeviceRealize parent_realize;
602db1015e9SEduardo Habkost };
603db1015e9SEduardo Habkost typedef struct KVMS390FLICStateClass KVMS390FLICStateClass;
6045cbab1bfSHalil Pasic
DECLARE_CLASS_CHECKERS(KVMS390FLICStateClass,KVM_S390_FLIC,TYPE_KVM_S390_FLIC)6058110fa1dSEduardo Habkost DECLARE_CLASS_CHECKERS(KVMS390FLICStateClass, KVM_S390_FLIC,
6068110fa1dSEduardo Habkost TYPE_KVM_S390_FLIC)
6075cbab1bfSHalil Pasic
6085cbab1bfSHalil Pasic
6097b35d0c4SCornelia Huck static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
6107b35d0c4SCornelia Huck {
6117b35d0c4SCornelia Huck KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
6127b35d0c4SCornelia Huck struct kvm_create_device cd = {0};
6139eccb862SHalil Pasic struct kvm_device_attr test_attr = {0};
6147b35d0c4SCornelia Huck int ret;
6158ca63ba8SMarkus Armbruster Error *err = NULL;
6167b35d0c4SCornelia Huck
6178ca63ba8SMarkus Armbruster KVM_S390_FLIC_GET_CLASS(dev)->parent_realize(dev, &err);
6188ca63ba8SMarkus Armbruster if (err) {
619d402c983SMarkus Armbruster error_propagate(errp, err);
620d402c983SMarkus Armbruster return;
6215cbab1bfSHalil Pasic }
6227b35d0c4SCornelia Huck flic_state->fd = -1;
6237b35d0c4SCornelia Huck
6247b35d0c4SCornelia Huck cd.type = KVM_DEV_TYPE_FLIC;
6257b35d0c4SCornelia Huck ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
6267b35d0c4SCornelia Huck if (ret < 0) {
627d402c983SMarkus Armbruster error_setg_errno(errp, errno, "Creating the KVM device failed");
6287b35d0c4SCornelia Huck trace_flic_create_device(errno);
629d402c983SMarkus Armbruster return;
6307b35d0c4SCornelia Huck }
6317b35d0c4SCornelia Huck flic_state->fd = cd.fd;
6327b35d0c4SCornelia Huck
6339eccb862SHalil Pasic /* Check clear_io_irq support */
6349eccb862SHalil Pasic test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
6359eccb862SHalil Pasic flic_state->clear_io_supported = !ioctl(flic_state->fd,
6369eccb862SHalil Pasic KVM_HAS_DEVICE_ATTR, test_attr);
6377b35d0c4SCornelia Huck }
6387b35d0c4SCornelia Huck
kvm_s390_flic_reset(DeviceState * dev)6397b35d0c4SCornelia Huck static void kvm_s390_flic_reset(DeviceState *dev)
6407b35d0c4SCornelia Huck {
6417b35d0c4SCornelia Huck KVMS390FLICState *flic = KVM_S390_FLIC(dev);
6426c1dd652SFei Li S390FLICState *fs = S390_FLIC_COMMON(dev);
6437b35d0c4SCornelia Huck struct kvm_device_attr attr = {
6447b35d0c4SCornelia Huck .group = KVM_DEV_FLIC_CLEAR_IRQS,
6457b35d0c4SCornelia Huck };
6467b35d0c4SCornelia Huck int rc = 0;
6476c1dd652SFei Li uint8_t isc;
6487b35d0c4SCornelia Huck
6497b35d0c4SCornelia Huck if (flic->fd == -1) {
6507b35d0c4SCornelia Huck return;
6517b35d0c4SCornelia Huck }
6527b35d0c4SCornelia Huck
6537b35d0c4SCornelia Huck flic_disable_wait_pfault(flic);
6547b35d0c4SCornelia Huck
6556c1dd652SFei Li if (fs->ais_supported) {
6566c1dd652SFei Li for (isc = 0; isc <= MAX_ISC; isc++) {
6576c1dd652SFei Li rc = kvm_s390_modify_ais_mode(fs, isc, SIC_IRQ_MODE_ALL);
6586c1dd652SFei Li if (rc) {
6596c1dd652SFei Li error_report("Failed to reset ais mode for isc %d: %s",
6606c1dd652SFei Li isc, strerror(-rc));
6616c1dd652SFei Li }
6626c1dd652SFei Li }
6636c1dd652SFei Li }
6646c1dd652SFei Li
6657b35d0c4SCornelia Huck rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
6667b35d0c4SCornelia Huck if (rc) {
6677b35d0c4SCornelia Huck trace_flic_reset_failed(errno);
6687b35d0c4SCornelia Huck }
6697b35d0c4SCornelia Huck
6707b35d0c4SCornelia Huck flic_enable_pfault(flic);
6717b35d0c4SCornelia Huck }
6727b35d0c4SCornelia Huck
kvm_s390_flic_class_init(ObjectClass * oc,void * data)6737b35d0c4SCornelia Huck static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
6747b35d0c4SCornelia Huck {
6757b35d0c4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(oc);
67603cf077aSCornelia Huck S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
6776269aad7SZhao Liu KVMS390FLICStateClass *kfsc = KVM_S390_FLIC_CLASS(oc);
6787b35d0c4SCornelia Huck
6796269aad7SZhao Liu device_class_set_parent_realize(dc, kvm_s390_flic_realize,
6806269aad7SZhao Liu &kfsc->parent_realize);
681f2cab7f1SCornelia Huck dc->vmsd = &kvm_s390_flic_vmstate;
682*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, kvm_s390_flic_reset);
68303cf077aSCornelia Huck fsc->register_io_adapter = kvm_s390_register_io_adapter;
684d426d9fbSCornelia Huck fsc->io_adapter_map = kvm_s390_io_adapter_map;
685d426d9fbSCornelia Huck fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
686d426d9fbSCornelia Huck fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
6879eccb862SHalil Pasic fsc->clear_io_irq = kvm_s390_clear_io_flic;
6886c1dd652SFei Li fsc->modify_ais_mode = kvm_s390_modify_ais_mode;
6891622ffd5SYi Min Zhao fsc->inject_airq = kvm_s390_inject_airq;
690e6505d53SDavid Hildenbrand fsc->inject_service = kvm_s390_inject_service;
691e6505d53SDavid Hildenbrand fsc->inject_io = kvm_s390_inject_io;
692e6505d53SDavid Hildenbrand fsc->inject_crw_mchk = kvm_s390_inject_crw_mchk;
6937b35d0c4SCornelia Huck }
6947b35d0c4SCornelia Huck
6957b35d0c4SCornelia Huck static const TypeInfo kvm_s390_flic_info = {
6967b35d0c4SCornelia Huck .name = TYPE_KVM_S390_FLIC,
6977b35d0c4SCornelia Huck .parent = TYPE_S390_FLIC_COMMON,
6987b35d0c4SCornelia Huck .instance_size = sizeof(KVMS390FLICState),
6995cbab1bfSHalil Pasic .class_size = sizeof(KVMS390FLICStateClass),
7007b35d0c4SCornelia Huck .class_init = kvm_s390_flic_class_init,
7017b35d0c4SCornelia Huck };
7027b35d0c4SCornelia Huck
kvm_s390_flic_register_types(void)7037b35d0c4SCornelia Huck static void kvm_s390_flic_register_types(void)
7047b35d0c4SCornelia Huck {
7057b35d0c4SCornelia Huck type_register_static(&kvm_s390_flic_info);
7067b35d0c4SCornelia Huck }
7077b35d0c4SCornelia Huck
7087b35d0c4SCornelia Huck type_init(kvm_s390_flic_register_types)
709