1a5cf2bb4SCornelia Huck /* 2a5cf2bb4SCornelia Huck * virtio ccw target implementation 3a5cf2bb4SCornelia Huck * 4de6a9218SPierre Morel * Copyright 2012,2015 IBM Corp. 5a5cf2bb4SCornelia Huck * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 6de6a9218SPierre Morel * Pierre Morel <pmorel@linux.vnet.ibm.com> 7a5cf2bb4SCornelia Huck * 8a5cf2bb4SCornelia Huck * This work is licensed under the terms of the GNU GPL, version 2 or (at 9a5cf2bb4SCornelia Huck * your option) any later version. See the COPYING file in the top-level 10a5cf2bb4SCornelia Huck * directory. 11a5cf2bb4SCornelia Huck */ 12a5cf2bb4SCornelia Huck 139615495aSPeter Maydell #include "qemu/osdep.h" 14da34e65cSMarkus Armbruster #include "qapi/error.h" 15a5cf2bb4SCornelia Huck #include "hw/hw.h" 164be74634SMarkus Armbruster #include "sysemu/block-backend.h" 17a5cf2bb4SCornelia Huck #include "sysemu/blockdev.h" 18a5cf2bb4SCornelia Huck #include "sysemu/sysemu.h" 19bd3f16acSPaolo Bonzini #include "sysemu/kvm.h" 20a5cf2bb4SCornelia Huck #include "net/net.h" 210d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h" 220d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h" 230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h" 24a5cf2bb4SCornelia Huck #include "hw/sysbus.h" 25a5cf2bb4SCornelia Huck #include "qemu/bitops.h" 26d49b6836SMarkus Armbruster #include "qemu/error-report.h" 27c42767f2SThomas Huth #include "hw/virtio/virtio-access.h" 280d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h" 29d426d9fbSCornelia Huck #include "hw/s390x/adapter.h" 30d426d9fbSCornelia Huck #include "hw/s390x/s390_flic.h" 31a5cf2bb4SCornelia Huck 32bd3f16acSPaolo Bonzini #include "hw/s390x/ioinst.h" 33bd3f16acSPaolo Bonzini #include "hw/s390x/css.h" 34a5cf2bb4SCornelia Huck #include "virtio-ccw.h" 35a5cf2bb4SCornelia Huck #include "trace.h" 36dd70bd0dSJing Liu #include "hw/s390x/css-bridge.h" 37a5cf2bb4SCornelia Huck 381bf4d7aaSAndreas Färber static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, 391bf4d7aaSAndreas Färber VirtioCcwDevice *dev); 40d51fcfacSKONRAD Frederic 41a5cf2bb4SCornelia Huck VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) 42a5cf2bb4SCornelia Huck { 43a5cf2bb4SCornelia Huck VirtIODevice *vdev = NULL; 44f24a6840SPaolo Bonzini VirtioCcwDevice *dev = sch->driver_data; 45a5cf2bb4SCornelia Huck 46f24a6840SPaolo Bonzini if (dev) { 47f24a6840SPaolo Bonzini vdev = virtio_bus_get_device(&dev->bus); 48a5cf2bb4SCornelia Huck } 49a5cf2bb4SCornelia Huck return vdev; 50a5cf2bb4SCornelia Huck } 51a5cf2bb4SCornelia Huck 52b4436a0bSCornelia Huck static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) 53b4436a0bSCornelia Huck { 547c55f68aSCornelia Huck virtio_bus_start_ioeventfd(&dev->bus); 55b4436a0bSCornelia Huck } 56b4436a0bSCornelia Huck 57b4436a0bSCornelia Huck static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev) 58b4436a0bSCornelia Huck { 597c55f68aSCornelia Huck virtio_bus_stop_ioeventfd(&dev->bus); 607c55f68aSCornelia Huck } 61b4436a0bSCornelia Huck 628e93cef1SPaolo Bonzini static bool virtio_ccw_ioeventfd_enabled(DeviceState *d) 637c55f68aSCornelia Huck { 647c55f68aSCornelia Huck VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 657c55f68aSCornelia Huck 668e93cef1SPaolo Bonzini return (dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) != 0; 677c55f68aSCornelia Huck } 687c55f68aSCornelia Huck 697c55f68aSCornelia Huck static int virtio_ccw_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, 707c55f68aSCornelia Huck int n, bool assign) 717c55f68aSCornelia Huck { 727c55f68aSCornelia Huck VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 73b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(dev); 74b804e8a6SJing Liu SubchDev *sch = ccw_dev->sch; 757c55f68aSCornelia Huck uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid; 767c55f68aSCornelia Huck 777c55f68aSCornelia Huck return s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); 78b4436a0bSCornelia Huck } 79b4436a0bSCornelia Huck 80a5cf2bb4SCornelia Huck /* Communication blocks used by several channel commands. */ 810db87e0dSCornelia Huck typedef struct VqInfoBlockLegacy { 82a5cf2bb4SCornelia Huck uint64_t queue; 83a5cf2bb4SCornelia Huck uint32_t align; 84a5cf2bb4SCornelia Huck uint16_t index; 85a5cf2bb4SCornelia Huck uint16_t num; 860db87e0dSCornelia Huck } QEMU_PACKED VqInfoBlockLegacy; 870db87e0dSCornelia Huck 880db87e0dSCornelia Huck typedef struct VqInfoBlock { 890db87e0dSCornelia Huck uint64_t desc; 900db87e0dSCornelia Huck uint32_t res0; 910db87e0dSCornelia Huck uint16_t index; 920db87e0dSCornelia Huck uint16_t num; 930db87e0dSCornelia Huck uint64_t avail; 940db87e0dSCornelia Huck uint64_t used; 95a5cf2bb4SCornelia Huck } QEMU_PACKED VqInfoBlock; 96a5cf2bb4SCornelia Huck 97a5cf2bb4SCornelia Huck typedef struct VqConfigBlock { 98a5cf2bb4SCornelia Huck uint16_t index; 99a5cf2bb4SCornelia Huck uint16_t num_max; 100a5cf2bb4SCornelia Huck } QEMU_PACKED VqConfigBlock; 101a5cf2bb4SCornelia Huck 102a5cf2bb4SCornelia Huck typedef struct VirtioFeatDesc { 103a5cf2bb4SCornelia Huck uint32_t features; 104a5cf2bb4SCornelia Huck uint8_t index; 105a5cf2bb4SCornelia Huck } QEMU_PACKED VirtioFeatDesc; 106a5cf2bb4SCornelia Huck 1077e749462SCornelia Huck typedef struct VirtioThinintInfo { 1087e749462SCornelia Huck hwaddr summary_indicator; 1097e749462SCornelia Huck hwaddr device_indicator; 1107e749462SCornelia Huck uint64_t ind_bit; 1117e749462SCornelia Huck uint8_t isc; 1127e749462SCornelia Huck } QEMU_PACKED VirtioThinintInfo; 1137e749462SCornelia Huck 114c42767f2SThomas Huth typedef struct VirtioRevInfo { 115c42767f2SThomas Huth uint16_t revision; 116c42767f2SThomas Huth uint16_t length; 117c42767f2SThomas Huth uint8_t data[0]; 118c42767f2SThomas Huth } QEMU_PACKED VirtioRevInfo; 119c42767f2SThomas Huth 120a5cf2bb4SCornelia Huck /* Specify where the virtqueues for the subchannel are in guest memory. */ 1210db87e0dSCornelia Huck static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info, 1220db87e0dSCornelia Huck VqInfoBlockLegacy *linfo) 123a5cf2bb4SCornelia Huck { 124f24a6840SPaolo Bonzini VirtIODevice *vdev = virtio_ccw_get_vdev(sch); 1250db87e0dSCornelia Huck uint16_t index = info ? info->index : linfo->index; 1260db87e0dSCornelia Huck uint16_t num = info ? info->num : linfo->num; 1270db87e0dSCornelia Huck uint64_t desc = info ? info->desc : linfo->queue; 128a5cf2bb4SCornelia Huck 1298dfbaa6aSJason Wang if (index >= VIRTIO_CCW_QUEUE_MAX) { 130a5cf2bb4SCornelia Huck return -EINVAL; 131a5cf2bb4SCornelia Huck } 132a5cf2bb4SCornelia Huck 133a5cf2bb4SCornelia Huck /* Current code in virtio.c relies on 4K alignment. */ 1340db87e0dSCornelia Huck if (linfo && desc && (linfo->align != 4096)) { 135a5cf2bb4SCornelia Huck return -EINVAL; 136a5cf2bb4SCornelia Huck } 137a5cf2bb4SCornelia Huck 138f24a6840SPaolo Bonzini if (!vdev) { 139a5cf2bb4SCornelia Huck return -EINVAL; 140a5cf2bb4SCornelia Huck } 141a5cf2bb4SCornelia Huck 1420db87e0dSCornelia Huck if (info) { 1430db87e0dSCornelia Huck virtio_queue_set_rings(vdev, index, desc, info->avail, info->used); 1440db87e0dSCornelia Huck } else { 1450db87e0dSCornelia Huck virtio_queue_set_addr(vdev, index, desc); 1460db87e0dSCornelia Huck } 1470db87e0dSCornelia Huck if (!desc) { 148955cc8c9SJason Wang virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR); 149a5cf2bb4SCornelia Huck } else { 15079cd0c80SCornelia Huck if (info) { 15179cd0c80SCornelia Huck /* virtio-1 allows changing the ring size. */ 1528c797e75SMichael S. Tsirkin if (virtio_queue_get_max_num(vdev, index) < num) { 15379cd0c80SCornelia Huck /* Fail if we exceed the maximum number. */ 154a5cf2bb4SCornelia Huck return -EINVAL; 155a5cf2bb4SCornelia Huck } 15679cd0c80SCornelia Huck virtio_queue_set_num(vdev, index, num); 15779cd0c80SCornelia Huck } else if (virtio_queue_get_num(vdev, index) > num) { 15879cd0c80SCornelia Huck /* Fail if we don't have a big enough queue. */ 15979cd0c80SCornelia Huck return -EINVAL; 16079cd0c80SCornelia Huck } 16179cd0c80SCornelia Huck /* We ignore possible increased num for legacy for compatibility. */ 162f24a6840SPaolo Bonzini virtio_queue_set_vector(vdev, index, index); 163a5cf2bb4SCornelia Huck } 164a5cf2bb4SCornelia Huck /* tell notify handler in case of config change */ 1658dfbaa6aSJason Wang vdev->config_vector = VIRTIO_CCW_QUEUE_MAX; 166a5cf2bb4SCornelia Huck return 0; 167a5cf2bb4SCornelia Huck } 168a5cf2bb4SCornelia Huck 169fa8b0ca5SCornelia Huck static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev) 170fa8b0ca5SCornelia Huck { 171b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(dev); 172b804e8a6SJing Liu 173fa8b0ca5SCornelia Huck virtio_ccw_stop_ioeventfd(dev); 174fa8b0ca5SCornelia Huck virtio_reset(vdev); 175fa8b0ca5SCornelia Huck if (dev->indicators) { 176fa8b0ca5SCornelia Huck release_indicator(&dev->routes.adapter, dev->indicators); 177fa8b0ca5SCornelia Huck dev->indicators = NULL; 178fa8b0ca5SCornelia Huck } 179fa8b0ca5SCornelia Huck if (dev->indicators2) { 180fa8b0ca5SCornelia Huck release_indicator(&dev->routes.adapter, dev->indicators2); 181fa8b0ca5SCornelia Huck dev->indicators2 = NULL; 182fa8b0ca5SCornelia Huck } 183fa8b0ca5SCornelia Huck if (dev->summary_indicator) { 184fa8b0ca5SCornelia Huck release_indicator(&dev->routes.adapter, dev->summary_indicator); 185fa8b0ca5SCornelia Huck dev->summary_indicator = NULL; 186fa8b0ca5SCornelia Huck } 187b804e8a6SJing Liu ccw_dev->sch->thinint_active = false; 188fa8b0ca5SCornelia Huck } 189fa8b0ca5SCornelia Huck 1900db87e0dSCornelia Huck static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len, 1910db87e0dSCornelia Huck bool is_legacy) 192a5cf2bb4SCornelia Huck { 193a5cf2bb4SCornelia Huck int ret; 194a5cf2bb4SCornelia Huck VqInfoBlock info; 1950db87e0dSCornelia Huck VqInfoBlockLegacy linfo; 1960db87e0dSCornelia Huck size_t info_len = is_legacy ? sizeof(linfo) : sizeof(info); 1970db87e0dSCornelia Huck 1980db87e0dSCornelia Huck if (check_len) { 1990db87e0dSCornelia Huck if (ccw.count != info_len) { 2000db87e0dSCornelia Huck return -EINVAL; 2010db87e0dSCornelia Huck } 2020db87e0dSCornelia Huck } else if (ccw.count < info_len) { 2030db87e0dSCornelia Huck /* Can't execute command. */ 2040db87e0dSCornelia Huck return -EINVAL; 2050db87e0dSCornelia Huck } 2060db87e0dSCornelia Huck if (!ccw.cda) { 2070db87e0dSCornelia Huck return -EFAULT; 2080db87e0dSCornelia Huck } 2090db87e0dSCornelia Huck if (is_legacy) { 2100db87e0dSCornelia Huck linfo.queue = address_space_ldq_be(&address_space_memory, ccw.cda, 2110db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, NULL); 2120db87e0dSCornelia Huck linfo.align = address_space_ldl_be(&address_space_memory, 2130db87e0dSCornelia Huck ccw.cda + sizeof(linfo.queue), 2140db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, 2150db87e0dSCornelia Huck NULL); 2160db87e0dSCornelia Huck linfo.index = address_space_lduw_be(&address_space_memory, 2170db87e0dSCornelia Huck ccw.cda + sizeof(linfo.queue) 2180db87e0dSCornelia Huck + sizeof(linfo.align), 2190db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, 2200db87e0dSCornelia Huck NULL); 2210db87e0dSCornelia Huck linfo.num = address_space_lduw_be(&address_space_memory, 2220db87e0dSCornelia Huck ccw.cda + sizeof(linfo.queue) 2230db87e0dSCornelia Huck + sizeof(linfo.align) 2240db87e0dSCornelia Huck + sizeof(linfo.index), 2250db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, 2260db87e0dSCornelia Huck NULL); 2270db87e0dSCornelia Huck ret = virtio_ccw_set_vqs(sch, NULL, &linfo); 2280db87e0dSCornelia Huck } else { 2290db87e0dSCornelia Huck info.desc = address_space_ldq_be(&address_space_memory, ccw.cda, 2300db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, NULL); 2310db87e0dSCornelia Huck info.index = address_space_lduw_be(&address_space_memory, 2320db87e0dSCornelia Huck ccw.cda + sizeof(info.desc) 2330db87e0dSCornelia Huck + sizeof(info.res0), 2340db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, NULL); 2350db87e0dSCornelia Huck info.num = address_space_lduw_be(&address_space_memory, 2360db87e0dSCornelia Huck ccw.cda + sizeof(info.desc) 2370db87e0dSCornelia Huck + sizeof(info.res0) 2380db87e0dSCornelia Huck + sizeof(info.index), 2390db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, NULL); 2400db87e0dSCornelia Huck info.avail = address_space_ldq_be(&address_space_memory, 2410db87e0dSCornelia Huck ccw.cda + sizeof(info.desc) 2420db87e0dSCornelia Huck + sizeof(info.res0) 2430db87e0dSCornelia Huck + sizeof(info.index) 2440db87e0dSCornelia Huck + sizeof(info.num), 2450db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, NULL); 2460db87e0dSCornelia Huck info.used = address_space_ldq_be(&address_space_memory, 2470db87e0dSCornelia Huck ccw.cda + sizeof(info.desc) 2480db87e0dSCornelia Huck + sizeof(info.res0) 2490db87e0dSCornelia Huck + sizeof(info.index) 2500db87e0dSCornelia Huck + sizeof(info.num) 2510db87e0dSCornelia Huck + sizeof(info.avail), 2520db87e0dSCornelia Huck MEMTXATTRS_UNSPECIFIED, NULL); 2530db87e0dSCornelia Huck ret = virtio_ccw_set_vqs(sch, &info, NULL); 2540db87e0dSCornelia Huck } 2550db87e0dSCornelia Huck sch->curr_status.scsw.count = 0; 2560db87e0dSCornelia Huck return ret; 2570db87e0dSCornelia Huck } 2580db87e0dSCornelia Huck 2590db87e0dSCornelia Huck static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) 2600db87e0dSCornelia Huck { 2610db87e0dSCornelia Huck int ret; 262c42767f2SThomas Huth VirtioRevInfo revinfo; 263a5cf2bb4SCornelia Huck uint8_t status; 264a5cf2bb4SCornelia Huck VirtioFeatDesc features; 265a5cf2bb4SCornelia Huck void *config; 266a5cf2bb4SCornelia Huck hwaddr indicators; 267a5cf2bb4SCornelia Huck VqConfigBlock vq_config; 268a5cf2bb4SCornelia Huck VirtioCcwDevice *dev = sch->driver_data; 269f24a6840SPaolo Bonzini VirtIODevice *vdev = virtio_ccw_get_vdev(sch); 270a5cf2bb4SCornelia Huck bool check_len; 271a5cf2bb4SCornelia Huck int len; 272a5cf2bb4SCornelia Huck hwaddr hw_len; 2737e749462SCornelia Huck VirtioThinintInfo *thinint; 274a5cf2bb4SCornelia Huck 275a5cf2bb4SCornelia Huck if (!dev) { 276a5cf2bb4SCornelia Huck return -EINVAL; 277a5cf2bb4SCornelia Huck } 278a5cf2bb4SCornelia Huck 279a5cf2bb4SCornelia Huck trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid, 280a5cf2bb4SCornelia Huck ccw.cmd_code); 281a5cf2bb4SCornelia Huck check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); 282a5cf2bb4SCornelia Huck 28347e13dfdSHalil Pasic if (dev->force_revision_1 && dev->revision < 0 && 28447e13dfdSHalil Pasic ccw.cmd_code != CCW_CMD_SET_VIRTIO_REV) { 28547e13dfdSHalil Pasic /* 28647e13dfdSHalil Pasic * virtio-1 drivers must start with negotiating to a revision >= 1, 28747e13dfdSHalil Pasic * so post a command reject for all other commands 28847e13dfdSHalil Pasic */ 28947e13dfdSHalil Pasic return -ENOSYS; 29047e13dfdSHalil Pasic } 29147e13dfdSHalil Pasic 292a5cf2bb4SCornelia Huck /* Look at the command. */ 293a5cf2bb4SCornelia Huck switch (ccw.cmd_code) { 294a5cf2bb4SCornelia Huck case CCW_CMD_SET_VQ: 2950db87e0dSCornelia Huck ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1); 296a5cf2bb4SCornelia Huck break; 297a5cf2bb4SCornelia Huck case CCW_CMD_VDEV_RESET: 298fa8b0ca5SCornelia Huck virtio_ccw_reset_virtio(dev, vdev); 299a5cf2bb4SCornelia Huck ret = 0; 300a5cf2bb4SCornelia Huck break; 301a5cf2bb4SCornelia Huck case CCW_CMD_READ_FEAT: 302a5cf2bb4SCornelia Huck if (check_len) { 303a5cf2bb4SCornelia Huck if (ccw.count != sizeof(features)) { 304a5cf2bb4SCornelia Huck ret = -EINVAL; 305a5cf2bb4SCornelia Huck break; 306a5cf2bb4SCornelia Huck } 307a5cf2bb4SCornelia Huck } else if (ccw.count < sizeof(features)) { 308a5cf2bb4SCornelia Huck /* Can't execute command. */ 309a5cf2bb4SCornelia Huck ret = -EINVAL; 310a5cf2bb4SCornelia Huck break; 311a5cf2bb4SCornelia Huck } 312a5cf2bb4SCornelia Huck if (!ccw.cda) { 313a5cf2bb4SCornelia Huck ret = -EFAULT; 314a5cf2bb4SCornelia Huck } else { 3159b706dbbSMichael S. Tsirkin VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 3169b706dbbSMichael S. Tsirkin 31742874d3aSPeter Maydell features.index = address_space_ldub(&address_space_memory, 31842874d3aSPeter Maydell ccw.cda 31942874d3aSPeter Maydell + sizeof(features.features), 32042874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 32142874d3aSPeter Maydell NULL); 3226b8f1020SCornelia Huck if (features.index == 0) { 323542571d5SCornelia Huck if (dev->revision >= 1) { 324542571d5SCornelia Huck /* Don't offer legacy features for modern devices. */ 325542571d5SCornelia Huck features.features = (uint32_t) 3269b706dbbSMichael S. Tsirkin (vdev->host_features & ~vdc->legacy_features); 327542571d5SCornelia Huck } else { 328c42767f2SThomas Huth features.features = (uint32_t)vdev->host_features; 329542571d5SCornelia Huck } 330b4f8f9dfSCornelia Huck } else if ((features.index == 1) && (dev->revision >= 1)) { 331c42767f2SThomas Huth /* 332b4f8f9dfSCornelia Huck * Only offer feature bits beyond 31 if the guest has 333b4f8f9dfSCornelia Huck * negotiated at least revision 1. 334c42767f2SThomas Huth */ 335b4f8f9dfSCornelia Huck features.features = (uint32_t)(vdev->host_features >> 32); 336a5cf2bb4SCornelia Huck } else { 337a5cf2bb4SCornelia Huck /* Return zeroes if the guest supports more feature bits. */ 338a5cf2bb4SCornelia Huck features.features = 0; 339a5cf2bb4SCornelia Huck } 34042874d3aSPeter Maydell address_space_stl_le(&address_space_memory, ccw.cda, 34142874d3aSPeter Maydell features.features, MEMTXATTRS_UNSPECIFIED, 34242874d3aSPeter Maydell NULL); 343a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - sizeof(features); 344a5cf2bb4SCornelia Huck ret = 0; 345a5cf2bb4SCornelia Huck } 346a5cf2bb4SCornelia Huck break; 347a5cf2bb4SCornelia Huck case CCW_CMD_WRITE_FEAT: 348a5cf2bb4SCornelia Huck if (check_len) { 349a5cf2bb4SCornelia Huck if (ccw.count != sizeof(features)) { 350a5cf2bb4SCornelia Huck ret = -EINVAL; 351a5cf2bb4SCornelia Huck break; 352a5cf2bb4SCornelia Huck } 353a5cf2bb4SCornelia Huck } else if (ccw.count < sizeof(features)) { 354a5cf2bb4SCornelia Huck /* Can't execute command. */ 355a5cf2bb4SCornelia Huck ret = -EINVAL; 356a5cf2bb4SCornelia Huck break; 357a5cf2bb4SCornelia Huck } 358a5cf2bb4SCornelia Huck if (!ccw.cda) { 359a5cf2bb4SCornelia Huck ret = -EFAULT; 360a5cf2bb4SCornelia Huck } else { 36142874d3aSPeter Maydell features.index = address_space_ldub(&address_space_memory, 36242874d3aSPeter Maydell ccw.cda 36342874d3aSPeter Maydell + sizeof(features.features), 36442874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 36542874d3aSPeter Maydell NULL); 36642874d3aSPeter Maydell features.features = address_space_ldl_le(&address_space_memory, 36742874d3aSPeter Maydell ccw.cda, 36842874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 36942874d3aSPeter Maydell NULL); 3706b8f1020SCornelia Huck if (features.index == 0) { 371c42767f2SThomas Huth virtio_set_features(vdev, 372c42767f2SThomas Huth (vdev->guest_features & 0xffffffff00000000ULL) | 373c42767f2SThomas Huth features.features); 374b4f8f9dfSCornelia Huck } else if ((features.index == 1) && (dev->revision >= 1)) { 375c42767f2SThomas Huth /* 376b4f8f9dfSCornelia Huck * If the guest did not negotiate at least revision 1, 377b4f8f9dfSCornelia Huck * we did not offer it any feature bits beyond 31. Such a 378b4f8f9dfSCornelia Huck * guest passing us any bit here is therefore buggy. 379c42767f2SThomas Huth */ 380c42767f2SThomas Huth virtio_set_features(vdev, 381c42767f2SThomas Huth (vdev->guest_features & 0x00000000ffffffffULL) | 382c42767f2SThomas Huth ((uint64_t)features.features << 32)); 383a5cf2bb4SCornelia Huck } else { 384a5cf2bb4SCornelia Huck /* 385a5cf2bb4SCornelia Huck * If the guest supports more feature bits, assert that it 386a5cf2bb4SCornelia Huck * passes us zeroes for those we don't support. 387a5cf2bb4SCornelia Huck */ 388a5cf2bb4SCornelia Huck if (features.features) { 389a5cf2bb4SCornelia Huck fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n", 390a5cf2bb4SCornelia Huck features.index, features.features); 391a5cf2bb4SCornelia Huck /* XXX: do a unit check here? */ 392a5cf2bb4SCornelia Huck } 393a5cf2bb4SCornelia Huck } 394a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - sizeof(features); 395a5cf2bb4SCornelia Huck ret = 0; 396a5cf2bb4SCornelia Huck } 397a5cf2bb4SCornelia Huck break; 398a5cf2bb4SCornelia Huck case CCW_CMD_READ_CONF: 399a5cf2bb4SCornelia Huck if (check_len) { 400f24a6840SPaolo Bonzini if (ccw.count > vdev->config_len) { 401a5cf2bb4SCornelia Huck ret = -EINVAL; 402a5cf2bb4SCornelia Huck break; 403a5cf2bb4SCornelia Huck } 404a5cf2bb4SCornelia Huck } 405f24a6840SPaolo Bonzini len = MIN(ccw.count, vdev->config_len); 406a5cf2bb4SCornelia Huck if (!ccw.cda) { 407a5cf2bb4SCornelia Huck ret = -EFAULT; 408a5cf2bb4SCornelia Huck } else { 409f24a6840SPaolo Bonzini virtio_bus_get_vdev_config(&dev->bus, vdev->config); 410a5cf2bb4SCornelia Huck /* XXX config space endianness */ 411f24a6840SPaolo Bonzini cpu_physical_memory_write(ccw.cda, vdev->config, len); 412a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - len; 413a5cf2bb4SCornelia Huck ret = 0; 414a5cf2bb4SCornelia Huck } 415a5cf2bb4SCornelia Huck break; 416a5cf2bb4SCornelia Huck case CCW_CMD_WRITE_CONF: 417a5cf2bb4SCornelia Huck if (check_len) { 418f24a6840SPaolo Bonzini if (ccw.count > vdev->config_len) { 419a5cf2bb4SCornelia Huck ret = -EINVAL; 420a5cf2bb4SCornelia Huck break; 421a5cf2bb4SCornelia Huck } 422a5cf2bb4SCornelia Huck } 423f24a6840SPaolo Bonzini len = MIN(ccw.count, vdev->config_len); 424a5cf2bb4SCornelia Huck hw_len = len; 425a5cf2bb4SCornelia Huck if (!ccw.cda) { 426a5cf2bb4SCornelia Huck ret = -EFAULT; 427a5cf2bb4SCornelia Huck } else { 428a5cf2bb4SCornelia Huck config = cpu_physical_memory_map(ccw.cda, &hw_len, 0); 429a5cf2bb4SCornelia Huck if (!config) { 430a5cf2bb4SCornelia Huck ret = -EFAULT; 431a5cf2bb4SCornelia Huck } else { 432a5cf2bb4SCornelia Huck len = hw_len; 433a5cf2bb4SCornelia Huck /* XXX config space endianness */ 434f24a6840SPaolo Bonzini memcpy(vdev->config, config, len); 435a5cf2bb4SCornelia Huck cpu_physical_memory_unmap(config, hw_len, 0, hw_len); 436f24a6840SPaolo Bonzini virtio_bus_set_vdev_config(&dev->bus, vdev->config); 437a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - len; 438a5cf2bb4SCornelia Huck ret = 0; 439a5cf2bb4SCornelia Huck } 440a5cf2bb4SCornelia Huck } 441a5cf2bb4SCornelia Huck break; 442e32652f7SPierre Morel case CCW_CMD_READ_STATUS: 443e32652f7SPierre Morel if (check_len) { 444e32652f7SPierre Morel if (ccw.count != sizeof(status)) { 445e32652f7SPierre Morel ret = -EINVAL; 446e32652f7SPierre Morel break; 447e32652f7SPierre Morel } 448e32652f7SPierre Morel } else if (ccw.count < sizeof(status)) { 449e32652f7SPierre Morel /* Can't execute command. */ 450e32652f7SPierre Morel ret = -EINVAL; 451e32652f7SPierre Morel break; 452e32652f7SPierre Morel } 453e32652f7SPierre Morel if (!ccw.cda) { 454e32652f7SPierre Morel ret = -EFAULT; 455e32652f7SPierre Morel } else { 456e32652f7SPierre Morel address_space_stb(&address_space_memory, ccw.cda, vdev->status, 457e32652f7SPierre Morel MEMTXATTRS_UNSPECIFIED, NULL); 458e32652f7SPierre Morel sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);; 459e32652f7SPierre Morel ret = 0; 460e32652f7SPierre Morel } 461e32652f7SPierre Morel break; 462a5cf2bb4SCornelia Huck case CCW_CMD_WRITE_STATUS: 463a5cf2bb4SCornelia Huck if (check_len) { 464a5cf2bb4SCornelia Huck if (ccw.count != sizeof(status)) { 465a5cf2bb4SCornelia Huck ret = -EINVAL; 466a5cf2bb4SCornelia Huck break; 467a5cf2bb4SCornelia Huck } 468a5cf2bb4SCornelia Huck } else if (ccw.count < sizeof(status)) { 469a5cf2bb4SCornelia Huck /* Can't execute command. */ 470a5cf2bb4SCornelia Huck ret = -EINVAL; 471a5cf2bb4SCornelia Huck break; 472a5cf2bb4SCornelia Huck } 473a5cf2bb4SCornelia Huck if (!ccw.cda) { 474a5cf2bb4SCornelia Huck ret = -EFAULT; 475a5cf2bb4SCornelia Huck } else { 47642874d3aSPeter Maydell status = address_space_ldub(&address_space_memory, ccw.cda, 47742874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, NULL); 478b4436a0bSCornelia Huck if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { 479b4436a0bSCornelia Huck virtio_ccw_stop_ioeventfd(dev); 480b4436a0bSCornelia Huck } 4810b352fd6SCornelia Huck if (virtio_set_status(vdev, status) == 0) { 482f24a6840SPaolo Bonzini if (vdev->status == 0) { 483fa8b0ca5SCornelia Huck virtio_ccw_reset_virtio(dev, vdev); 484a5cf2bb4SCornelia Huck } 485b4436a0bSCornelia Huck if (status & VIRTIO_CONFIG_S_DRIVER_OK) { 486b4436a0bSCornelia Huck virtio_ccw_start_ioeventfd(dev); 487b4436a0bSCornelia Huck } 488a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - sizeof(status); 489a5cf2bb4SCornelia Huck ret = 0; 4900b352fd6SCornelia Huck } else { 4910b352fd6SCornelia Huck /* Trigger a command reject. */ 4920b352fd6SCornelia Huck ret = -ENOSYS; 4930b352fd6SCornelia Huck } 494a5cf2bb4SCornelia Huck } 495a5cf2bb4SCornelia Huck break; 496a5cf2bb4SCornelia Huck case CCW_CMD_SET_IND: 497a5cf2bb4SCornelia Huck if (check_len) { 498a5cf2bb4SCornelia Huck if (ccw.count != sizeof(indicators)) { 499a5cf2bb4SCornelia Huck ret = -EINVAL; 500a5cf2bb4SCornelia Huck break; 501a5cf2bb4SCornelia Huck } 502a5cf2bb4SCornelia Huck } else if (ccw.count < sizeof(indicators)) { 503a5cf2bb4SCornelia Huck /* Can't execute command. */ 504a5cf2bb4SCornelia Huck ret = -EINVAL; 505a5cf2bb4SCornelia Huck break; 506a5cf2bb4SCornelia Huck } 5077e749462SCornelia Huck if (sch->thinint_active) { 5087e749462SCornelia Huck /* Trigger a command reject. */ 5097e749462SCornelia Huck ret = -ENOSYS; 5107e749462SCornelia Huck break; 5117e749462SCornelia Huck } 512d1db1fa8SCornelia Huck if (!ccw.cda) { 513a5cf2bb4SCornelia Huck ret = -EFAULT; 514a5cf2bb4SCornelia Huck } else { 51542874d3aSPeter Maydell indicators = address_space_ldq_be(&address_space_memory, ccw.cda, 51642874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, NULL); 5177bca3892SCornelia Huck dev->indicators = get_indicator(indicators, sizeof(uint64_t)); 518a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - sizeof(indicators); 519a5cf2bb4SCornelia Huck ret = 0; 520a5cf2bb4SCornelia Huck } 521a5cf2bb4SCornelia Huck break; 522a5cf2bb4SCornelia Huck case CCW_CMD_SET_CONF_IND: 523a5cf2bb4SCornelia Huck if (check_len) { 524a5cf2bb4SCornelia Huck if (ccw.count != sizeof(indicators)) { 525a5cf2bb4SCornelia Huck ret = -EINVAL; 526a5cf2bb4SCornelia Huck break; 527a5cf2bb4SCornelia Huck } 528a5cf2bb4SCornelia Huck } else if (ccw.count < sizeof(indicators)) { 529a5cf2bb4SCornelia Huck /* Can't execute command. */ 530a5cf2bb4SCornelia Huck ret = -EINVAL; 531a5cf2bb4SCornelia Huck break; 532a5cf2bb4SCornelia Huck } 533d1db1fa8SCornelia Huck if (!ccw.cda) { 534a5cf2bb4SCornelia Huck ret = -EFAULT; 535a5cf2bb4SCornelia Huck } else { 53642874d3aSPeter Maydell indicators = address_space_ldq_be(&address_space_memory, ccw.cda, 53742874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, NULL); 5387bca3892SCornelia Huck dev->indicators2 = get_indicator(indicators, sizeof(uint64_t)); 539a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - sizeof(indicators); 540a5cf2bb4SCornelia Huck ret = 0; 541a5cf2bb4SCornelia Huck } 542a5cf2bb4SCornelia Huck break; 543a5cf2bb4SCornelia Huck case CCW_CMD_READ_VQ_CONF: 544a5cf2bb4SCornelia Huck if (check_len) { 545a5cf2bb4SCornelia Huck if (ccw.count != sizeof(vq_config)) { 546a5cf2bb4SCornelia Huck ret = -EINVAL; 547a5cf2bb4SCornelia Huck break; 548a5cf2bb4SCornelia Huck } 549a5cf2bb4SCornelia Huck } else if (ccw.count < sizeof(vq_config)) { 550a5cf2bb4SCornelia Huck /* Can't execute command. */ 551a5cf2bb4SCornelia Huck ret = -EINVAL; 552a5cf2bb4SCornelia Huck break; 553a5cf2bb4SCornelia Huck } 554a5cf2bb4SCornelia Huck if (!ccw.cda) { 555a5cf2bb4SCornelia Huck ret = -EFAULT; 556a5cf2bb4SCornelia Huck } else { 55742874d3aSPeter Maydell vq_config.index = address_space_lduw_be(&address_space_memory, 55842874d3aSPeter Maydell ccw.cda, 55942874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 56042874d3aSPeter Maydell NULL); 5618dfbaa6aSJason Wang if (vq_config.index >= VIRTIO_CCW_QUEUE_MAX) { 562d03a3630SCornelia Huck ret = -EINVAL; 563d03a3630SCornelia Huck break; 564d03a3630SCornelia Huck } 565f24a6840SPaolo Bonzini vq_config.num_max = virtio_queue_get_num(vdev, 566a5cf2bb4SCornelia Huck vq_config.index); 56742874d3aSPeter Maydell address_space_stw_be(&address_space_memory, 56842874d3aSPeter Maydell ccw.cda + sizeof(vq_config.index), 56942874d3aSPeter Maydell vq_config.num_max, 57042874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 57142874d3aSPeter Maydell NULL); 572a5cf2bb4SCornelia Huck sch->curr_status.scsw.count = ccw.count - sizeof(vq_config); 573a5cf2bb4SCornelia Huck ret = 0; 574a5cf2bb4SCornelia Huck } 575a5cf2bb4SCornelia Huck break; 5767e749462SCornelia Huck case CCW_CMD_SET_IND_ADAPTER: 5777e749462SCornelia Huck if (check_len) { 5787e749462SCornelia Huck if (ccw.count != sizeof(*thinint)) { 5797e749462SCornelia Huck ret = -EINVAL; 5807e749462SCornelia Huck break; 5817e749462SCornelia Huck } 5827e749462SCornelia Huck } else if (ccw.count < sizeof(*thinint)) { 5837e749462SCornelia Huck /* Can't execute command. */ 5847e749462SCornelia Huck ret = -EINVAL; 5857e749462SCornelia Huck break; 5867e749462SCornelia Huck } 5877e749462SCornelia Huck len = sizeof(*thinint); 5887e749462SCornelia Huck hw_len = len; 5897e749462SCornelia Huck if (!ccw.cda) { 5907e749462SCornelia Huck ret = -EFAULT; 5917e749462SCornelia Huck } else if (dev->indicators && !sch->thinint_active) { 5927e749462SCornelia Huck /* Trigger a command reject. */ 5937e749462SCornelia Huck ret = -ENOSYS; 5947e749462SCornelia Huck } else { 5957e749462SCornelia Huck thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0); 5967e749462SCornelia Huck if (!thinint) { 5977e749462SCornelia Huck ret = -EFAULT; 5987e749462SCornelia Huck } else { 5997d45285fSCornelia Huck uint64_t ind_bit = ldq_be_p(&thinint->ind_bit); 6007d45285fSCornelia Huck 6017e749462SCornelia Huck len = hw_len; 6027bca3892SCornelia Huck dev->summary_indicator = 6037d45285fSCornelia Huck get_indicator(ldq_be_p(&thinint->summary_indicator), 6047d45285fSCornelia Huck sizeof(uint8_t)); 6057d45285fSCornelia Huck dev->indicators = 6067d45285fSCornelia Huck get_indicator(ldq_be_p(&thinint->device_indicator), 6077d45285fSCornelia Huck ind_bit / 8 + 1); 6087e749462SCornelia Huck dev->thinint_isc = thinint->isc; 6097d45285fSCornelia Huck dev->routes.adapter.ind_offset = ind_bit; 610d426d9fbSCornelia Huck dev->routes.adapter.summary_offset = 7; 6117e749462SCornelia Huck cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len); 61203cf077aSCornelia Huck ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO, 61303cf077aSCornelia Huck dev->thinint_isc, true, false, 614d426d9fbSCornelia Huck &dev->routes.adapter.adapter_id); 61503cf077aSCornelia Huck assert(ret == 0); 6167bca3892SCornelia Huck sch->thinint_active = ((dev->indicators != NULL) && 6177bca3892SCornelia Huck (dev->summary_indicator != NULL)); 6187e749462SCornelia Huck sch->curr_status.scsw.count = ccw.count - len; 6197e749462SCornelia Huck ret = 0; 6207e749462SCornelia Huck } 6217e749462SCornelia Huck } 6227e749462SCornelia Huck break; 623c42767f2SThomas Huth case CCW_CMD_SET_VIRTIO_REV: 624c42767f2SThomas Huth len = sizeof(revinfo); 625c42767f2SThomas Huth if (ccw.count < len) { 626c42767f2SThomas Huth ret = -EINVAL; 627c42767f2SThomas Huth break; 628c42767f2SThomas Huth } 629c42767f2SThomas Huth if (!ccw.cda) { 630c42767f2SThomas Huth ret = -EFAULT; 631c42767f2SThomas Huth break; 632c42767f2SThomas Huth } 633c42767f2SThomas Huth revinfo.revision = 634c42767f2SThomas Huth address_space_lduw_be(&address_space_memory, ccw.cda, 635c42767f2SThomas Huth MEMTXATTRS_UNSPECIFIED, NULL); 636c42767f2SThomas Huth revinfo.length = 637c42767f2SThomas Huth address_space_lduw_be(&address_space_memory, 638c42767f2SThomas Huth ccw.cda + sizeof(revinfo.revision), 639c42767f2SThomas Huth MEMTXATTRS_UNSPECIFIED, NULL); 640c42767f2SThomas Huth if (ccw.count < len + revinfo.length || 641c42767f2SThomas Huth (check_len && ccw.count > len + revinfo.length)) { 642c42767f2SThomas Huth ret = -EINVAL; 643c42767f2SThomas Huth break; 644c42767f2SThomas Huth } 645c42767f2SThomas Huth /* 646c42767f2SThomas Huth * Once we start to support revisions with additional data, we'll 647c42767f2SThomas Huth * need to fetch it here. Nothing to do for now, though. 648c42767f2SThomas Huth */ 649c42767f2SThomas Huth if (dev->revision >= 0 || 65047e13dfdSHalil Pasic revinfo.revision > virtio_ccw_rev_max(dev) || 65147e13dfdSHalil Pasic (dev->force_revision_1 && !revinfo.revision)) { 652c42767f2SThomas Huth ret = -ENOSYS; 653c42767f2SThomas Huth break; 654c42767f2SThomas Huth } 655c42767f2SThomas Huth ret = 0; 656c42767f2SThomas Huth dev->revision = revinfo.revision; 657c42767f2SThomas Huth break; 658a5cf2bb4SCornelia Huck default: 6598d034a6fSCornelia Huck ret = -ENOSYS; 660a5cf2bb4SCornelia Huck break; 661a5cf2bb4SCornelia Huck } 662a5cf2bb4SCornelia Huck return ret; 663a5cf2bb4SCornelia Huck } 664a5cf2bb4SCornelia Huck 665c42767f2SThomas Huth static void virtio_sch_disable_cb(SubchDev *sch) 666c42767f2SThomas Huth { 667c42767f2SThomas Huth VirtioCcwDevice *dev = sch->driver_data; 668c42767f2SThomas Huth 669c42767f2SThomas Huth dev->revision = -1; 670c42767f2SThomas Huth } 671c42767f2SThomas Huth 6721fa75523SCornelia Huck static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) 673a5cf2bb4SCornelia Huck { 6741fa75523SCornelia Huck VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); 675b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(dev); 676b804e8a6SJing Liu SubchDev *sch = css_create_virtual_sch(ccw_dev->bus_id, errp); 677cf249935SSascha Silbe Error *err = NULL; 678a5cf2bb4SCornelia Huck 679cf249935SSascha Silbe if (!sch) { 680cf249935SSascha Silbe return; 681cf249935SSascha Silbe } 68247e13dfdSHalil Pasic if (!virtio_ccw_rev_max(dev) && dev->force_revision_1) { 68347e13dfdSHalil Pasic error_setg(&err, "Invalid value of property max_rev " 68447e13dfdSHalil Pasic "(is %d expected >= 1)", virtio_ccw_rev_max(dev)); 68547e13dfdSHalil Pasic error_propagate(errp, err); 68647e13dfdSHalil Pasic return; 68747e13dfdSHalil Pasic } 688a5cf2bb4SCornelia Huck 689a5cf2bb4SCornelia Huck sch->driver_data = dev; 690a5cf2bb4SCornelia Huck sch->ccw_cb = virtio_ccw_cb; 691c42767f2SThomas Huth sch->disable_cb = virtio_sch_disable_cb; 692a5cf2bb4SCornelia Huck sch->id.reserved = 0xff; 693a5cf2bb4SCornelia Huck sch->id.cu_type = VIRTIO_CCW_CU_TYPE; 694b804e8a6SJing Liu ccw_dev->sch = sch; 695cf249935SSascha Silbe dev->indicators = NULL; 696c42767f2SThomas Huth dev->revision = -1; 697cf249935SSascha Silbe css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE); 698cf249935SSascha Silbe 699cf249935SSascha Silbe trace_virtio_ccw_new_device( 700cf249935SSascha Silbe sch->cssid, sch->ssid, sch->schid, sch->devno, 701b804e8a6SJing Liu ccw_dev->bus_id.valid ? "user-configured" : "auto-configured"); 702c42767f2SThomas Huth 703ca2b413cSPaolo Bonzini if (!kvm_eventfds_enabled()) { 704ca2b413cSPaolo Bonzini dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD; 705ca2b413cSPaolo Bonzini } 706ca2b413cSPaolo Bonzini 7071fa75523SCornelia Huck if (k->realize) { 7081fa75523SCornelia Huck k->realize(dev, &err); 7091fa75523SCornelia Huck } 7101fa75523SCornelia Huck if (err) { 7111fa75523SCornelia Huck error_propagate(errp, err); 71206e686eaSCornelia Huck css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); 713b804e8a6SJing Liu ccw_dev->sch = NULL; 714a5cf2bb4SCornelia Huck g_free(sch); 715a5cf2bb4SCornelia Huck } 716cf249935SSascha Silbe } 717a5cf2bb4SCornelia Huck 718a5cf2bb4SCornelia Huck static int virtio_ccw_exit(VirtioCcwDevice *dev) 719a5cf2bb4SCornelia Huck { 720b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(dev); 721b804e8a6SJing Liu SubchDev *sch = ccw_dev->sch; 722a5cf2bb4SCornelia Huck 723a5cf2bb4SCornelia Huck if (sch) { 724a5cf2bb4SCornelia Huck css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); 725a5cf2bb4SCornelia Huck g_free(sch); 726a5cf2bb4SCornelia Huck } 7277bca3892SCornelia Huck if (dev->indicators) { 728d426d9fbSCornelia Huck release_indicator(&dev->routes.adapter, dev->indicators); 7297bca3892SCornelia Huck dev->indicators = NULL; 7307bca3892SCornelia Huck } 731a5cf2bb4SCornelia Huck return 0; 732a5cf2bb4SCornelia Huck } 733a5cf2bb4SCornelia Huck 7345e5ced38SMarkus Armbruster static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp) 735a5cf2bb4SCornelia Huck { 736800ced8cSKONRAD Frederic DeviceState *qdev = DEVICE(ccw_dev); 73789334c8bSKONRAD Frederic VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev); 73889334c8bSKONRAD Frederic DeviceState *vdev = DEVICE(&dev->vdev); 739a5cf2bb4SCornelia Huck 740800ced8cSKONRAD Frederic virtio_net_set_netclient_name(&dev->vdev, qdev->id, 741800ced8cSKONRAD Frederic object_get_typename(OBJECT(qdev))); 74289334c8bSKONRAD Frederic qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 7436b62d961SEduardo Habkost object_property_set_bool(OBJECT(vdev), true, "realized", errp); 744a5cf2bb4SCornelia Huck } 745a5cf2bb4SCornelia Huck 74689334c8bSKONRAD Frederic static void virtio_ccw_net_instance_init(Object *obj) 747a5cf2bb4SCornelia Huck { 74889334c8bSKONRAD Frederic VirtIONetCcw *dev = VIRTIO_NET_CCW(obj); 749c8075cafSGonglei 750c8075cafSGonglei virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 751c8075cafSGonglei TYPE_VIRTIO_NET); 7520cf63c3eSGonglei object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), 7530cf63c3eSGonglei "bootindex", &error_abort); 754a5cf2bb4SCornelia Huck } 755a5cf2bb4SCornelia Huck 7565e5ced38SMarkus Armbruster static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp) 757a5cf2bb4SCornelia Huck { 7583400c455SKONRAD Frederic VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); 7593400c455SKONRAD Frederic DeviceState *vdev = DEVICE(&dev->vdev); 7605e5ced38SMarkus Armbruster 7613400c455SKONRAD Frederic qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 7626b62d961SEduardo Habkost object_property_set_bool(OBJECT(vdev), true, "realized", errp); 763a5cf2bb4SCornelia Huck } 764a5cf2bb4SCornelia Huck 7653400c455SKONRAD Frederic static void virtio_ccw_blk_instance_init(Object *obj) 766a5cf2bb4SCornelia Huck { 7673400c455SKONRAD Frederic VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj); 768c8075cafSGonglei 769c8075cafSGonglei virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 770c8075cafSGonglei TYPE_VIRTIO_BLK); 771467b3f33SStefan Hajnoczi object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", 772467b3f33SStefan Hajnoczi &error_abort); 773aeb98ddcSGonglei object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), 774aeb98ddcSGonglei "bootindex", &error_abort); 775a5cf2bb4SCornelia Huck } 776a5cf2bb4SCornelia Huck 7775e5ced38SMarkus Armbruster static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) 778a5cf2bb4SCornelia Huck { 7796acf69cdSKONRAD Frederic VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev); 7806acf69cdSKONRAD Frederic DeviceState *vdev = DEVICE(&dev->vdev); 78180270a19SKONRAD Frederic DeviceState *proxy = DEVICE(ccw_dev); 78280270a19SKONRAD Frederic char *bus_name; 78380270a19SKONRAD Frederic 78480270a19SKONRAD Frederic /* 78580270a19SKONRAD Frederic * For command line compatibility, this sets the virtio-serial-device bus 78680270a19SKONRAD Frederic * name as before. 78780270a19SKONRAD Frederic */ 78880270a19SKONRAD Frederic if (proxy->id) { 78980270a19SKONRAD Frederic bus_name = g_strdup_printf("%s.0", proxy->id); 79080270a19SKONRAD Frederic virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); 79180270a19SKONRAD Frederic g_free(bus_name); 79280270a19SKONRAD Frederic } 793a5cf2bb4SCornelia Huck 7946acf69cdSKONRAD Frederic qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 7956b62d961SEduardo Habkost object_property_set_bool(OBJECT(vdev), true, "realized", errp); 796a5cf2bb4SCornelia Huck } 797a5cf2bb4SCornelia Huck 7986acf69cdSKONRAD Frederic 7996acf69cdSKONRAD Frederic static void virtio_ccw_serial_instance_init(Object *obj) 800a5cf2bb4SCornelia Huck { 8016acf69cdSKONRAD Frederic VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj); 802c8075cafSGonglei 803c8075cafSGonglei virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 804c8075cafSGonglei TYPE_VIRTIO_SERIAL); 805a5cf2bb4SCornelia Huck } 806a5cf2bb4SCornelia Huck 8075e5ced38SMarkus Armbruster static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp) 808a5cf2bb4SCornelia Huck { 80930bff6a0SKONRAD Frederic VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev); 81030bff6a0SKONRAD Frederic DeviceState *vdev = DEVICE(&dev->vdev); 811a5cf2bb4SCornelia Huck 81230bff6a0SKONRAD Frederic qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 8136b62d961SEduardo Habkost object_property_set_bool(OBJECT(vdev), true, "realized", errp); 814a5cf2bb4SCornelia Huck } 815a5cf2bb4SCornelia Huck 81630bff6a0SKONRAD Frederic static void virtio_ccw_balloon_instance_init(Object *obj) 817a5cf2bb4SCornelia Huck { 81830bff6a0SKONRAD Frederic VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj); 819ecfa60e3SShannon Zhao 820a6027b0fSDenis V. Lunev virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 821a6027b0fSDenis V. Lunev TYPE_VIRTIO_BALLOON); 822ecfa60e3SShannon Zhao object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev), 823ecfa60e3SShannon Zhao "guest-stats", &error_abort); 824ecfa60e3SShannon Zhao object_property_add_alias(obj, "guest-stats-polling-interval", 825ecfa60e3SShannon Zhao OBJECT(&dev->vdev), 826ecfa60e3SShannon Zhao "guest-stats-polling-interval", &error_abort); 827a5cf2bb4SCornelia Huck } 828a5cf2bb4SCornelia Huck 8295e5ced38SMarkus Armbruster static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) 830a5cf2bb4SCornelia Huck { 831c908ea10SKONRAD Frederic VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev); 832c908ea10SKONRAD Frederic DeviceState *vdev = DEVICE(&dev->vdev); 8336f32a6b4SKONRAD Frederic DeviceState *qdev = DEVICE(ccw_dev); 8346f32a6b4SKONRAD Frederic char *bus_name; 8356f32a6b4SKONRAD Frederic 8366f32a6b4SKONRAD Frederic /* 8376f32a6b4SKONRAD Frederic * For command line compatibility, this sets the virtio-scsi-device bus 8386f32a6b4SKONRAD Frederic * name as before. 8396f32a6b4SKONRAD Frederic */ 8406f32a6b4SKONRAD Frederic if (qdev->id) { 8416f32a6b4SKONRAD Frederic bus_name = g_strdup_printf("%s.0", qdev->id); 8426f32a6b4SKONRAD Frederic virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); 8436f32a6b4SKONRAD Frederic g_free(bus_name); 8446f32a6b4SKONRAD Frederic } 845a5cf2bb4SCornelia Huck 846c908ea10SKONRAD Frederic qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 8476b62d961SEduardo Habkost object_property_set_bool(OBJECT(vdev), true, "realized", errp); 848a5cf2bb4SCornelia Huck } 849a5cf2bb4SCornelia Huck 850c908ea10SKONRAD Frederic static void virtio_ccw_scsi_instance_init(Object *obj) 851a5cf2bb4SCornelia Huck { 852c908ea10SKONRAD Frederic VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj); 853c8075cafSGonglei 854c8075cafSGonglei virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 855c8075cafSGonglei TYPE_VIRTIO_SCSI); 85619d339f1SFam Zheng object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread", 85719d339f1SFam Zheng &error_abort); 858a5cf2bb4SCornelia Huck } 859a5cf2bb4SCornelia Huck 860ccf6916cSPaolo Bonzini #ifdef CONFIG_VHOST_SCSI 8615e5ced38SMarkus Armbruster static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) 862ccf6916cSPaolo Bonzini { 863ccf6916cSPaolo Bonzini VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); 864ccf6916cSPaolo Bonzini DeviceState *vdev = DEVICE(&dev->vdev); 865ccf6916cSPaolo Bonzini 866ccf6916cSPaolo Bonzini qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 8676b62d961SEduardo Habkost object_property_set_bool(OBJECT(vdev), true, "realized", errp); 868ccf6916cSPaolo Bonzini } 869ccf6916cSPaolo Bonzini 870ccf6916cSPaolo Bonzini static void vhost_ccw_scsi_instance_init(Object *obj) 871ccf6916cSPaolo Bonzini { 872ccf6916cSPaolo Bonzini VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); 873c8075cafSGonglei 874c8075cafSGonglei virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 875c8075cafSGonglei TYPE_VHOST_SCSI); 876ccf6916cSPaolo Bonzini } 877ccf6916cSPaolo Bonzini #endif 878ccf6916cSPaolo Bonzini 8795e5ced38SMarkus Armbruster static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) 8802362ecc5SCornelia Huck { 8812db26d4cSKONRAD Frederic VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev); 8822db26d4cSKONRAD Frederic DeviceState *vdev = DEVICE(&dev->vdev); 8835e5ced38SMarkus Armbruster Error *err = NULL; 8842362ecc5SCornelia Huck 8852db26d4cSKONRAD Frederic qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 8865e5ced38SMarkus Armbruster object_property_set_bool(OBJECT(vdev), true, "realized", &err); 8875e5ced38SMarkus Armbruster if (err) { 8885e5ced38SMarkus Armbruster error_propagate(errp, err); 8895e5ced38SMarkus Armbruster return; 8902362ecc5SCornelia Huck } 8912362ecc5SCornelia Huck 8922db26d4cSKONRAD Frederic object_property_set_link(OBJECT(dev), 8935b456438SCole Robinson OBJECT(dev->vdev.conf.rng), "rng", 8942db26d4cSKONRAD Frederic NULL); 8952362ecc5SCornelia Huck } 8962362ecc5SCornelia Huck 897*d2256070SHalil Pasic static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) 898*d2256070SHalil Pasic { 899*d2256070SHalil Pasic VirtIOCryptoCcw *dev = VIRTIO_CRYPTO_CCW(ccw_dev); 900*d2256070SHalil Pasic DeviceState *vdev = DEVICE(&dev->vdev); 901*d2256070SHalil Pasic Error *err = NULL; 902*d2256070SHalil Pasic 903*d2256070SHalil Pasic qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 904*d2256070SHalil Pasic object_property_set_bool(OBJECT(vdev), true, "realized", &err); 905*d2256070SHalil Pasic if (err) { 906*d2256070SHalil Pasic error_propagate(errp, err); 907*d2256070SHalil Pasic return; 908*d2256070SHalil Pasic } 909*d2256070SHalil Pasic 910*d2256070SHalil Pasic object_property_set_link(OBJECT(vdev), 911*d2256070SHalil Pasic OBJECT(dev->vdev.conf.cryptodev), "cryptodev", 912*d2256070SHalil Pasic NULL); 913*d2256070SHalil Pasic } 914*d2256070SHalil Pasic 915a5cf2bb4SCornelia Huck /* DeviceState to VirtioCcwDevice. Note: used on datapath, 916a5cf2bb4SCornelia Huck * be careful and test performance if you change this. 917a5cf2bb4SCornelia Huck */ 918a5cf2bb4SCornelia Huck static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) 919a5cf2bb4SCornelia Huck { 920b804e8a6SJing Liu CcwDevice *ccw_dev = to_ccw_dev_fast(d); 921b804e8a6SJing Liu 922b804e8a6SJing Liu return container_of(ccw_dev, VirtioCcwDevice, parent_obj); 923a5cf2bb4SCornelia Huck } 924a5cf2bb4SCornelia Huck 9257e749462SCornelia Huck static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, 9267e749462SCornelia Huck uint8_t to_be_set) 9277e749462SCornelia Huck { 9287e749462SCornelia Huck uint8_t ind_old, ind_new; 9297e749462SCornelia Huck hwaddr len = 1; 9307e749462SCornelia Huck uint8_t *ind_addr; 9317e749462SCornelia Huck 9327e749462SCornelia Huck ind_addr = cpu_physical_memory_map(ind_loc, &len, 1); 9337e749462SCornelia Huck if (!ind_addr) { 9347e749462SCornelia Huck error_report("%s(%x.%x.%04x): unable to access indicator", 9357e749462SCornelia Huck __func__, sch->cssid, sch->ssid, sch->schid); 9367e749462SCornelia Huck return -1; 9377e749462SCornelia Huck } 9387e749462SCornelia Huck do { 9397e749462SCornelia Huck ind_old = *ind_addr; 9407e749462SCornelia Huck ind_new = ind_old | to_be_set; 9417e749462SCornelia Huck } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); 94206409bd9SChristian Borntraeger trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new); 9437e749462SCornelia Huck cpu_physical_memory_unmap(ind_addr, len, 1, len); 9447e749462SCornelia Huck 9457e749462SCornelia Huck return ind_old; 9467e749462SCornelia Huck } 9477e749462SCornelia Huck 948a5cf2bb4SCornelia Huck static void virtio_ccw_notify(DeviceState *d, uint16_t vector) 949a5cf2bb4SCornelia Huck { 950a5cf2bb4SCornelia Huck VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d); 951b804e8a6SJing Liu CcwDevice *ccw_dev = to_ccw_dev_fast(d); 952b804e8a6SJing Liu SubchDev *sch = ccw_dev->sch; 953a5cf2bb4SCornelia Huck uint64_t indicators; 954a5cf2bb4SCornelia Huck 9551789f4e3SHalil Pasic /* queue indicators + secondary indicators */ 9561789f4e3SHalil Pasic if (vector >= VIRTIO_CCW_QUEUE_MAX + 64) { 957a5cf2bb4SCornelia Huck return; 958a5cf2bb4SCornelia Huck } 959a5cf2bb4SCornelia Huck 9608dfbaa6aSJason Wang if (vector < VIRTIO_CCW_QUEUE_MAX) { 9617c486976SCornelia Huck if (!dev->indicators) { 9627c486976SCornelia Huck return; 9637c486976SCornelia Huck } 9647e749462SCornelia Huck if (sch->thinint_active) { 9657e749462SCornelia Huck /* 9667e749462SCornelia Huck * In the adapter interrupt case, indicators points to a 9677e749462SCornelia Huck * memory area that may be (way) larger than 64 bit and 9687e749462SCornelia Huck * ind_bit indicates the start of the indicators in a big 9697e749462SCornelia Huck * endian notation. 9707e749462SCornelia Huck */ 971d426d9fbSCornelia Huck uint64_t ind_bit = dev->routes.adapter.ind_offset; 972d426d9fbSCornelia Huck 9737bca3892SCornelia Huck virtio_set_ind_atomic(sch, dev->indicators->addr + 974d426d9fbSCornelia Huck (ind_bit + vector) / 8, 975d426d9fbSCornelia Huck 0x80 >> ((ind_bit + vector) % 8)); 9767bca3892SCornelia Huck if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr, 9777e749462SCornelia Huck 0x01)) { 9787e749462SCornelia Huck css_adapter_interrupt(dev->thinint_isc); 9797e749462SCornelia Huck } 9807e749462SCornelia Huck } else { 98142874d3aSPeter Maydell indicators = address_space_ldq(&address_space_memory, 98242874d3aSPeter Maydell dev->indicators->addr, 98342874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 98442874d3aSPeter Maydell NULL); 98519380b1bSCornelia Huck indicators |= 1ULL << vector; 98642874d3aSPeter Maydell address_space_stq(&address_space_memory, dev->indicators->addr, 98742874d3aSPeter Maydell indicators, MEMTXATTRS_UNSPECIFIED, NULL); 9887e749462SCornelia Huck css_conditional_io_interrupt(sch); 9897e749462SCornelia Huck } 990a5cf2bb4SCornelia Huck } else { 9917c486976SCornelia Huck if (!dev->indicators2) { 9927c486976SCornelia Huck return; 9937c486976SCornelia Huck } 994a5cf2bb4SCornelia Huck vector = 0; 99542874d3aSPeter Maydell indicators = address_space_ldq(&address_space_memory, 99642874d3aSPeter Maydell dev->indicators2->addr, 99742874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, 99842874d3aSPeter Maydell NULL); 99919380b1bSCornelia Huck indicators |= 1ULL << vector; 100042874d3aSPeter Maydell address_space_stq(&address_space_memory, dev->indicators2->addr, 100142874d3aSPeter Maydell indicators, MEMTXATTRS_UNSPECIFIED, NULL); 1002a5cf2bb4SCornelia Huck css_conditional_io_interrupt(sch); 10037e749462SCornelia Huck } 1004a5cf2bb4SCornelia Huck } 1005a5cf2bb4SCornelia Huck 1006a5cf2bb4SCornelia Huck static void virtio_ccw_reset(DeviceState *d) 1007a5cf2bb4SCornelia Huck { 1008a5cf2bb4SCornelia Huck VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1009f24a6840SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1010b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(d); 1011a5cf2bb4SCornelia Huck 1012fa8b0ca5SCornelia Huck virtio_ccw_reset_virtio(dev, vdev); 1013b804e8a6SJing Liu css_reset_sch(ccw_dev->sch); 1014a5cf2bb4SCornelia Huck } 1015a5cf2bb4SCornelia Huck 1016b4436a0bSCornelia Huck static void virtio_ccw_vmstate_change(DeviceState *d, bool running) 1017b4436a0bSCornelia Huck { 1018b4436a0bSCornelia Huck VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1019b4436a0bSCornelia Huck 1020b4436a0bSCornelia Huck if (running) { 1021b4436a0bSCornelia Huck virtio_ccw_start_ioeventfd(dev); 1022b4436a0bSCornelia Huck } else { 1023b4436a0bSCornelia Huck virtio_ccw_stop_ioeventfd(dev); 1024b4436a0bSCornelia Huck } 1025b4436a0bSCornelia Huck } 1026b4436a0bSCornelia Huck 1027320ce850SCornelia Huck static bool virtio_ccw_query_guest_notifiers(DeviceState *d) 1028320ce850SCornelia Huck { 1029b804e8a6SJing Liu CcwDevice *dev = CCW_DEVICE(d); 1030320ce850SCornelia Huck 1031320ce850SCornelia Huck return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA); 1032320ce850SCornelia Huck } 1033320ce850SCornelia Huck 1034d426d9fbSCornelia Huck static int virtio_ccw_get_mappings(VirtioCcwDevice *dev) 1035d426d9fbSCornelia Huck { 1036d426d9fbSCornelia Huck int r; 1037b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(dev); 1038d426d9fbSCornelia Huck 1039b804e8a6SJing Liu if (!ccw_dev->sch->thinint_active) { 1040d426d9fbSCornelia Huck return -EINVAL; 1041d426d9fbSCornelia Huck } 1042d426d9fbSCornelia Huck 1043d426d9fbSCornelia Huck r = map_indicator(&dev->routes.adapter, dev->summary_indicator); 1044d426d9fbSCornelia Huck if (r) { 1045d426d9fbSCornelia Huck return r; 1046d426d9fbSCornelia Huck } 1047d426d9fbSCornelia Huck r = map_indicator(&dev->routes.adapter, dev->indicators); 1048d426d9fbSCornelia Huck if (r) { 1049d426d9fbSCornelia Huck return r; 1050d426d9fbSCornelia Huck } 1051d426d9fbSCornelia Huck dev->routes.adapter.summary_addr = dev->summary_indicator->map; 1052d426d9fbSCornelia Huck dev->routes.adapter.ind_addr = dev->indicators->map; 1053d426d9fbSCornelia Huck 1054d426d9fbSCornelia Huck return 0; 1055d426d9fbSCornelia Huck } 1056d426d9fbSCornelia Huck 1057d426d9fbSCornelia Huck static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs) 1058d426d9fbSCornelia Huck { 1059d426d9fbSCornelia Huck int i; 1060d426d9fbSCornelia Huck VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1061d426d9fbSCornelia Huck int ret; 1062d426d9fbSCornelia Huck S390FLICState *fs = s390_get_flic(); 1063d426d9fbSCornelia Huck S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); 1064d426d9fbSCornelia Huck 1065d426d9fbSCornelia Huck ret = virtio_ccw_get_mappings(dev); 1066d426d9fbSCornelia Huck if (ret) { 1067d426d9fbSCornelia Huck return ret; 1068d426d9fbSCornelia Huck } 1069d426d9fbSCornelia Huck for (i = 0; i < nvqs; i++) { 1070d426d9fbSCornelia Huck if (!virtio_queue_get_num(vdev, i)) { 1071d426d9fbSCornelia Huck break; 1072d426d9fbSCornelia Huck } 1073d426d9fbSCornelia Huck } 1074d426d9fbSCornelia Huck dev->routes.num_routes = i; 1075d426d9fbSCornelia Huck return fsc->add_adapter_routes(fs, &dev->routes); 1076d426d9fbSCornelia Huck } 1077d426d9fbSCornelia Huck 1078d426d9fbSCornelia Huck static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs) 1079d426d9fbSCornelia Huck { 1080d426d9fbSCornelia Huck S390FLICState *fs = s390_get_flic(); 1081d426d9fbSCornelia Huck S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); 1082d426d9fbSCornelia Huck 1083d426d9fbSCornelia Huck fsc->release_adapter_routes(fs, &dev->routes); 1084d426d9fbSCornelia Huck } 1085d426d9fbSCornelia Huck 1086d426d9fbSCornelia Huck static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n) 1087d426d9fbSCornelia Huck { 1088d426d9fbSCornelia Huck VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1089d426d9fbSCornelia Huck VirtQueue *vq = virtio_get_queue(vdev, n); 1090d426d9fbSCornelia Huck EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); 1091d426d9fbSCornelia Huck 10921c9b71a7SEric Auger return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, notifier, NULL, 1093d426d9fbSCornelia Huck dev->routes.gsi[n]); 1094d426d9fbSCornelia Huck } 1095d426d9fbSCornelia Huck 1096d426d9fbSCornelia Huck static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n) 1097d426d9fbSCornelia Huck { 1098d426d9fbSCornelia Huck VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1099d426d9fbSCornelia Huck VirtQueue *vq = virtio_get_queue(vdev, n); 1100d426d9fbSCornelia Huck EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); 1101d426d9fbSCornelia Huck int ret; 1102d426d9fbSCornelia Huck 11031c9b71a7SEric Auger ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, notifier, 1104d426d9fbSCornelia Huck dev->routes.gsi[n]); 1105d426d9fbSCornelia Huck assert(ret == 0); 1106d426d9fbSCornelia Huck } 1107d426d9fbSCornelia Huck 1108320ce850SCornelia Huck static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, 1109320ce850SCornelia Huck bool assign, bool with_irqfd) 1110320ce850SCornelia Huck { 1111f24a6840SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1112f24a6840SPaolo Bonzini VirtQueue *vq = virtio_get_queue(vdev, n); 1113320ce850SCornelia Huck EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); 1114f24a6840SPaolo Bonzini VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); 1115320ce850SCornelia Huck 1116320ce850SCornelia Huck if (assign) { 1117320ce850SCornelia Huck int r = event_notifier_init(notifier, 0); 1118320ce850SCornelia Huck 1119320ce850SCornelia Huck if (r < 0) { 1120320ce850SCornelia Huck return r; 1121320ce850SCornelia Huck } 1122320ce850SCornelia Huck virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); 1123d426d9fbSCornelia Huck if (with_irqfd) { 1124d426d9fbSCornelia Huck r = virtio_ccw_add_irqfd(dev, n); 1125d426d9fbSCornelia Huck if (r) { 1126d426d9fbSCornelia Huck virtio_queue_set_guest_notifier_fd_handler(vq, false, 1127d426d9fbSCornelia Huck with_irqfd); 1128d426d9fbSCornelia Huck return r; 1129d426d9fbSCornelia Huck } 1130d426d9fbSCornelia Huck } 1131d426d9fbSCornelia Huck /* 1132d426d9fbSCornelia Huck * We do not support individual masking for channel devices, so we 1133d426d9fbSCornelia Huck * need to manually trigger any guest masking callbacks here. 1134320ce850SCornelia Huck */ 11352858bc68SWei Huang if (k->guest_notifier_mask && vdev->use_guest_notifier_mask) { 1136f24a6840SPaolo Bonzini k->guest_notifier_mask(vdev, n, false); 1137320ce850SCornelia Huck } 1138320ce850SCornelia Huck /* get lost events and re-inject */ 1139320ce850SCornelia Huck if (k->guest_notifier_pending && 1140f24a6840SPaolo Bonzini k->guest_notifier_pending(vdev, n)) { 1141320ce850SCornelia Huck event_notifier_set(notifier); 1142320ce850SCornelia Huck } 1143320ce850SCornelia Huck } else { 11442858bc68SWei Huang if (k->guest_notifier_mask && vdev->use_guest_notifier_mask) { 1145f24a6840SPaolo Bonzini k->guest_notifier_mask(vdev, n, true); 1146320ce850SCornelia Huck } 1147d426d9fbSCornelia Huck if (with_irqfd) { 1148d426d9fbSCornelia Huck virtio_ccw_remove_irqfd(dev, n); 1149d426d9fbSCornelia Huck } 1150320ce850SCornelia Huck virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); 1151320ce850SCornelia Huck event_notifier_cleanup(notifier); 1152320ce850SCornelia Huck } 1153320ce850SCornelia Huck return 0; 1154320ce850SCornelia Huck } 1155320ce850SCornelia Huck 1156320ce850SCornelia Huck static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, 1157320ce850SCornelia Huck bool assigned) 1158320ce850SCornelia Huck { 1159320ce850SCornelia Huck VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1160f24a6840SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1161b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(d); 1162b804e8a6SJing Liu bool with_irqfd = ccw_dev->sch->thinint_active && kvm_irqfds_enabled(); 1163320ce850SCornelia Huck int r, n; 1164320ce850SCornelia Huck 1165d426d9fbSCornelia Huck if (with_irqfd && assigned) { 1166d426d9fbSCornelia Huck /* irq routes need to be set up before assigning irqfds */ 1167d426d9fbSCornelia Huck r = virtio_ccw_setup_irqroutes(dev, nvqs); 1168d426d9fbSCornelia Huck if (r < 0) { 1169d426d9fbSCornelia Huck goto irqroute_error; 1170d426d9fbSCornelia Huck } 1171d426d9fbSCornelia Huck } 1172320ce850SCornelia Huck for (n = 0; n < nvqs; n++) { 1173320ce850SCornelia Huck if (!virtio_queue_get_num(vdev, n)) { 1174320ce850SCornelia Huck break; 1175320ce850SCornelia Huck } 1176d426d9fbSCornelia Huck r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd); 1177320ce850SCornelia Huck if (r < 0) { 1178320ce850SCornelia Huck goto assign_error; 1179320ce850SCornelia Huck } 1180320ce850SCornelia Huck } 1181d426d9fbSCornelia Huck if (with_irqfd && !assigned) { 1182d426d9fbSCornelia Huck /* release irq routes after irqfds have been released */ 1183d426d9fbSCornelia Huck virtio_ccw_release_irqroutes(dev, nvqs); 1184d426d9fbSCornelia Huck } 1185320ce850SCornelia Huck return 0; 1186320ce850SCornelia Huck 1187320ce850SCornelia Huck assign_error: 1188320ce850SCornelia Huck while (--n >= 0) { 1189320ce850SCornelia Huck virtio_ccw_set_guest_notifier(dev, n, !assigned, false); 1190320ce850SCornelia Huck } 1191d426d9fbSCornelia Huck irqroute_error: 1192d426d9fbSCornelia Huck if (with_irqfd && assigned) { 1193d426d9fbSCornelia Huck virtio_ccw_release_irqroutes(dev, nvqs); 1194d426d9fbSCornelia Huck } 1195320ce850SCornelia Huck return r; 1196320ce850SCornelia Huck } 1197320ce850SCornelia Huck 1198bcb2b582SJens Freimann static void virtio_ccw_save_queue(DeviceState *d, int n, QEMUFile *f) 1199bcb2b582SJens Freimann { 1200bcb2b582SJens Freimann VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1201bcb2b582SJens Freimann VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1202bcb2b582SJens Freimann 1203bcb2b582SJens Freimann qemu_put_be16(f, virtio_queue_vector(vdev, n)); 1204bcb2b582SJens Freimann } 1205bcb2b582SJens Freimann 1206bcb2b582SJens Freimann static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f) 1207bcb2b582SJens Freimann { 1208bcb2b582SJens Freimann VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1209bcb2b582SJens Freimann VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1210bcb2b582SJens Freimann uint16_t vector; 1211bcb2b582SJens Freimann 1212bcb2b582SJens Freimann qemu_get_be16s(f, &vector); 1213bcb2b582SJens Freimann virtio_queue_set_vector(vdev, n , vector); 1214bcb2b582SJens Freimann 1215bcb2b582SJens Freimann return 0; 1216bcb2b582SJens Freimann } 1217bcb2b582SJens Freimann 1218bcb2b582SJens Freimann static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f) 1219bcb2b582SJens Freimann { 1220bcb2b582SJens Freimann VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1221b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(d); 1222b804e8a6SJing Liu SubchDev *s = ccw_dev->sch; 12232a72ea5fSJason J. Herne VirtIODevice *vdev = virtio_ccw_get_vdev(s); 1224bcb2b582SJens Freimann 1225bcb2b582SJens Freimann subch_device_save(s, f); 1226bcb2b582SJens Freimann if (dev->indicators != NULL) { 1227bcb2b582SJens Freimann qemu_put_be32(f, dev->indicators->len); 1228bcb2b582SJens Freimann qemu_put_be64(f, dev->indicators->addr); 1229bcb2b582SJens Freimann } else { 1230bcb2b582SJens Freimann qemu_put_be32(f, 0); 1231bcb2b582SJens Freimann qemu_put_be64(f, 0UL); 1232bcb2b582SJens Freimann } 1233bcb2b582SJens Freimann if (dev->indicators2 != NULL) { 1234bcb2b582SJens Freimann qemu_put_be32(f, dev->indicators2->len); 1235bcb2b582SJens Freimann qemu_put_be64(f, dev->indicators2->addr); 1236bcb2b582SJens Freimann } else { 1237bcb2b582SJens Freimann qemu_put_be32(f, 0); 1238bcb2b582SJens Freimann qemu_put_be64(f, 0UL); 1239bcb2b582SJens Freimann } 1240bcb2b582SJens Freimann if (dev->summary_indicator != NULL) { 1241bcb2b582SJens Freimann qemu_put_be32(f, dev->summary_indicator->len); 1242bcb2b582SJens Freimann qemu_put_be64(f, dev->summary_indicator->addr); 1243bcb2b582SJens Freimann } else { 1244bcb2b582SJens Freimann qemu_put_be32(f, 0); 1245bcb2b582SJens Freimann qemu_put_be64(f, 0UL); 1246bcb2b582SJens Freimann } 12472a72ea5fSJason J. Herne qemu_put_be16(f, vdev->config_vector); 1248bcb2b582SJens Freimann qemu_put_be64(f, dev->routes.adapter.ind_offset); 1249bcb2b582SJens Freimann qemu_put_byte(f, dev->thinint_isc); 1250213941d7SCornelia Huck qemu_put_be32(f, dev->revision); 1251bcb2b582SJens Freimann } 1252bcb2b582SJens Freimann 1253bcb2b582SJens Freimann static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) 1254bcb2b582SJens Freimann { 1255bcb2b582SJens Freimann VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1256b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(d); 1257b804e8a6SJing Liu SubchDev *s = ccw_dev->sch; 12582a72ea5fSJason J. Herne VirtIODevice *vdev = virtio_ccw_get_vdev(s); 1259bcb2b582SJens Freimann int len; 1260bcb2b582SJens Freimann 1261bcb2b582SJens Freimann s->driver_data = dev; 1262bcb2b582SJens Freimann subch_device_load(s, f); 1263bcb2b582SJens Freimann len = qemu_get_be32(f); 1264bcb2b582SJens Freimann if (len != 0) { 1265bcb2b582SJens Freimann dev->indicators = get_indicator(qemu_get_be64(f), len); 1266bcb2b582SJens Freimann } else { 1267bcb2b582SJens Freimann qemu_get_be64(f); 1268bcb2b582SJens Freimann dev->indicators = NULL; 1269bcb2b582SJens Freimann } 1270bcb2b582SJens Freimann len = qemu_get_be32(f); 1271bcb2b582SJens Freimann if (len != 0) { 1272bcb2b582SJens Freimann dev->indicators2 = get_indicator(qemu_get_be64(f), len); 1273bcb2b582SJens Freimann } else { 1274bcb2b582SJens Freimann qemu_get_be64(f); 1275bcb2b582SJens Freimann dev->indicators2 = NULL; 1276bcb2b582SJens Freimann } 1277bcb2b582SJens Freimann len = qemu_get_be32(f); 1278bcb2b582SJens Freimann if (len != 0) { 1279bcb2b582SJens Freimann dev->summary_indicator = get_indicator(qemu_get_be64(f), len); 1280bcb2b582SJens Freimann } else { 1281bcb2b582SJens Freimann qemu_get_be64(f); 1282bcb2b582SJens Freimann dev->summary_indicator = NULL; 1283bcb2b582SJens Freimann } 12842a72ea5fSJason J. Herne qemu_get_be16s(f, &vdev->config_vector); 1285bcb2b582SJens Freimann dev->routes.adapter.ind_offset = qemu_get_be64(f); 1286bcb2b582SJens Freimann dev->thinint_isc = qemu_get_byte(f); 12872af9170cSChristian Borntraeger dev->revision = qemu_get_be32(f); 1288bcb2b582SJens Freimann if (s->thinint_active) { 1289bcb2b582SJens Freimann return css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO, 1290bcb2b582SJens Freimann dev->thinint_isc, true, false, 1291bcb2b582SJens Freimann &dev->routes.adapter.adapter_id); 1292bcb2b582SJens Freimann } 1293bcb2b582SJens Freimann 1294bcb2b582SJens Freimann return 0; 1295bcb2b582SJens Freimann } 1296bcb2b582SJens Freimann 1297d1b4259fSMaxime Coquelin static void virtio_ccw_pre_plugged(DeviceState *d, Error **errp) 1298d1b4259fSMaxime Coquelin { 1299d1b4259fSMaxime Coquelin VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1300d1b4259fSMaxime Coquelin VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1301d1b4259fSMaxime Coquelin 1302d1b4259fSMaxime Coquelin if (dev->max_rev >= 1) { 1303d1b4259fSMaxime Coquelin virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); 1304d1b4259fSMaxime Coquelin } 1305d1b4259fSMaxime Coquelin } 1306d1b4259fSMaxime Coquelin 1307fb846a09SCornelia Huck /* This is called by virtio-bus just after the device is plugged. */ 1308e8398045SJason Wang static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) 1309fb846a09SCornelia Huck { 1310fb846a09SCornelia Huck VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 131110ceaa1eSJason Wang VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); 1312b804e8a6SJing Liu CcwDevice *ccw_dev = CCW_DEVICE(d); 1313b804e8a6SJing Liu SubchDev *sch = ccw_dev->sch; 131410ceaa1eSJason Wang int n = virtio_get_num_queues(vdev); 131510ceaa1eSJason Wang 1316d1b4259fSMaxime Coquelin if (!virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) { 1317d1b4259fSMaxime Coquelin dev->max_rev = 0; 1318d1b4259fSMaxime Coquelin } 1319d1b4259fSMaxime Coquelin 132010ceaa1eSJason Wang if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) { 1321b34aee54SMichael Tokarev error_setg(errp, "The number of virtqueues %d " 132210ceaa1eSJason Wang "exceeds ccw limit %d", n, 132310ceaa1eSJason Wang VIRTIO_CCW_QUEUE_MAX); 132410ceaa1eSJason Wang return; 132510ceaa1eSJason Wang } 1326fb846a09SCornelia Huck 1327fb846a09SCornelia Huck sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus); 1328fb846a09SCornelia Huck 1329542571d5SCornelia Huck 1330fb846a09SCornelia Huck css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1331fb846a09SCornelia Huck d->hotplugged, 1); 1332fb846a09SCornelia Huck } 1333fb846a09SCornelia Huck 1334fb846a09SCornelia Huck static void virtio_ccw_device_unplugged(DeviceState *d) 1335fb846a09SCornelia Huck { 1336fb846a09SCornelia Huck VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); 1337fb846a09SCornelia Huck 1338fb846a09SCornelia Huck virtio_ccw_stop_ioeventfd(dev); 1339fb846a09SCornelia Huck } 1340a5cf2bb4SCornelia Huck /**************** Virtio-ccw Bus Device Descriptions *******************/ 1341a5cf2bb4SCornelia Huck 1342a5cf2bb4SCornelia Huck static Property virtio_ccw_net_properties[] = { 1343b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1344b4436a0bSCornelia Huck DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1345b4436a0bSCornelia Huck VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1346542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1347542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 1348a5cf2bb4SCornelia Huck DEFINE_PROP_END_OF_LIST(), 1349a5cf2bb4SCornelia Huck }; 1350a5cf2bb4SCornelia Huck 1351a5cf2bb4SCornelia Huck static void virtio_ccw_net_class_init(ObjectClass *klass, void *data) 1352a5cf2bb4SCornelia Huck { 1353a5cf2bb4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(klass); 1354a5cf2bb4SCornelia Huck VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1355a5cf2bb4SCornelia Huck 13565e5ced38SMarkus Armbruster k->realize = virtio_ccw_net_realize; 135789334c8bSKONRAD Frederic k->exit = virtio_ccw_exit; 1358a5cf2bb4SCornelia Huck dc->reset = virtio_ccw_reset; 1359a5cf2bb4SCornelia Huck dc->props = virtio_ccw_net_properties; 1360cd20d616SCornelia Huck set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 1361a5cf2bb4SCornelia Huck } 1362a5cf2bb4SCornelia Huck 1363a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_net = { 136489334c8bSKONRAD Frederic .name = TYPE_VIRTIO_NET_CCW, 1365a5cf2bb4SCornelia Huck .parent = TYPE_VIRTIO_CCW_DEVICE, 136689334c8bSKONRAD Frederic .instance_size = sizeof(VirtIONetCcw), 136789334c8bSKONRAD Frederic .instance_init = virtio_ccw_net_instance_init, 1368a5cf2bb4SCornelia Huck .class_init = virtio_ccw_net_class_init, 1369a5cf2bb4SCornelia Huck }; 1370a5cf2bb4SCornelia Huck 1371a5cf2bb4SCornelia Huck static Property virtio_ccw_blk_properties[] = { 1372b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1373b4436a0bSCornelia Huck DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1374b4436a0bSCornelia Huck VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1375542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1376542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 1377a5cf2bb4SCornelia Huck DEFINE_PROP_END_OF_LIST(), 1378a5cf2bb4SCornelia Huck }; 1379a5cf2bb4SCornelia Huck 1380a5cf2bb4SCornelia Huck static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data) 1381a5cf2bb4SCornelia Huck { 1382a5cf2bb4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(klass); 1383a5cf2bb4SCornelia Huck VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1384a5cf2bb4SCornelia Huck 13855e5ced38SMarkus Armbruster k->realize = virtio_ccw_blk_realize; 13863400c455SKONRAD Frederic k->exit = virtio_ccw_exit; 1387a5cf2bb4SCornelia Huck dc->reset = virtio_ccw_reset; 1388a5cf2bb4SCornelia Huck dc->props = virtio_ccw_blk_properties; 1389cd20d616SCornelia Huck set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1390a5cf2bb4SCornelia Huck } 1391a5cf2bb4SCornelia Huck 1392a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_blk = { 13933400c455SKONRAD Frederic .name = TYPE_VIRTIO_BLK_CCW, 1394a5cf2bb4SCornelia Huck .parent = TYPE_VIRTIO_CCW_DEVICE, 13953400c455SKONRAD Frederic .instance_size = sizeof(VirtIOBlkCcw), 13963400c455SKONRAD Frederic .instance_init = virtio_ccw_blk_instance_init, 1397a5cf2bb4SCornelia Huck .class_init = virtio_ccw_blk_class_init, 1398a5cf2bb4SCornelia Huck }; 1399a5cf2bb4SCornelia Huck 1400a5cf2bb4SCornelia Huck static Property virtio_ccw_serial_properties[] = { 1401b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1402b4436a0bSCornelia Huck DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1403b4436a0bSCornelia Huck VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1404542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1405542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 1406a5cf2bb4SCornelia Huck DEFINE_PROP_END_OF_LIST(), 1407a5cf2bb4SCornelia Huck }; 1408a5cf2bb4SCornelia Huck 1409a5cf2bb4SCornelia Huck static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data) 1410a5cf2bb4SCornelia Huck { 1411a5cf2bb4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(klass); 1412a5cf2bb4SCornelia Huck VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1413a5cf2bb4SCornelia Huck 14145e5ced38SMarkus Armbruster k->realize = virtio_ccw_serial_realize; 14156acf69cdSKONRAD Frederic k->exit = virtio_ccw_exit; 1416a5cf2bb4SCornelia Huck dc->reset = virtio_ccw_reset; 1417a5cf2bb4SCornelia Huck dc->props = virtio_ccw_serial_properties; 1418cd20d616SCornelia Huck set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 1419a5cf2bb4SCornelia Huck } 1420a5cf2bb4SCornelia Huck 1421a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_serial = { 14226acf69cdSKONRAD Frederic .name = TYPE_VIRTIO_SERIAL_CCW, 1423a5cf2bb4SCornelia Huck .parent = TYPE_VIRTIO_CCW_DEVICE, 14246acf69cdSKONRAD Frederic .instance_size = sizeof(VirtioSerialCcw), 14256acf69cdSKONRAD Frederic .instance_init = virtio_ccw_serial_instance_init, 1426a5cf2bb4SCornelia Huck .class_init = virtio_ccw_serial_class_init, 1427a5cf2bb4SCornelia Huck }; 1428a5cf2bb4SCornelia Huck 1429a5cf2bb4SCornelia Huck static Property virtio_ccw_balloon_properties[] = { 1430b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1431b4436a0bSCornelia Huck DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1432b4436a0bSCornelia Huck VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1433542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1434542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 1435a5cf2bb4SCornelia Huck DEFINE_PROP_END_OF_LIST(), 1436a5cf2bb4SCornelia Huck }; 1437a5cf2bb4SCornelia Huck 1438a5cf2bb4SCornelia Huck static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data) 1439a5cf2bb4SCornelia Huck { 1440a5cf2bb4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(klass); 1441a5cf2bb4SCornelia Huck VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1442a5cf2bb4SCornelia Huck 14435e5ced38SMarkus Armbruster k->realize = virtio_ccw_balloon_realize; 144430bff6a0SKONRAD Frederic k->exit = virtio_ccw_exit; 1445a5cf2bb4SCornelia Huck dc->reset = virtio_ccw_reset; 1446a5cf2bb4SCornelia Huck dc->props = virtio_ccw_balloon_properties; 1447cd20d616SCornelia Huck set_bit(DEVICE_CATEGORY_MISC, dc->categories); 1448a5cf2bb4SCornelia Huck } 1449a5cf2bb4SCornelia Huck 1450a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_balloon = { 145130bff6a0SKONRAD Frederic .name = TYPE_VIRTIO_BALLOON_CCW, 1452a5cf2bb4SCornelia Huck .parent = TYPE_VIRTIO_CCW_DEVICE, 145330bff6a0SKONRAD Frederic .instance_size = sizeof(VirtIOBalloonCcw), 145430bff6a0SKONRAD Frederic .instance_init = virtio_ccw_balloon_instance_init, 1455a5cf2bb4SCornelia Huck .class_init = virtio_ccw_balloon_class_init, 1456a5cf2bb4SCornelia Huck }; 1457a5cf2bb4SCornelia Huck 1458a5cf2bb4SCornelia Huck static Property virtio_ccw_scsi_properties[] = { 1459b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1460b4436a0bSCornelia Huck DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1461b4436a0bSCornelia Huck VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1462542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1463542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 1464a5cf2bb4SCornelia Huck DEFINE_PROP_END_OF_LIST(), 1465a5cf2bb4SCornelia Huck }; 1466a5cf2bb4SCornelia Huck 1467a5cf2bb4SCornelia Huck static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data) 1468a5cf2bb4SCornelia Huck { 1469a5cf2bb4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(klass); 1470a5cf2bb4SCornelia Huck VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1471a5cf2bb4SCornelia Huck 14725e5ced38SMarkus Armbruster k->realize = virtio_ccw_scsi_realize; 1473c908ea10SKONRAD Frederic k->exit = virtio_ccw_exit; 1474a5cf2bb4SCornelia Huck dc->reset = virtio_ccw_reset; 1475a5cf2bb4SCornelia Huck dc->props = virtio_ccw_scsi_properties; 1476cd20d616SCornelia Huck set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1477a5cf2bb4SCornelia Huck } 1478a5cf2bb4SCornelia Huck 1479a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_scsi = { 1480c908ea10SKONRAD Frederic .name = TYPE_VIRTIO_SCSI_CCW, 1481a5cf2bb4SCornelia Huck .parent = TYPE_VIRTIO_CCW_DEVICE, 1482c908ea10SKONRAD Frederic .instance_size = sizeof(VirtIOSCSICcw), 1483c908ea10SKONRAD Frederic .instance_init = virtio_ccw_scsi_instance_init, 1484a5cf2bb4SCornelia Huck .class_init = virtio_ccw_scsi_class_init, 1485a5cf2bb4SCornelia Huck }; 1486a5cf2bb4SCornelia Huck 1487ccf6916cSPaolo Bonzini #ifdef CONFIG_VHOST_SCSI 1488ccf6916cSPaolo Bonzini static Property vhost_ccw_scsi_properties[] = { 1489b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1490542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1491542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 1492ccf6916cSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 1493ccf6916cSPaolo Bonzini }; 1494ccf6916cSPaolo Bonzini 1495ccf6916cSPaolo Bonzini static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data) 1496ccf6916cSPaolo Bonzini { 1497ccf6916cSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 1498ccf6916cSPaolo Bonzini VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1499ccf6916cSPaolo Bonzini 15005e5ced38SMarkus Armbruster k->realize = vhost_ccw_scsi_realize; 1501ccf6916cSPaolo Bonzini k->exit = virtio_ccw_exit; 1502ccf6916cSPaolo Bonzini dc->reset = virtio_ccw_reset; 1503ccf6916cSPaolo Bonzini dc->props = vhost_ccw_scsi_properties; 1504cd20d616SCornelia Huck set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1505ccf6916cSPaolo Bonzini } 1506ccf6916cSPaolo Bonzini 1507ccf6916cSPaolo Bonzini static const TypeInfo vhost_ccw_scsi = { 1508ccf6916cSPaolo Bonzini .name = TYPE_VHOST_SCSI_CCW, 1509ccf6916cSPaolo Bonzini .parent = TYPE_VIRTIO_CCW_DEVICE, 15104b7757baSCornelia Huck .instance_size = sizeof(VHostSCSICcw), 1511ccf6916cSPaolo Bonzini .instance_init = vhost_ccw_scsi_instance_init, 1512ccf6916cSPaolo Bonzini .class_init = vhost_ccw_scsi_class_init, 1513ccf6916cSPaolo Bonzini }; 1514ccf6916cSPaolo Bonzini #endif 1515ccf6916cSPaolo Bonzini 15162db26d4cSKONRAD Frederic static void virtio_ccw_rng_instance_init(Object *obj) 15172362ecc5SCornelia Huck { 15182db26d4cSKONRAD Frederic VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj); 1519c8075cafSGonglei 1520c8075cafSGonglei virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 1521c8075cafSGonglei TYPE_VIRTIO_RNG); 1522cbd5ac69SPaolo Bonzini object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), 1523cbd5ac69SPaolo Bonzini "rng", &error_abort); 15242362ecc5SCornelia Huck } 15252362ecc5SCornelia Huck 15262362ecc5SCornelia Huck static Property virtio_ccw_rng_properties[] = { 1527b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1528b4436a0bSCornelia Huck DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1529b4436a0bSCornelia Huck VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1530542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1531542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 15322362ecc5SCornelia Huck DEFINE_PROP_END_OF_LIST(), 15332362ecc5SCornelia Huck }; 15342362ecc5SCornelia Huck 15352362ecc5SCornelia Huck static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data) 15362362ecc5SCornelia Huck { 15372362ecc5SCornelia Huck DeviceClass *dc = DEVICE_CLASS(klass); 15382362ecc5SCornelia Huck VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 15392362ecc5SCornelia Huck 15405e5ced38SMarkus Armbruster k->realize = virtio_ccw_rng_realize; 15412db26d4cSKONRAD Frederic k->exit = virtio_ccw_exit; 15422362ecc5SCornelia Huck dc->reset = virtio_ccw_reset; 15432362ecc5SCornelia Huck dc->props = virtio_ccw_rng_properties; 1544cd20d616SCornelia Huck set_bit(DEVICE_CATEGORY_MISC, dc->categories); 15452362ecc5SCornelia Huck } 15462362ecc5SCornelia Huck 15472362ecc5SCornelia Huck static const TypeInfo virtio_ccw_rng = { 15482db26d4cSKONRAD Frederic .name = TYPE_VIRTIO_RNG_CCW, 15492362ecc5SCornelia Huck .parent = TYPE_VIRTIO_CCW_DEVICE, 15502db26d4cSKONRAD Frederic .instance_size = sizeof(VirtIORNGCcw), 15512db26d4cSKONRAD Frederic .instance_init = virtio_ccw_rng_instance_init, 15522362ecc5SCornelia Huck .class_init = virtio_ccw_rng_class_init, 15532362ecc5SCornelia Huck }; 15542362ecc5SCornelia Huck 1555*d2256070SHalil Pasic static Property virtio_ccw_crypto_properties[] = { 1556*d2256070SHalil Pasic DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1557*d2256070SHalil Pasic DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1558*d2256070SHalil Pasic VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1559*d2256070SHalil Pasic DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1560*d2256070SHalil Pasic VIRTIO_CCW_MAX_REV), 1561*d2256070SHalil Pasic DEFINE_PROP_END_OF_LIST(), 1562*d2256070SHalil Pasic }; 1563*d2256070SHalil Pasic 1564*d2256070SHalil Pasic static void virtio_ccw_crypto_instance_init(Object *obj) 1565*d2256070SHalil Pasic { 1566*d2256070SHalil Pasic VirtIOCryptoCcw *dev = VIRTIO_CRYPTO_CCW(obj); 1567*d2256070SHalil Pasic VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj); 1568*d2256070SHalil Pasic 1569*d2256070SHalil Pasic ccw_dev->force_revision_1 = true; 1570*d2256070SHalil Pasic virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 1571*d2256070SHalil Pasic TYPE_VIRTIO_CRYPTO); 1572*d2256070SHalil Pasic 1573*d2256070SHalil Pasic object_property_add_alias(obj, "cryptodev", OBJECT(&dev->vdev), 1574*d2256070SHalil Pasic "cryptodev", &error_abort); 1575*d2256070SHalil Pasic } 1576*d2256070SHalil Pasic 1577*d2256070SHalil Pasic static void virtio_ccw_crypto_class_init(ObjectClass *klass, void *data) 1578*d2256070SHalil Pasic { 1579*d2256070SHalil Pasic DeviceClass *dc = DEVICE_CLASS(klass); 1580*d2256070SHalil Pasic VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1581*d2256070SHalil Pasic 1582*d2256070SHalil Pasic k->realize = virtio_ccw_crypto_realize; 1583*d2256070SHalil Pasic k->exit = virtio_ccw_exit; 1584*d2256070SHalil Pasic dc->reset = virtio_ccw_reset; 1585*d2256070SHalil Pasic dc->props = virtio_ccw_crypto_properties; 1586*d2256070SHalil Pasic set_bit(DEVICE_CATEGORY_MISC, dc->categories); 1587*d2256070SHalil Pasic } 1588*d2256070SHalil Pasic 1589*d2256070SHalil Pasic static const TypeInfo virtio_ccw_crypto = { 1590*d2256070SHalil Pasic .name = TYPE_VIRTIO_CRYPTO_CCW, 1591*d2256070SHalil Pasic .parent = TYPE_VIRTIO_CCW_DEVICE, 1592*d2256070SHalil Pasic .instance_size = sizeof(VirtIOCryptoCcw), 1593*d2256070SHalil Pasic .instance_init = virtio_ccw_crypto_instance_init, 1594*d2256070SHalil Pasic .class_init = virtio_ccw_crypto_class_init, 1595*d2256070SHalil Pasic }; 1596*d2256070SHalil Pasic 15975e5ced38SMarkus Armbruster static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp) 1598a5cf2bb4SCornelia Huck { 1599a5cf2bb4SCornelia Huck VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; 1600a5cf2bb4SCornelia Huck 16011bf4d7aaSAndreas Färber virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev); 16021fa75523SCornelia Huck virtio_ccw_device_realize(_dev, errp); 1603a5cf2bb4SCornelia Huck } 1604a5cf2bb4SCornelia Huck 1605a5cf2bb4SCornelia Huck static int virtio_ccw_busdev_exit(DeviceState *dev) 1606a5cf2bb4SCornelia Huck { 1607a5cf2bb4SCornelia Huck VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; 1608a5cf2bb4SCornelia Huck VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev); 1609a5cf2bb4SCornelia Huck 1610a5cf2bb4SCornelia Huck return _info->exit(_dev); 1611a5cf2bb4SCornelia Huck } 1612a5cf2bb4SCornelia Huck 1613b804e8a6SJing Liu static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev, 1614277bc95eSIgor Mammedov DeviceState *dev, Error **errp) 1615a5cf2bb4SCornelia Huck { 1616b804e8a6SJing Liu VirtioCcwDevice *_dev = to_virtio_ccw_dev_fast(dev); 1617a5cf2bb4SCornelia Huck 16180b81c1efSPaolo Bonzini virtio_ccw_stop_ioeventfd(_dev); 1619a5cf2bb4SCornelia Huck } 1620a5cf2bb4SCornelia Huck 1621a5cf2bb4SCornelia Huck static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) 1622a5cf2bb4SCornelia Huck { 1623a5cf2bb4SCornelia Huck DeviceClass *dc = DEVICE_CLASS(klass); 1624b804e8a6SJing Liu CCWDeviceClass *k = CCW_DEVICE_CLASS(dc); 1625a5cf2bb4SCornelia Huck 1626b804e8a6SJing Liu k->unplug = virtio_ccw_busdev_unplug; 16275e5ced38SMarkus Armbruster dc->realize = virtio_ccw_busdev_realize; 1628a5cf2bb4SCornelia Huck dc->exit = virtio_ccw_busdev_exit; 1629a5cf2bb4SCornelia Huck dc->bus_type = TYPE_VIRTUAL_CSS_BUS; 1630a5cf2bb4SCornelia Huck } 1631a5cf2bb4SCornelia Huck 1632a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_device_info = { 1633a5cf2bb4SCornelia Huck .name = TYPE_VIRTIO_CCW_DEVICE, 1634b804e8a6SJing Liu .parent = TYPE_CCW_DEVICE, 1635a5cf2bb4SCornelia Huck .instance_size = sizeof(VirtioCcwDevice), 1636a5cf2bb4SCornelia Huck .class_init = virtio_ccw_device_class_init, 1637a5cf2bb4SCornelia Huck .class_size = sizeof(VirtIOCCWDeviceClass), 1638a5cf2bb4SCornelia Huck .abstract = true, 1639a5cf2bb4SCornelia Huck }; 1640a5cf2bb4SCornelia Huck 1641a5cf2bb4SCornelia Huck /* virtio-ccw-bus */ 1642a5cf2bb4SCornelia Huck 16431bf4d7aaSAndreas Färber static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, 16441bf4d7aaSAndreas Färber VirtioCcwDevice *dev) 1645a5cf2bb4SCornelia Huck { 1646a5cf2bb4SCornelia Huck DeviceState *qdev = DEVICE(dev); 1647f4dd69aaSKONRAD Frederic char virtio_bus_name[] = "virtio-bus"; 1648a5cf2bb4SCornelia Huck 1649fb17dfe0SAndreas Färber qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS, 1650fb17dfe0SAndreas Färber qdev, virtio_bus_name); 1651a5cf2bb4SCornelia Huck } 1652a5cf2bb4SCornelia Huck 1653a5cf2bb4SCornelia Huck static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) 1654a5cf2bb4SCornelia Huck { 1655a5cf2bb4SCornelia Huck VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); 1656a5cf2bb4SCornelia Huck BusClass *bus_class = BUS_CLASS(klass); 1657a5cf2bb4SCornelia Huck 1658a5cf2bb4SCornelia Huck bus_class->max_dev = 1; 1659a5cf2bb4SCornelia Huck k->notify = virtio_ccw_notify; 1660b4436a0bSCornelia Huck k->vmstate_change = virtio_ccw_vmstate_change; 1661320ce850SCornelia Huck k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; 1662320ce850SCornelia Huck k->set_guest_notifiers = virtio_ccw_set_guest_notifiers; 1663bcb2b582SJens Freimann k->save_queue = virtio_ccw_save_queue; 1664bcb2b582SJens Freimann k->load_queue = virtio_ccw_load_queue; 1665bcb2b582SJens Freimann k->save_config = virtio_ccw_save_config; 1666bcb2b582SJens Freimann k->load_config = virtio_ccw_load_config; 1667d1b4259fSMaxime Coquelin k->pre_plugged = virtio_ccw_pre_plugged; 1668fb846a09SCornelia Huck k->device_plugged = virtio_ccw_device_plugged; 1669fb846a09SCornelia Huck k->device_unplugged = virtio_ccw_device_unplugged; 16708e93cef1SPaolo Bonzini k->ioeventfd_enabled = virtio_ccw_ioeventfd_enabled; 16717c55f68aSCornelia Huck k->ioeventfd_assign = virtio_ccw_ioeventfd_assign; 1672a5cf2bb4SCornelia Huck } 1673a5cf2bb4SCornelia Huck 1674a5cf2bb4SCornelia Huck static const TypeInfo virtio_ccw_bus_info = { 1675a5cf2bb4SCornelia Huck .name = TYPE_VIRTIO_CCW_BUS, 1676a5cf2bb4SCornelia Huck .parent = TYPE_VIRTIO_BUS, 1677a5cf2bb4SCornelia Huck .instance_size = sizeof(VirtioCcwBusState), 1678a5cf2bb4SCornelia Huck .class_init = virtio_ccw_bus_class_init, 1679a5cf2bb4SCornelia Huck }; 1680a5cf2bb4SCornelia Huck 1681de6a9218SPierre Morel #ifdef CONFIG_VIRTFS 1682de6a9218SPierre Morel static Property virtio_ccw_9p_properties[] = { 1683b804e8a6SJing Liu DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1684de6a9218SPierre Morel DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, 1685de6a9218SPierre Morel VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), 1686542571d5SCornelia Huck DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1687542571d5SCornelia Huck VIRTIO_CCW_MAX_REV), 1688de6a9218SPierre Morel DEFINE_PROP_END_OF_LIST(), 1689de6a9218SPierre Morel }; 1690de6a9218SPierre Morel 1691de6a9218SPierre Morel static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp) 1692de6a9218SPierre Morel { 1693de6a9218SPierre Morel V9fsCCWState *dev = VIRTIO_9P_CCW(ccw_dev); 1694de6a9218SPierre Morel DeviceState *vdev = DEVICE(&dev->vdev); 1695de6a9218SPierre Morel 1696de6a9218SPierre Morel qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 16976b62d961SEduardo Habkost object_property_set_bool(OBJECT(vdev), true, "realized", errp); 1698de6a9218SPierre Morel } 1699de6a9218SPierre Morel 1700de6a9218SPierre Morel static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data) 1701de6a9218SPierre Morel { 1702de6a9218SPierre Morel DeviceClass *dc = DEVICE_CLASS(klass); 1703de6a9218SPierre Morel VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1704de6a9218SPierre Morel 1705de6a9218SPierre Morel k->exit = virtio_ccw_exit; 1706de6a9218SPierre Morel k->realize = virtio_ccw_9p_realize; 1707de6a9218SPierre Morel dc->reset = virtio_ccw_reset; 1708de6a9218SPierre Morel dc->props = virtio_ccw_9p_properties; 1709de6a9218SPierre Morel set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1710de6a9218SPierre Morel } 1711de6a9218SPierre Morel 1712de6a9218SPierre Morel static void virtio_ccw_9p_instance_init(Object *obj) 1713de6a9218SPierre Morel { 1714de6a9218SPierre Morel V9fsCCWState *dev = VIRTIO_9P_CCW(obj); 1715de6a9218SPierre Morel 1716de6a9218SPierre Morel virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 1717de6a9218SPierre Morel TYPE_VIRTIO_9P); 1718de6a9218SPierre Morel } 1719de6a9218SPierre Morel 1720de6a9218SPierre Morel static const TypeInfo virtio_ccw_9p_info = { 1721de6a9218SPierre Morel .name = TYPE_VIRTIO_9P_CCW, 1722de6a9218SPierre Morel .parent = TYPE_VIRTIO_CCW_DEVICE, 1723de6a9218SPierre Morel .instance_size = sizeof(V9fsCCWState), 1724de6a9218SPierre Morel .instance_init = virtio_ccw_9p_instance_init, 1725de6a9218SPierre Morel .class_init = virtio_ccw_9p_class_init, 1726de6a9218SPierre Morel }; 1727de6a9218SPierre Morel #endif 1728de6a9218SPierre Morel 1729fc0b9b0eSStefan Hajnoczi #ifdef CONFIG_VHOST_VSOCK 1730fc0b9b0eSStefan Hajnoczi 1731fc0b9b0eSStefan Hajnoczi static Property vhost_vsock_ccw_properties[] = { 1732fc0b9b0eSStefan Hajnoczi DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), 1733fc0b9b0eSStefan Hajnoczi DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, 1734fc0b9b0eSStefan Hajnoczi VIRTIO_CCW_MAX_REV), 1735fc0b9b0eSStefan Hajnoczi DEFINE_PROP_END_OF_LIST(), 1736fc0b9b0eSStefan Hajnoczi }; 1737fc0b9b0eSStefan Hajnoczi 1738fc0b9b0eSStefan Hajnoczi static void vhost_vsock_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp) 1739fc0b9b0eSStefan Hajnoczi { 1740fc0b9b0eSStefan Hajnoczi VHostVSockCCWState *dev = VHOST_VSOCK_CCW(ccw_dev); 1741fc0b9b0eSStefan Hajnoczi DeviceState *vdev = DEVICE(&dev->vdev); 1742fc0b9b0eSStefan Hajnoczi Error *err = NULL; 1743fc0b9b0eSStefan Hajnoczi 1744fc0b9b0eSStefan Hajnoczi qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); 1745fc0b9b0eSStefan Hajnoczi object_property_set_bool(OBJECT(vdev), true, "realized", &err); 1746fc0b9b0eSStefan Hajnoczi if (err) { 1747fc0b9b0eSStefan Hajnoczi error_propagate(errp, err); 1748fc0b9b0eSStefan Hajnoczi } 1749fc0b9b0eSStefan Hajnoczi } 1750fc0b9b0eSStefan Hajnoczi 1751fc0b9b0eSStefan Hajnoczi static void vhost_vsock_ccw_class_init(ObjectClass *klass, void *data) 1752fc0b9b0eSStefan Hajnoczi { 1753fc0b9b0eSStefan Hajnoczi DeviceClass *dc = DEVICE_CLASS(klass); 1754fc0b9b0eSStefan Hajnoczi VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); 1755fc0b9b0eSStefan Hajnoczi 1756fc0b9b0eSStefan Hajnoczi k->realize = vhost_vsock_ccw_realize; 1757fc0b9b0eSStefan Hajnoczi k->exit = virtio_ccw_exit; 1758fc0b9b0eSStefan Hajnoczi set_bit(DEVICE_CATEGORY_MISC, dc->categories); 1759fc0b9b0eSStefan Hajnoczi dc->props = vhost_vsock_ccw_properties; 1760fc0b9b0eSStefan Hajnoczi dc->reset = virtio_ccw_reset; 1761fc0b9b0eSStefan Hajnoczi } 1762fc0b9b0eSStefan Hajnoczi 1763fc0b9b0eSStefan Hajnoczi static void vhost_vsock_ccw_instance_init(Object *obj) 1764fc0b9b0eSStefan Hajnoczi { 1765fc0b9b0eSStefan Hajnoczi VHostVSockCCWState *dev = VHOST_VSOCK_CCW(obj); 1766fc0b9b0eSStefan Hajnoczi 1767fc0b9b0eSStefan Hajnoczi virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), 1768fc0b9b0eSStefan Hajnoczi TYPE_VHOST_VSOCK); 1769fc0b9b0eSStefan Hajnoczi } 1770fc0b9b0eSStefan Hajnoczi 1771fc0b9b0eSStefan Hajnoczi static const TypeInfo vhost_vsock_ccw_info = { 1772fc0b9b0eSStefan Hajnoczi .name = TYPE_VHOST_VSOCK_CCW, 1773fc0b9b0eSStefan Hajnoczi .parent = TYPE_VIRTIO_CCW_DEVICE, 1774fc0b9b0eSStefan Hajnoczi .instance_size = sizeof(VHostVSockCCWState), 1775fc0b9b0eSStefan Hajnoczi .instance_init = vhost_vsock_ccw_instance_init, 1776fc0b9b0eSStefan Hajnoczi .class_init = vhost_vsock_ccw_class_init, 1777fc0b9b0eSStefan Hajnoczi }; 1778fc0b9b0eSStefan Hajnoczi #endif 1779fc0b9b0eSStefan Hajnoczi 1780a5cf2bb4SCornelia Huck static void virtio_ccw_register(void) 1781a5cf2bb4SCornelia Huck { 1782a5cf2bb4SCornelia Huck type_register_static(&virtio_ccw_bus_info); 1783a5cf2bb4SCornelia Huck type_register_static(&virtio_ccw_device_info); 1784a5cf2bb4SCornelia Huck type_register_static(&virtio_ccw_serial); 1785a5cf2bb4SCornelia Huck type_register_static(&virtio_ccw_blk); 1786a5cf2bb4SCornelia Huck type_register_static(&virtio_ccw_net); 1787a5cf2bb4SCornelia Huck type_register_static(&virtio_ccw_balloon); 1788a5cf2bb4SCornelia Huck type_register_static(&virtio_ccw_scsi); 1789b702d2aeSEd Maste #ifdef CONFIG_VHOST_SCSI 1790ccf6916cSPaolo Bonzini type_register_static(&vhost_ccw_scsi); 1791b702d2aeSEd Maste #endif 17922362ecc5SCornelia Huck type_register_static(&virtio_ccw_rng); 1793de6a9218SPierre Morel #ifdef CONFIG_VIRTFS 1794de6a9218SPierre Morel type_register_static(&virtio_ccw_9p_info); 1795de6a9218SPierre Morel #endif 1796fc0b9b0eSStefan Hajnoczi #ifdef CONFIG_VHOST_VSOCK 1797fc0b9b0eSStefan Hajnoczi type_register_static(&vhost_vsock_ccw_info); 1798fc0b9b0eSStefan Hajnoczi #endif 1799*d2256070SHalil Pasic type_register_static(&virtio_ccw_crypto); 1800a5cf2bb4SCornelia Huck } 1801a5cf2bb4SCornelia Huck 1802a5cf2bb4SCornelia Huck type_init(virtio_ccw_register) 1803