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" 153a553fc6SJens Freimann #include "hw/sysbus.h" 161622ffd5SYi Min Zhao #include "hw/s390x/ioinst.h" 173a553fc6SJens Freimann #include "hw/s390x/s390_flic.h" 181622ffd5SYi Min Zhao #include "hw/s390x/css.h" 193a553fc6SJens Freimann #include "trace.h" 201622ffd5SYi Min Zhao #include "cpu.h" 21e61cc6b5SHalil Pasic #include "hw/qdev.h" 22e61cc6b5SHalil Pasic #include "qapi/error.h" 23517ff12cSHalil Pasic #include "hw/s390x/s390-virtio-ccw.h" 243a553fc6SJens Freimann 257b35d0c4SCornelia Huck S390FLICState *s390_get_flic(void) 267b35d0c4SCornelia Huck { 27bc66d6cbSFei Li static S390FLICState *fs; 287b35d0c4SCornelia Huck 29bc66d6cbSFei Li if (!fs) { 30*b03d9970SDavid Hildenbrand fs = S390_FLIC_COMMON(object_resolve_path_type("", 31*b03d9970SDavid Hildenbrand TYPE_S390_FLIC_COMMON, 32bc66d6cbSFei Li NULL)); 33bc66d6cbSFei Li } 347b35d0c4SCornelia Huck return fs; 357b35d0c4SCornelia Huck } 363a553fc6SJens Freimann 373a553fc6SJens Freimann void s390_flic_init(void) 383a553fc6SJens Freimann { 393a553fc6SJens Freimann DeviceState *dev; 403a553fc6SJens Freimann 41e2ac12f0SDavid Hildenbrand if (kvm_enabled()) { 42e2ac12f0SDavid Hildenbrand dev = qdev_create(NULL, TYPE_KVM_S390_FLIC); 43e2ac12f0SDavid Hildenbrand object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC, 44e2ac12f0SDavid Hildenbrand OBJECT(dev), NULL); 45e2ac12f0SDavid Hildenbrand } else { 467b35d0c4SCornelia Huck dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC); 477b35d0c4SCornelia Huck object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC, 483a553fc6SJens Freimann OBJECT(dev), NULL); 497b35d0c4SCornelia Huck } 50ae4a2bd7SMarkus Armbruster qdev_init_nofail(dev); 513a553fc6SJens Freimann } 523a553fc6SJens Freimann 5303cf077aSCornelia Huck static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id, 5403cf077aSCornelia Huck uint8_t isc, bool swap, 551497c160SFei Li bool is_maskable, uint8_t flags) 5603cf077aSCornelia Huck { 5703cf077aSCornelia Huck /* nothing to do */ 5803cf077aSCornelia Huck return 0; 5903cf077aSCornelia Huck } 6003cf077aSCornelia Huck 61d426d9fbSCornelia Huck static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id, 62d426d9fbSCornelia Huck uint64_t map_addr, bool do_map) 63d426d9fbSCornelia Huck { 64d426d9fbSCornelia Huck /* nothing to do */ 65d426d9fbSCornelia Huck return 0; 66d426d9fbSCornelia Huck } 67d426d9fbSCornelia Huck 68d426d9fbSCornelia Huck static int qemu_s390_add_adapter_routes(S390FLICState *fs, 69d426d9fbSCornelia Huck AdapterRoutes *routes) 70d426d9fbSCornelia Huck { 71d426d9fbSCornelia Huck return -ENOSYS; 72d426d9fbSCornelia Huck } 73d426d9fbSCornelia Huck 74d426d9fbSCornelia Huck static void qemu_s390_release_adapter_routes(S390FLICState *fs, 75d426d9fbSCornelia Huck AdapterRoutes *routes) 76d426d9fbSCornelia Huck { 77d426d9fbSCornelia Huck } 78d426d9fbSCornelia Huck 799eccb862SHalil Pasic static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, 809eccb862SHalil Pasic uint16_t subchannel_nr) 819eccb862SHalil Pasic { 829eccb862SHalil Pasic /* Fixme TCG */ 839eccb862SHalil Pasic return -ENOSYS; 849eccb862SHalil Pasic } 859eccb862SHalil Pasic 866c1dd652SFei Li static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, 876c1dd652SFei Li uint16_t mode) 886c1dd652SFei Li { 896c1dd652SFei Li QEMUS390FLICState *flic = QEMU_S390_FLIC(fs); 906c1dd652SFei Li 916c1dd652SFei Li switch (mode) { 926c1dd652SFei Li case SIC_IRQ_MODE_ALL: 936c1dd652SFei Li flic->simm &= ~AIS_MODE_MASK(isc); 946c1dd652SFei Li flic->nimm &= ~AIS_MODE_MASK(isc); 956c1dd652SFei Li break; 966c1dd652SFei Li case SIC_IRQ_MODE_SINGLE: 976c1dd652SFei Li flic->simm |= AIS_MODE_MASK(isc); 986c1dd652SFei Li flic->nimm &= ~AIS_MODE_MASK(isc); 996c1dd652SFei Li break; 1006c1dd652SFei Li default: 1016c1dd652SFei Li return -EINVAL; 1026c1dd652SFei Li } 1036c1dd652SFei Li 1046c1dd652SFei Li return 0; 1056c1dd652SFei Li } 1066c1dd652SFei Li 1071622ffd5SYi Min Zhao static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type, 1081622ffd5SYi Min Zhao uint8_t isc, uint8_t flags) 1091622ffd5SYi Min Zhao { 1101622ffd5SYi Min Zhao QEMUS390FLICState *flic = QEMU_S390_FLIC(fs); 1111622ffd5SYi Min Zhao bool flag = flags & S390_ADAPTER_SUPPRESSIBLE; 1121622ffd5SYi Min Zhao uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; 1131622ffd5SYi Min Zhao 1141622ffd5SYi Min Zhao if (flag && (flic->nimm & AIS_MODE_MASK(isc))) { 1151622ffd5SYi Min Zhao trace_qemu_s390_airq_suppressed(type, isc); 1161622ffd5SYi Min Zhao return 0; 1171622ffd5SYi Min Zhao } 1181622ffd5SYi Min Zhao 1191622ffd5SYi Min Zhao s390_io_interrupt(0, 0, 0, io_int_word); 1201622ffd5SYi Min Zhao 1211622ffd5SYi Min Zhao if (flag && (flic->simm & AIS_MODE_MASK(isc))) { 1221622ffd5SYi Min Zhao flic->nimm |= AIS_MODE_MASK(isc); 1231622ffd5SYi Min Zhao trace_qemu_s390_suppress_airq(isc, "Single-Interruption Mode", 1241622ffd5SYi Min Zhao "NO-Interruptions Mode"); 1251622ffd5SYi Min Zhao } 1261622ffd5SYi Min Zhao 1271622ffd5SYi Min Zhao return 0; 1281622ffd5SYi Min Zhao } 1291622ffd5SYi Min Zhao 1306c1dd652SFei Li static void qemu_s390_flic_reset(DeviceState *dev) 1316c1dd652SFei Li { 1326c1dd652SFei Li QEMUS390FLICState *flic = QEMU_S390_FLIC(dev); 1336c1dd652SFei Li 1346c1dd652SFei Li flic->simm = 0; 1356c1dd652SFei Li flic->nimm = 0; 1366c1dd652SFei Li } 1376c1dd652SFei Li 138e7be8d49SYi Min Zhao bool ais_needed(void *opaque) 139e7be8d49SYi Min Zhao { 140e7be8d49SYi Min Zhao S390FLICState *s = opaque; 141e7be8d49SYi Min Zhao 142e7be8d49SYi Min Zhao return s->ais_supported; 143e7be8d49SYi Min Zhao } 144e7be8d49SYi Min Zhao 145e7be8d49SYi Min Zhao static const VMStateDescription qemu_s390_flic_vmstate = { 146e7be8d49SYi Min Zhao .name = "qemu-s390-flic", 147e7be8d49SYi Min Zhao .version_id = 1, 148e7be8d49SYi Min Zhao .minimum_version_id = 1, 149e7be8d49SYi Min Zhao .needed = ais_needed, 150e7be8d49SYi Min Zhao .fields = (VMStateField[]) { 151e7be8d49SYi Min Zhao VMSTATE_UINT8(simm, QEMUS390FLICState), 152e7be8d49SYi Min Zhao VMSTATE_UINT8(nimm, QEMUS390FLICState), 153e7be8d49SYi Min Zhao VMSTATE_END_OF_LIST() 154e7be8d49SYi Min Zhao } 155e7be8d49SYi Min Zhao }; 156e7be8d49SYi Min Zhao 15703cf077aSCornelia Huck static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) 15803cf077aSCornelia Huck { 1596c1dd652SFei Li DeviceClass *dc = DEVICE_CLASS(oc); 16003cf077aSCornelia Huck S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); 16103cf077aSCornelia Huck 1626c1dd652SFei Li dc->reset = qemu_s390_flic_reset; 163e7be8d49SYi Min Zhao dc->vmsd = &qemu_s390_flic_vmstate; 16403cf077aSCornelia Huck fsc->register_io_adapter = qemu_s390_register_io_adapter; 165d426d9fbSCornelia Huck fsc->io_adapter_map = qemu_s390_io_adapter_map; 166d426d9fbSCornelia Huck fsc->add_adapter_routes = qemu_s390_add_adapter_routes; 167d426d9fbSCornelia Huck fsc->release_adapter_routes = qemu_s390_release_adapter_routes; 1689eccb862SHalil Pasic fsc->clear_io_irq = qemu_s390_clear_io_flic; 1696c1dd652SFei Li fsc->modify_ais_mode = qemu_s390_modify_ais_mode; 1701622ffd5SYi Min Zhao fsc->inject_airq = qemu_s390_inject_airq; 17103cf077aSCornelia Huck } 17203cf077aSCornelia Huck 173e61cc6b5SHalil Pasic static Property s390_flic_common_properties[] = { 174e61cc6b5SHalil Pasic DEFINE_PROP_UINT32("adapter_routes_max_batch", S390FLICState, 175e61cc6b5SHalil Pasic adapter_routes_max_batch, ADAPTER_ROUTES_MAX_GSI), 176e61cc6b5SHalil Pasic DEFINE_PROP_END_OF_LIST(), 177e61cc6b5SHalil Pasic }; 178e61cc6b5SHalil Pasic 179e61cc6b5SHalil Pasic static void s390_flic_common_realize(DeviceState *dev, Error **errp) 180e61cc6b5SHalil Pasic { 1816c1dd652SFei Li S390FLICState *fs = S390_FLIC_COMMON(dev); 1826c1dd652SFei Li uint32_t max_batch = fs->adapter_routes_max_batch; 183e61cc6b5SHalil Pasic 184e61cc6b5SHalil Pasic if (max_batch > ADAPTER_ROUTES_MAX_GSI) { 1855cbab1bfSHalil Pasic error_setg(errp, "flic property adapter_routes_max_batch too big" 1865cbab1bfSHalil Pasic " (%d > %d)", max_batch, ADAPTER_ROUTES_MAX_GSI); 1873b00f702SYi Min Zhao return; 188e61cc6b5SHalil Pasic } 1896c1dd652SFei Li 1903b00f702SYi Min Zhao fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION); 191e61cc6b5SHalil Pasic } 192e61cc6b5SHalil Pasic 193e61cc6b5SHalil Pasic static void s390_flic_class_init(ObjectClass *oc, void *data) 194e61cc6b5SHalil Pasic { 195e61cc6b5SHalil Pasic DeviceClass *dc = DEVICE_CLASS(oc); 196e61cc6b5SHalil Pasic 197e61cc6b5SHalil Pasic dc->props = s390_flic_common_properties; 198e61cc6b5SHalil Pasic dc->realize = s390_flic_common_realize; 199e61cc6b5SHalil Pasic } 200e61cc6b5SHalil Pasic 2017b35d0c4SCornelia Huck static const TypeInfo qemu_s390_flic_info = { 2027b35d0c4SCornelia Huck .name = TYPE_QEMU_S390_FLIC, 2037b35d0c4SCornelia Huck .parent = TYPE_S390_FLIC_COMMON, 2047b35d0c4SCornelia Huck .instance_size = sizeof(QEMUS390FLICState), 20503cf077aSCornelia Huck .class_init = qemu_s390_flic_class_init, 2063a553fc6SJens Freimann }; 2073a553fc6SJens Freimann 208e61cc6b5SHalil Pasic 2097b35d0c4SCornelia Huck static const TypeInfo s390_flic_common_info = { 2107b35d0c4SCornelia Huck .name = TYPE_S390_FLIC_COMMON, 2113a553fc6SJens Freimann .parent = TYPE_SYS_BUS_DEVICE, 2127b35d0c4SCornelia Huck .instance_size = sizeof(S390FLICState), 213e61cc6b5SHalil Pasic .class_init = s390_flic_class_init, 2147b35d0c4SCornelia Huck .class_size = sizeof(S390FLICStateClass), 2153a553fc6SJens Freimann }; 2163a553fc6SJens Freimann 2177b35d0c4SCornelia Huck static void qemu_s390_flic_register_types(void) 2183a553fc6SJens Freimann { 2197b35d0c4SCornelia Huck type_register_static(&s390_flic_common_info); 2207b35d0c4SCornelia Huck type_register_static(&qemu_s390_flic_info); 2213a553fc6SJens Freimann } 2223a553fc6SJens Freimann 2237b35d0c4SCornelia Huck type_init(qemu_s390_flic_register_types) 224517ff12cSHalil Pasic 225457af626SHalil Pasic static bool adapter_info_so_needed(void *opaque) 226457af626SHalil Pasic { 227457af626SHalil Pasic return css_migration_enabled(); 228457af626SHalil Pasic } 229457af626SHalil Pasic 230457af626SHalil Pasic const VMStateDescription vmstate_adapter_info_so = { 231457af626SHalil Pasic .name = "s390_adapter_info/summary_offset", 232457af626SHalil Pasic .version_id = 1, 233457af626SHalil Pasic .minimum_version_id = 1, 234457af626SHalil Pasic .needed = adapter_info_so_needed, 235457af626SHalil Pasic .fields = (VMStateField[]) { 236457af626SHalil Pasic VMSTATE_UINT32(summary_offset, AdapterInfo), 237457af626SHalil Pasic VMSTATE_END_OF_LIST() 238457af626SHalil Pasic } 239457af626SHalil Pasic }; 240457af626SHalil Pasic 241517ff12cSHalil Pasic const VMStateDescription vmstate_adapter_info = { 242517ff12cSHalil Pasic .name = "s390_adapter_info", 243517ff12cSHalil Pasic .version_id = 1, 244517ff12cSHalil Pasic .minimum_version_id = 1, 245517ff12cSHalil Pasic .fields = (VMStateField[]) { 246517ff12cSHalil Pasic VMSTATE_UINT64(ind_offset, AdapterInfo), 247517ff12cSHalil Pasic /* 248517ff12cSHalil Pasic * We do not have to migrate neither the id nor the addresses. 249517ff12cSHalil Pasic * The id is set by css_register_io_adapter and the addresses 250517ff12cSHalil Pasic * are set based on the IndAddr objects after those get mapped. 251517ff12cSHalil Pasic */ 252517ff12cSHalil Pasic VMSTATE_END_OF_LIST() 253517ff12cSHalil Pasic }, 254457af626SHalil Pasic .subsections = (const VMStateDescription * []) { 255457af626SHalil Pasic &vmstate_adapter_info_so, 256457af626SHalil Pasic NULL 257457af626SHalil Pasic } 258517ff12cSHalil Pasic }; 259517ff12cSHalil Pasic 260517ff12cSHalil Pasic const VMStateDescription vmstate_adapter_routes = { 261517ff12cSHalil Pasic 262517ff12cSHalil Pasic .name = "s390_adapter_routes", 263517ff12cSHalil Pasic .version_id = 1, 264517ff12cSHalil Pasic .minimum_version_id = 1, 265517ff12cSHalil Pasic .fields = (VMStateField[]) { 266517ff12cSHalil Pasic VMSTATE_STRUCT(adapter, AdapterRoutes, 1, vmstate_adapter_info, 267517ff12cSHalil Pasic AdapterInfo), 268517ff12cSHalil Pasic VMSTATE_END_OF_LIST() 269517ff12cSHalil Pasic } 270517ff12cSHalil Pasic }; 271