13a553fc6SJens Freimann /* 27b35d0c4SCornelia Huck * QEMU S390x floating interrupt controller (flic) 33a553fc6SJens Freimann * 43a553fc6SJens Freimann * Copyright 2014 IBM Corp. 53a553fc6SJens Freimann * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com> 67b35d0c4SCornelia Huck * Cornelia Huck <cornelia.huck@de.ibm.com> 73a553fc6SJens Freimann * 83a553fc6SJens Freimann * This work is licensed under the terms of the GNU GPL, version 2 or (at 93a553fc6SJens Freimann * your option) any later version. See the COPYING file in the top-level 103a553fc6SJens Freimann * directory. 113a553fc6SJens Freimann */ 123a553fc6SJens Freimann 1390191d07SPeter Maydell #include "qemu/osdep.h" 143a553fc6SJens Freimann #include "qemu/error-report.h" 15*0b8fa32fSMarkus Armbruster #include "qemu/module.h" 163a553fc6SJens Freimann #include "hw/sysbus.h" 171622ffd5SYi Min Zhao #include "hw/s390x/ioinst.h" 183a553fc6SJens Freimann #include "hw/s390x/s390_flic.h" 191622ffd5SYi Min Zhao #include "hw/s390x/css.h" 203a553fc6SJens Freimann #include "trace.h" 211622ffd5SYi Min Zhao #include "cpu.h" 22e61cc6b5SHalil Pasic #include "hw/qdev.h" 23e61cc6b5SHalil Pasic #include "qapi/error.h" 24517ff12cSHalil Pasic #include "hw/s390x/s390-virtio-ccw.h" 253a553fc6SJens Freimann 266762808fSDavid Hildenbrand S390FLICStateClass *s390_get_flic_class(S390FLICState *fs) 276762808fSDavid Hildenbrand { 286762808fSDavid Hildenbrand static S390FLICStateClass *class; 296762808fSDavid Hildenbrand 306762808fSDavid Hildenbrand if (!class) { 316762808fSDavid Hildenbrand /* we only have one flic device, so this is fine to cache */ 326762808fSDavid Hildenbrand class = S390_FLIC_COMMON_GET_CLASS(fs); 336762808fSDavid Hildenbrand } 346762808fSDavid Hildenbrand return class; 356762808fSDavid Hildenbrand } 366762808fSDavid Hildenbrand 37f68ecdd4SDavid Hildenbrand QEMUS390FLICState *s390_get_qemu_flic(S390FLICState *fs) 38f68ecdd4SDavid Hildenbrand { 39f68ecdd4SDavid Hildenbrand static QEMUS390FLICState *flic; 40f68ecdd4SDavid Hildenbrand 41f68ecdd4SDavid Hildenbrand if (!flic) { 42f68ecdd4SDavid Hildenbrand /* we only have one flic device, so this is fine to cache */ 43f68ecdd4SDavid Hildenbrand flic = QEMU_S390_FLIC(fs); 44f68ecdd4SDavid Hildenbrand } 45f68ecdd4SDavid Hildenbrand return flic; 46f68ecdd4SDavid Hildenbrand } 47f68ecdd4SDavid Hildenbrand 487b35d0c4SCornelia Huck S390FLICState *s390_get_flic(void) 497b35d0c4SCornelia Huck { 50bc66d6cbSFei Li static S390FLICState *fs; 517b35d0c4SCornelia Huck 52bc66d6cbSFei Li if (!fs) { 53b03d9970SDavid Hildenbrand fs = S390_FLIC_COMMON(object_resolve_path_type("", 54b03d9970SDavid Hildenbrand TYPE_S390_FLIC_COMMON, 55bc66d6cbSFei Li NULL)); 56bc66d6cbSFei Li } 577b35d0c4SCornelia Huck return fs; 587b35d0c4SCornelia Huck } 593a553fc6SJens Freimann 603a553fc6SJens Freimann void s390_flic_init(void) 613a553fc6SJens Freimann { 623a553fc6SJens Freimann DeviceState *dev; 633a553fc6SJens Freimann 64e2ac12f0SDavid Hildenbrand if (kvm_enabled()) { 65e2ac12f0SDavid Hildenbrand dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); 66e2ac12f0SDavid Hildenbrand object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, 67e2ac12f0SDavid Hildenbrand OBJECT(dev), NULL); 68e2ac12f0SDavid Hildenbrand } else { 697b35d0c4SCornelia Huck dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC); 707b35d0c4SCornelia Huck object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC, 713a553fc6SJens Freimann OBJECT(dev), NULL); 727b35d0c4SCornelia Huck } 73ae4a2bd7SMarkus Armbruster qdev_init_nofail(dev); 743a553fc6SJens Freimann } 753a553fc6SJens Freimann 7603cf077aSCornelia Huck static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id, 7703cf077aSCornelia Huck uint8_t isc, bool swap, 781497c160SFei Li bool is_maskable, uint8_t flags) 7903cf077aSCornelia Huck { 8003cf077aSCornelia Huck /* nothing to do */ 8103cf077aSCornelia Huck return 0; 8203cf077aSCornelia Huck } 8303cf077aSCornelia Huck 84d426d9fbSCornelia Huck static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id, 85d426d9fbSCornelia Huck uint64_t map_addr, bool do_map) 86d426d9fbSCornelia Huck { 87d426d9fbSCornelia Huck /* nothing to do */ 88d426d9fbSCornelia Huck return 0; 89d426d9fbSCornelia Huck } 90d426d9fbSCornelia Huck 91d426d9fbSCornelia Huck static int qemu_s390_add_adapter_routes(S390FLICState *fs, 92d426d9fbSCornelia Huck AdapterRoutes *routes) 93d426d9fbSCornelia Huck { 94d426d9fbSCornelia Huck return -ENOSYS; 95d426d9fbSCornelia Huck } 96d426d9fbSCornelia Huck 97d426d9fbSCornelia Huck static void qemu_s390_release_adapter_routes(S390FLICState *fs, 98d426d9fbSCornelia Huck AdapterRoutes *routes) 99d426d9fbSCornelia Huck { 100d426d9fbSCornelia Huck } 101d426d9fbSCornelia Huck 1029eccb862SHalil Pasic static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, 1039eccb862SHalil Pasic uint16_t subchannel_nr) 1049eccb862SHalil Pasic { 105f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(fs); 1066e0d8175SDavid Hildenbrand QEMUS390FlicIO *cur, *next; 1076e0d8175SDavid Hildenbrand uint8_t isc; 1086e0d8175SDavid Hildenbrand 1096e0d8175SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 1106e0d8175SDavid Hildenbrand if (!(flic->pending & FLIC_PENDING_IO)) { 1116e0d8175SDavid Hildenbrand return 0; 1126e0d8175SDavid Hildenbrand } 1136e0d8175SDavid Hildenbrand 1146e0d8175SDavid Hildenbrand /* check all iscs */ 1156e0d8175SDavid Hildenbrand for (isc = 0; isc < 8; isc++) { 1166e0d8175SDavid Hildenbrand if (QLIST_EMPTY(&flic->io[isc])) { 1176e0d8175SDavid Hildenbrand continue; 1186e0d8175SDavid Hildenbrand } 1196e0d8175SDavid Hildenbrand 1206e0d8175SDavid Hildenbrand /* search and delete any matching one */ 1216e0d8175SDavid Hildenbrand QLIST_FOREACH_SAFE(cur, &flic->io[isc], next, next) { 1226e0d8175SDavid Hildenbrand if (cur->id == subchannel_id && cur->nr == subchannel_nr) { 1236e0d8175SDavid Hildenbrand QLIST_REMOVE(cur, next); 1246e0d8175SDavid Hildenbrand g_free(cur); 1256e0d8175SDavid Hildenbrand } 1266e0d8175SDavid Hildenbrand } 1276e0d8175SDavid Hildenbrand 1286e0d8175SDavid Hildenbrand /* update our indicator bit */ 1296e0d8175SDavid Hildenbrand if (QLIST_EMPTY(&flic->io[isc])) { 1306e0d8175SDavid Hildenbrand flic->pending &= ~ISC_TO_PENDING_IO(isc); 1316e0d8175SDavid Hildenbrand } 1326e0d8175SDavid Hildenbrand } 1336e0d8175SDavid Hildenbrand return 0; 1349eccb862SHalil Pasic } 1359eccb862SHalil Pasic 1366c1dd652SFei Li static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, 1376c1dd652SFei Li uint16_t mode) 1386c1dd652SFei Li { 139f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(fs); 1406c1dd652SFei Li 1416c1dd652SFei Li switch (mode) { 1426c1dd652SFei Li case SIC_IRQ_MODE_ALL: 1436c1dd652SFei Li flic->simm &= ~AIS_MODE_MASK(isc); 1446c1dd652SFei Li flic->nimm &= ~AIS_MODE_MASK(isc); 1456c1dd652SFei Li break; 1466c1dd652SFei Li case SIC_IRQ_MODE_SINGLE: 1476c1dd652SFei Li flic->simm |= AIS_MODE_MASK(isc); 1486c1dd652SFei Li flic->nimm &= ~AIS_MODE_MASK(isc); 1496c1dd652SFei Li break; 1506c1dd652SFei Li default: 1516c1dd652SFei Li return -EINVAL; 1526c1dd652SFei Li } 1536c1dd652SFei Li 1546c1dd652SFei Li return 0; 1556c1dd652SFei Li } 1566c1dd652SFei Li 1571622ffd5SYi Min Zhao static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type, 1581622ffd5SYi Min Zhao uint8_t isc, uint8_t flags) 1591622ffd5SYi Min Zhao { 160f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(fs); 1616762808fSDavid Hildenbrand S390FLICStateClass *fsc = s390_get_flic_class(fs); 1621622ffd5SYi Min Zhao bool flag = flags & S390_ADAPTER_SUPPRESSIBLE; 1631622ffd5SYi Min Zhao uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; 1641622ffd5SYi Min Zhao 1651622ffd5SYi Min Zhao if (flag && (flic->nimm & AIS_MODE_MASK(isc))) { 1661622ffd5SYi Min Zhao trace_qemu_s390_airq_suppressed(type, isc); 1671622ffd5SYi Min Zhao return 0; 1681622ffd5SYi Min Zhao } 1691622ffd5SYi Min Zhao 170d8d7942dSDavid Hildenbrand fsc->inject_io(fs, 0, 0, 0, io_int_word); 1711622ffd5SYi Min Zhao 1721622ffd5SYi Min Zhao if (flag && (flic->simm & AIS_MODE_MASK(isc))) { 1731622ffd5SYi Min Zhao flic->nimm |= AIS_MODE_MASK(isc); 1741622ffd5SYi Min Zhao trace_qemu_s390_suppress_airq(isc, "Single-Interruption Mode", 1751622ffd5SYi Min Zhao "NO-Interruptions Mode"); 1761622ffd5SYi Min Zhao } 1771622ffd5SYi Min Zhao 1781622ffd5SYi Min Zhao return 0; 1791622ffd5SYi Min Zhao } 1801622ffd5SYi Min Zhao 181b194e447SDavid Hildenbrand static void qemu_s390_flic_notify(uint32_t type) 182b194e447SDavid Hildenbrand { 183b194e447SDavid Hildenbrand CPUState *cs; 184b194e447SDavid Hildenbrand 185b194e447SDavid Hildenbrand /* 186b194e447SDavid Hildenbrand * We have to make all CPUs see CPU_INTERRUPT_HARD, so they might 187631b5966SDavid Hildenbrand * consider it. We will kick all running CPUs and only relevant 188631b5966SDavid Hildenbrand * sleeping ones. 189b194e447SDavid Hildenbrand */ 190b194e447SDavid Hildenbrand CPU_FOREACH(cs) { 191631b5966SDavid Hildenbrand S390CPU *cpu = S390_CPU(cs); 192631b5966SDavid Hildenbrand 193631b5966SDavid Hildenbrand cs->interrupt_request |= CPU_INTERRUPT_HARD; 194631b5966SDavid Hildenbrand 195631b5966SDavid Hildenbrand /* ignore CPUs that are not sleeping */ 1969d0306dfSViktor Mihajlovski if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING && 1979d0306dfSViktor Mihajlovski s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD) { 198631b5966SDavid Hildenbrand continue; 199631b5966SDavid Hildenbrand } 200631b5966SDavid Hildenbrand 201631b5966SDavid Hildenbrand /* we always kick running CPUs for now, this is tricky */ 202631b5966SDavid Hildenbrand if (cs->halted) { 203631b5966SDavid Hildenbrand /* don't check for subclasses, CPUs double check when waking up */ 204631b5966SDavid Hildenbrand if (type & FLIC_PENDING_SERVICE) { 205631b5966SDavid Hildenbrand if (!(cpu->env.psw.mask & PSW_MASK_EXT)) { 206631b5966SDavid Hildenbrand continue; 207631b5966SDavid Hildenbrand } 208631b5966SDavid Hildenbrand } else if (type & FLIC_PENDING_IO) { 209631b5966SDavid Hildenbrand if (!(cpu->env.psw.mask & PSW_MASK_IO)) { 210631b5966SDavid Hildenbrand continue; 211631b5966SDavid Hildenbrand } 212631b5966SDavid Hildenbrand } else if (type & FLIC_PENDING_MCHK_CR) { 213631b5966SDavid Hildenbrand if (!(cpu->env.psw.mask & PSW_MASK_MCHECK)) { 214631b5966SDavid Hildenbrand continue; 215631b5966SDavid Hildenbrand } 216631b5966SDavid Hildenbrand } 217631b5966SDavid Hildenbrand } 218b194e447SDavid Hildenbrand cpu_interrupt(cs, CPU_INTERRUPT_HARD); 219b194e447SDavid Hildenbrand } 220b194e447SDavid Hildenbrand } 221b194e447SDavid Hildenbrand 222b194e447SDavid Hildenbrand uint32_t qemu_s390_flic_dequeue_service(QEMUS390FLICState *flic) 223b194e447SDavid Hildenbrand { 224b194e447SDavid Hildenbrand uint32_t tmp; 225b194e447SDavid Hildenbrand 226b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 227b194e447SDavid Hildenbrand g_assert(flic->pending & FLIC_PENDING_SERVICE); 228b194e447SDavid Hildenbrand tmp = flic->service_param; 229b194e447SDavid Hildenbrand flic->service_param = 0; 230b194e447SDavid Hildenbrand flic->pending &= ~FLIC_PENDING_SERVICE; 231b194e447SDavid Hildenbrand 232b194e447SDavid Hildenbrand return tmp; 233b194e447SDavid Hildenbrand } 234b194e447SDavid Hildenbrand 235b194e447SDavid Hildenbrand /* caller has to free the returned object */ 236b194e447SDavid Hildenbrand QEMUS390FlicIO *qemu_s390_flic_dequeue_io(QEMUS390FLICState *flic, uint64_t cr6) 237b194e447SDavid Hildenbrand { 238b194e447SDavid Hildenbrand QEMUS390FlicIO *io; 239b194e447SDavid Hildenbrand uint8_t isc; 240b194e447SDavid Hildenbrand 241b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 242b194e447SDavid Hildenbrand if (!(flic->pending & CR6_TO_PENDING_IO(cr6))) { 243b194e447SDavid Hildenbrand return NULL; 244b194e447SDavid Hildenbrand } 245b194e447SDavid Hildenbrand 246b194e447SDavid Hildenbrand for (isc = 0; isc < 8; isc++) { 247b194e447SDavid Hildenbrand if (QLIST_EMPTY(&flic->io[isc]) || !(cr6 & ISC_TO_ISC_BITS(isc))) { 248b194e447SDavid Hildenbrand continue; 249b194e447SDavid Hildenbrand } 250b194e447SDavid Hildenbrand io = QLIST_FIRST(&flic->io[isc]); 251b194e447SDavid Hildenbrand QLIST_REMOVE(io, next); 252b194e447SDavid Hildenbrand 253b194e447SDavid Hildenbrand /* update our indicator bit */ 254b194e447SDavid Hildenbrand if (QLIST_EMPTY(&flic->io[isc])) { 255b194e447SDavid Hildenbrand flic->pending &= ~ISC_TO_PENDING_IO(isc); 256b194e447SDavid Hildenbrand } 257b194e447SDavid Hildenbrand return io; 258b194e447SDavid Hildenbrand } 259b194e447SDavid Hildenbrand 260b194e447SDavid Hildenbrand return NULL; 261b194e447SDavid Hildenbrand } 262b194e447SDavid Hildenbrand 263b194e447SDavid Hildenbrand void qemu_s390_flic_dequeue_crw_mchk(QEMUS390FLICState *flic) 264b194e447SDavid Hildenbrand { 265b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 266b194e447SDavid Hildenbrand g_assert(flic->pending & FLIC_PENDING_MCHK_CR); 267b194e447SDavid Hildenbrand flic->pending &= ~FLIC_PENDING_MCHK_CR; 268b194e447SDavid Hildenbrand } 269b194e447SDavid Hildenbrand 270e6505d53SDavid Hildenbrand static void qemu_s390_inject_service(S390FLICState *fs, uint32_t parm) 271e6505d53SDavid Hildenbrand { 272f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(fs); 273e6505d53SDavid Hildenbrand 274b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 275b194e447SDavid Hildenbrand /* multiplexing is good enough for sclp - kvm does it internally as well */ 276b194e447SDavid Hildenbrand flic->service_param |= parm; 277b194e447SDavid Hildenbrand flic->pending |= FLIC_PENDING_SERVICE; 278e6505d53SDavid Hildenbrand 279b194e447SDavid Hildenbrand qemu_s390_flic_notify(FLIC_PENDING_SERVICE); 280e6505d53SDavid Hildenbrand } 281e6505d53SDavid Hildenbrand 282e6505d53SDavid Hildenbrand static void qemu_s390_inject_io(S390FLICState *fs, uint16_t subchannel_id, 283e6505d53SDavid Hildenbrand uint16_t subchannel_nr, uint32_t io_int_parm, 284e6505d53SDavid Hildenbrand uint32_t io_int_word) 285e6505d53SDavid Hildenbrand { 286b194e447SDavid Hildenbrand const uint8_t isc = IO_INT_WORD_ISC(io_int_word); 287f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(fs); 288b194e447SDavid Hildenbrand QEMUS390FlicIO *io; 289e6505d53SDavid Hildenbrand 290b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 291b194e447SDavid Hildenbrand io = g_new0(QEMUS390FlicIO, 1); 292b194e447SDavid Hildenbrand io->id = subchannel_id; 293b194e447SDavid Hildenbrand io->nr = subchannel_nr; 294b194e447SDavid Hildenbrand io->parm = io_int_parm; 295b194e447SDavid Hildenbrand io->word = io_int_word; 296b194e447SDavid Hildenbrand 297b194e447SDavid Hildenbrand QLIST_INSERT_HEAD(&flic->io[isc], io, next); 298b194e447SDavid Hildenbrand flic->pending |= ISC_TO_PENDING_IO(isc); 299b194e447SDavid Hildenbrand 300b194e447SDavid Hildenbrand qemu_s390_flic_notify(ISC_TO_PENDING_IO(isc)); 301e6505d53SDavid Hildenbrand } 302e6505d53SDavid Hildenbrand 303e6505d53SDavid Hildenbrand static void qemu_s390_inject_crw_mchk(S390FLICState *fs) 304e6505d53SDavid Hildenbrand { 305f68ecdd4SDavid Hildenbrand QEMUS390FLICState *flic = s390_get_qemu_flic(fs); 306e6505d53SDavid Hildenbrand 307b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 308b194e447SDavid Hildenbrand flic->pending |= FLIC_PENDING_MCHK_CR; 309b194e447SDavid Hildenbrand 310b194e447SDavid Hildenbrand qemu_s390_flic_notify(FLIC_PENDING_MCHK_CR); 311b194e447SDavid Hildenbrand } 312b194e447SDavid Hildenbrand 313b194e447SDavid Hildenbrand bool qemu_s390_flic_has_service(QEMUS390FLICState *flic) 314b194e447SDavid Hildenbrand { 315b194e447SDavid Hildenbrand /* called without lock via cc->has_work, will be validated under lock */ 316b194e447SDavid Hildenbrand return !!(flic->pending & FLIC_PENDING_SERVICE); 317b194e447SDavid Hildenbrand } 318b194e447SDavid Hildenbrand 319b194e447SDavid Hildenbrand bool qemu_s390_flic_has_io(QEMUS390FLICState *flic, uint64_t cr6) 320b194e447SDavid Hildenbrand { 321b194e447SDavid Hildenbrand /* called without lock via cc->has_work, will be validated under lock */ 322b194e447SDavid Hildenbrand return !!(flic->pending & CR6_TO_PENDING_IO(cr6)); 323b194e447SDavid Hildenbrand } 324b194e447SDavid Hildenbrand 325b194e447SDavid Hildenbrand bool qemu_s390_flic_has_crw_mchk(QEMUS390FLICState *flic) 326b194e447SDavid Hildenbrand { 327b194e447SDavid Hildenbrand /* called without lock via cc->has_work, will be validated under lock */ 328b194e447SDavid Hildenbrand return !!(flic->pending & FLIC_PENDING_MCHK_CR); 329b194e447SDavid Hildenbrand } 330b194e447SDavid Hildenbrand 331b194e447SDavid Hildenbrand bool qemu_s390_flic_has_any(QEMUS390FLICState *flic) 332b194e447SDavid Hildenbrand { 333b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 334b194e447SDavid Hildenbrand return !!flic->pending; 335e6505d53SDavid Hildenbrand } 336e6505d53SDavid Hildenbrand 3376c1dd652SFei Li static void qemu_s390_flic_reset(DeviceState *dev) 3386c1dd652SFei Li { 3396c1dd652SFei Li QEMUS390FLICState *flic = QEMU_S390_FLIC(dev); 340b194e447SDavid Hildenbrand QEMUS390FlicIO *cur, *next; 341b194e447SDavid Hildenbrand int isc; 3426c1dd652SFei Li 343b194e447SDavid Hildenbrand g_assert(qemu_mutex_iothread_locked()); 3446c1dd652SFei Li flic->simm = 0; 3456c1dd652SFei Li flic->nimm = 0; 346b194e447SDavid Hildenbrand flic->pending = 0; 347b194e447SDavid Hildenbrand 348b194e447SDavid Hildenbrand /* remove all pending io interrupts */ 349b194e447SDavid Hildenbrand for (isc = 0; isc < 8; isc++) { 350b194e447SDavid Hildenbrand QLIST_FOREACH_SAFE(cur, &flic->io[isc], next, next) { 351b194e447SDavid Hildenbrand QLIST_REMOVE(cur, next); 352b194e447SDavid Hildenbrand g_free(cur); 353b194e447SDavid Hildenbrand } 354b194e447SDavid Hildenbrand } 3556c1dd652SFei Li } 3566c1dd652SFei Li 357e7be8d49SYi Min Zhao bool ais_needed(void *opaque) 358e7be8d49SYi Min Zhao { 359e7be8d49SYi Min Zhao S390FLICState *s = opaque; 360e7be8d49SYi Min Zhao 361e7be8d49SYi Min Zhao return s->ais_supported; 362e7be8d49SYi Min Zhao } 363e7be8d49SYi Min Zhao 364e7be8d49SYi Min Zhao static const VMStateDescription qemu_s390_flic_vmstate = { 365e7be8d49SYi Min Zhao .name = "qemu-s390-flic", 366e7be8d49SYi Min Zhao .version_id = 1, 367e7be8d49SYi Min Zhao .minimum_version_id = 1, 368e7be8d49SYi Min Zhao .needed = ais_needed, 369e7be8d49SYi Min Zhao .fields = (VMStateField[]) { 370e7be8d49SYi Min Zhao VMSTATE_UINT8(simm, QEMUS390FLICState), 371e7be8d49SYi Min Zhao VMSTATE_UINT8(nimm, QEMUS390FLICState), 372e7be8d49SYi Min Zhao VMSTATE_END_OF_LIST() 373e7be8d49SYi Min Zhao } 374e7be8d49SYi Min Zhao }; 375e7be8d49SYi Min Zhao 376b194e447SDavid Hildenbrand static void qemu_s390_flic_instance_init(Object *obj) 377b194e447SDavid Hildenbrand { 378b194e447SDavid Hildenbrand QEMUS390FLICState *flic = QEMU_S390_FLIC(obj); 379b194e447SDavid Hildenbrand int isc; 380b194e447SDavid Hildenbrand 381b194e447SDavid Hildenbrand for (isc = 0; isc < 8; isc++) { 382b194e447SDavid Hildenbrand QLIST_INIT(&flic->io[isc]); 383b194e447SDavid Hildenbrand } 384b194e447SDavid Hildenbrand } 385b194e447SDavid Hildenbrand 38603cf077aSCornelia Huck static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) 38703cf077aSCornelia Huck { 3886c1dd652SFei Li DeviceClass *dc = DEVICE_CLASS(oc); 38903cf077aSCornelia Huck S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); 39003cf077aSCornelia Huck 3916c1dd652SFei Li dc->reset = qemu_s390_flic_reset; 392e7be8d49SYi Min Zhao dc->vmsd = &qemu_s390_flic_vmstate; 39303cf077aSCornelia Huck fsc->register_io_adapter = qemu_s390_register_io_adapter; 394d426d9fbSCornelia Huck fsc->io_adapter_map = qemu_s390_io_adapter_map; 395d426d9fbSCornelia Huck fsc->add_adapter_routes = qemu_s390_add_adapter_routes; 396d426d9fbSCornelia Huck fsc->release_adapter_routes = qemu_s390_release_adapter_routes; 3979eccb862SHalil Pasic fsc->clear_io_irq = qemu_s390_clear_io_flic; 3986c1dd652SFei Li fsc->modify_ais_mode = qemu_s390_modify_ais_mode; 3991622ffd5SYi Min Zhao fsc->inject_airq = qemu_s390_inject_airq; 400e6505d53SDavid Hildenbrand fsc->inject_service = qemu_s390_inject_service; 401e6505d53SDavid Hildenbrand fsc->inject_io = qemu_s390_inject_io; 402e6505d53SDavid Hildenbrand fsc->inject_crw_mchk = qemu_s390_inject_crw_mchk; 40303cf077aSCornelia Huck } 40403cf077aSCornelia Huck 405e61cc6b5SHalil Pasic static Property s390_flic_common_properties[] = { 406e61cc6b5SHalil Pasic DEFINE_PROP_UINT32("adapter_routes_max_batch", S390FLICState, 407e61cc6b5SHalil Pasic adapter_routes_max_batch, ADAPTER_ROUTES_MAX_GSI), 408e61cc6b5SHalil Pasic DEFINE_PROP_END_OF_LIST(), 409e61cc6b5SHalil Pasic }; 410e61cc6b5SHalil Pasic 411e61cc6b5SHalil Pasic static void s390_flic_common_realize(DeviceState *dev, Error **errp) 412e61cc6b5SHalil Pasic { 4136c1dd652SFei Li S390FLICState *fs = S390_FLIC_COMMON(dev); 4146c1dd652SFei Li uint32_t max_batch = fs->adapter_routes_max_batch; 415e61cc6b5SHalil Pasic 416e61cc6b5SHalil Pasic if (max_batch > ADAPTER_ROUTES_MAX_GSI) { 4175cbab1bfSHalil Pasic error_setg(errp, "flic property adapter_routes_max_batch too big" 4185cbab1bfSHalil Pasic " (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI); 4193b00f702SYi Min Zhao return; 420e61cc6b5SHalil Pasic } 4216c1dd652SFei Li 4223b00f702SYi Min Zhao fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION); 423e61cc6b5SHalil Pasic } 424e61cc6b5SHalil Pasic 425e61cc6b5SHalil Pasic static void s390_flic_class_init(ObjectClass *oc, void *data) 426e61cc6b5SHalil Pasic { 427e61cc6b5SHalil Pasic DeviceClass *dc = DEVICE_CLASS(oc); 428e61cc6b5SHalil Pasic 429e61cc6b5SHalil Pasic dc->props = s390_flic_common_properties; 430e61cc6b5SHalil Pasic dc->realize = s390_flic_common_realize; 431e61cc6b5SHalil Pasic } 432e61cc6b5SHalil Pasic 4337b35d0c4SCornelia Huck static const TypeInfo qemu_s390_flic_info = { 4347b35d0c4SCornelia Huck .name = TYPE_QEMU_S390_FLIC, 4357b35d0c4SCornelia Huck .parent = TYPE_S390_FLIC_COMMON, 4367b35d0c4SCornelia Huck .instance_size = sizeof(QEMUS390FLICState), 437b194e447SDavid Hildenbrand .instance_init = qemu_s390_flic_instance_init, 43803cf077aSCornelia Huck .class_init = qemu_s390_flic_class_init, 4393a553fc6SJens Freimann }; 4403a553fc6SJens Freimann 441e61cc6b5SHalil Pasic 4427b35d0c4SCornelia Huck static const TypeInfo s390_flic_common_info = { 4437b35d0c4SCornelia Huck .name = TYPE_S390_FLIC_COMMON, 4443a553fc6SJens Freimann .parent = TYPE_SYS_BUS_DEVICE, 4457b35d0c4SCornelia Huck .instance_size = sizeof(S390FLICState), 446e61cc6b5SHalil Pasic .class_init = s390_flic_class_init, 4477b35d0c4SCornelia Huck .class_size = sizeof(S390FLICStateClass), 4483a553fc6SJens Freimann }; 4493a553fc6SJens Freimann 4507b35d0c4SCornelia Huck static void qemu_s390_flic_register_types(void) 4513a553fc6SJens Freimann { 4527b35d0c4SCornelia Huck type_register_static(&s390_flic_common_info); 4537b35d0c4SCornelia Huck type_register_static(&qemu_s390_flic_info); 4543a553fc6SJens Freimann } 4553a553fc6SJens Freimann 4567b35d0c4SCornelia Huck type_init(qemu_s390_flic_register_types) 457517ff12cSHalil Pasic 458457af626SHalil Pasic static bool adapter_info_so_needed(void *opaque) 459457af626SHalil Pasic { 460457af626SHalil Pasic return css_migration_enabled(); 461457af626SHalil Pasic } 462457af626SHalil Pasic 463457af626SHalil Pasic const VMStateDescription vmstate_adapter_info_so = { 464457af626SHalil Pasic .name = "s390_adapter_info/summary_offset", 465457af626SHalil Pasic .version_id = 1, 466457af626SHalil Pasic .minimum_version_id = 1, 467457af626SHalil Pasic .needed = adapter_info_so_needed, 468457af626SHalil Pasic .fields = (VMStateField[]) { 469457af626SHalil Pasic VMSTATE_UINT32(summary_offset, AdapterInfo), 470457af626SHalil Pasic VMSTATE_END_OF_LIST() 471457af626SHalil Pasic } 472457af626SHalil Pasic }; 473457af626SHalil Pasic 474517ff12cSHalil Pasic const VMStateDescription vmstate_adapter_info = { 475517ff12cSHalil Pasic .name = "s390_adapter_info", 476517ff12cSHalil Pasic .version_id = 1, 477517ff12cSHalil Pasic .minimum_version_id = 1, 478517ff12cSHalil Pasic .fields = (VMStateField[]) { 479517ff12cSHalil Pasic VMSTATE_UINT64(ind_offset, AdapterInfo), 480517ff12cSHalil Pasic /* 481517ff12cSHalil Pasic * We do not have to migrate neither the id nor the addresses. 482517ff12cSHalil Pasic * The id is set by css_register_io_adapter and the addresses 483517ff12cSHalil Pasic * are set based on the IndAddr objects after those get mapped. 484517ff12cSHalil Pasic */ 485517ff12cSHalil Pasic VMSTATE_END_OF_LIST() 486517ff12cSHalil Pasic }, 487457af626SHalil Pasic .subsections = (const VMStateDescription * []) { 488457af626SHalil Pasic &vmstate_adapter_info_so, 489457af626SHalil Pasic NULL 490457af626SHalil Pasic } 491517ff12cSHalil Pasic }; 492517ff12cSHalil Pasic 493517ff12cSHalil Pasic const VMStateDescription vmstate_adapter_routes = { 494517ff12cSHalil Pasic 495517ff12cSHalil Pasic .name = "s390_adapter_routes", 496517ff12cSHalil Pasic .version_id = 1, 497517ff12cSHalil Pasic .minimum_version_id = 1, 498517ff12cSHalil Pasic .fields = (VMStateField[]) { 499517ff12cSHalil Pasic VMSTATE_STRUCT(adapter, AdapterRoutes, 1, vmstate_adapter_info, 500517ff12cSHalil Pasic AdapterInfo), 501517ff12cSHalil Pasic VMSTATE_END_OF_LIST() 502517ff12cSHalil Pasic } 503517ff12cSHalil Pasic }; 504