diff options
Diffstat (limited to 'hw/s390x/virtio-ccw.c')
-rw-r--r-- | hw/s390x/virtio-ccw.c | 457 |
1 files changed, 353 insertions, 104 deletions
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index a554a24d0..d51642db0 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -16,7 +16,6 @@ #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" -#include "sysemu/kvm.h" #include "net/net.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-serial.h" @@ -29,15 +28,35 @@ #include "hw/s390x/adapter.h" #include "hw/s390x/s390_flic.h" -#include "hw/s390x/ioinst.h" -#include "hw/s390x/css.h" +#include "ioinst.h" +#include "css.h" #include "virtio-ccw.h" #include "trace.h" -#include "hw/s390x/css-bridge.h" static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, VirtioCcwDevice *dev); +static void virtual_css_bus_reset(BusState *qbus) +{ + /* This should actually be modelled via the generic css */ + css_reset(); +} + + +static void virtual_css_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->reset = virtual_css_bus_reset; +} + +static const TypeInfo virtual_css_bus_info = { + .name = TYPE_VIRTUAL_CSS_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(VirtualCssBus), + .class_init = virtual_css_bus_class_init, +}; + VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) { VirtIODevice *vdev = NULL; @@ -49,59 +68,112 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) return vdev; } -static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) +static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n, + bool assign, bool set_handler) { - virtio_bus_start_ioeventfd(&dev->bus); -} + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + int r = 0; + SubchDev *sch = dev->sch; + uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid; -static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev) -{ - virtio_bus_stop_ioeventfd(&dev->bus); + if (assign) { + r = event_notifier_init(notifier, 1); + if (r < 0) { + error_report("%s: unable to init event notifier: %d", __func__, r); + return r; + } + virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); + r = s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); + if (r < 0) { + error_report("%s: unable to assign ioeventfd: %d", __func__, r); + virtio_queue_set_host_notifier_fd_handler(vq, false, false); + event_notifier_cleanup(notifier); + return r; + } + } else { + virtio_queue_set_host_notifier_fd_handler(vq, false, false); + s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); + event_notifier_cleanup(notifier); + } + return r; } -static bool virtio_ccw_ioeventfd_started(DeviceState *d) +static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) { - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - - return dev->ioeventfd_started; -} + VirtIODevice *vdev; + int n, r; -static void virtio_ccw_ioeventfd_set_started(DeviceState *d, bool started, - bool err) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) || + dev->ioeventfd_disabled || + dev->ioeventfd_started) { + return; + } + vdev = virtio_bus_get_device(&dev->bus); + for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = virtio_ccw_set_guest2host_notifier(dev, n, true, true); + if (r < 0) { + goto assign_error; + } + } + dev->ioeventfd_started = true; + return; - dev->ioeventfd_started = started; - if (err) { - /* Disable ioeventfd for this device. */ - dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD; + assign_error: + while (--n >= 0) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); + assert(r >= 0); } + dev->ioeventfd_started = false; + /* Disable ioeventfd for this device. */ + dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD; + error_report("%s: failed. Fallback to userspace (slower).", __func__); } -static bool virtio_ccw_ioeventfd_disabled(DeviceState *d) +static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev) { - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtIODevice *vdev; + int n, r; - return dev->ioeventfd_disabled || - !(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD); + if (!dev->ioeventfd_started) { + return; + } + vdev = virtio_bus_get_device(&dev->bus); + for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); + assert(r >= 0); + } + dev->ioeventfd_started = false; } -static void virtio_ccw_ioeventfd_set_disabled(DeviceState *d, bool disabled) +VirtualCssBus *virtual_css_bus_init(void) { - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtualCssBus *cbus; + BusState *bus; + DeviceState *dev; - dev->ioeventfd_disabled = disabled; -} + /* Create bridge device */ + dev = qdev_create(NULL, "virtual-css-bridge"); + qdev_init_nofail(dev); -static int virtio_ccw_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, - int n, bool assign) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - CcwDevice *ccw_dev = CCW_DEVICE(dev); - SubchDev *sch = ccw_dev->sch; - uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid; + /* Create bus on bridge device */ + bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); + cbus = VIRTUAL_CSS_BUS(bus); + + /* Enable hotplugging */ + qbus_set_hotplug_handler(bus, dev, &error_abort); - return s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); + return cbus; } /* Communication blocks used by several channel commands. */ @@ -195,8 +267,6 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info, static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev) { - CcwDevice *ccw_dev = CCW_DEVICE(dev); - virtio_ccw_stop_ioeventfd(dev); virtio_reset(vdev); if (dev->indicators) { @@ -211,7 +281,7 @@ static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev) release_indicator(&dev->routes.adapter, dev->summary_indicator); dev->summary_indicator = NULL; } - ccw_dev->sch->thinint_active = false; + dev->sch->thinint_active = false; } static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len, @@ -666,44 +736,151 @@ static void virtio_sch_disable_cb(SubchDev *sch) static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) { - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); - CcwDevice *ccw_dev = CCW_DEVICE(dev); - SubchDev *sch = css_create_virtual_sch(ccw_dev->bus_id, errp); + unsigned int cssid = 0; + unsigned int ssid = 0; + unsigned int schid; + unsigned int devno; + bool have_devno = false; + bool found = false; + SubchDev *sch; + int num; Error *err = NULL; + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); - if (!sch) { - return; - } + sch = g_malloc0(sizeof(SubchDev)); sch->driver_data = dev; + dev->sch = sch; + + dev->indicators = NULL; + + /* Initialize subchannel structure. */ + sch->channel_prog = 0x0; + sch->last_cmd_valid = false; + sch->thinint_active = false; + /* + * Use a device number if provided. Otherwise, fall back to subchannel + * number. + */ + if (dev->bus_id) { + num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno); + if (num == 3) { + if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) { + error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x", + cssid, ssid); + goto out_err; + } + /* Enforce use of virtual cssid. */ + if (cssid != VIRTUAL_CSSID) { + error_setg(errp, "cssid %x not valid for virtio devices", + cssid); + goto out_err; + } + if (css_devno_used(cssid, ssid, devno)) { + error_setg(errp, "Device %x.%x.%04x already exists", + cssid, ssid, devno); + goto out_err; + } + sch->cssid = cssid; + sch->ssid = ssid; + sch->devno = devno; + have_devno = true; + } else { + error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id); + goto out_err; + } + } + + /* Find the next free id. */ + if (have_devno) { + for (schid = 0; schid <= MAX_SCHID; schid++) { + if (!css_find_subch(1, cssid, ssid, schid)) { + sch->schid = schid; + css_subch_assign(cssid, ssid, schid, devno, sch); + found = true; + break; + } + } + if (!found) { + error_setg(errp, "No free subchannel found for %x.%x.%04x", + cssid, ssid, devno); + goto out_err; + } + trace_virtio_ccw_new_device(cssid, ssid, schid, devno, + "user-configured"); + } else { + cssid = VIRTUAL_CSSID; + for (ssid = 0; ssid <= MAX_SSID; ssid++) { + for (schid = 0; schid <= MAX_SCHID; schid++) { + if (!css_find_subch(1, cssid, ssid, schid)) { + sch->cssid = cssid; + sch->ssid = ssid; + sch->schid = schid; + devno = schid; + /* + * If the devno is already taken, look further in this + * subchannel set. + */ + while (css_devno_used(cssid, ssid, devno)) { + if (devno == MAX_SCHID) { + devno = 0; + } else if (devno == schid - 1) { + error_setg(errp, "No free devno found"); + goto out_err; + } else { + devno++; + } + } + sch->devno = devno; + css_subch_assign(cssid, ssid, schid, devno, sch); + found = true; + break; + } + } + if (found) { + break; + } + } + if (!found) { + error_setg(errp, "Virtual channel subsystem is full!"); + goto out_err; + } + trace_virtio_ccw_new_device(cssid, ssid, schid, devno, + "auto-configured"); + } + + /* Build initial schib. */ + css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE); + sch->ccw_cb = virtio_ccw_cb; sch->disable_cb = virtio_sch_disable_cb; + + /* Build senseid data. */ + memset(&sch->id, 0, sizeof(SenseId)); sch->id.reserved = 0xff; sch->id.cu_type = VIRTIO_CCW_CU_TYPE; - ccw_dev->sch = sch; - dev->indicators = NULL; - dev->revision = -1; - css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE); - trace_virtio_ccw_new_device( - sch->cssid, sch->ssid, sch->schid, sch->devno, - ccw_dev->bus_id.valid ? "user-configured" : "auto-configured"); + dev->revision = -1; if (k->realize) { k->realize(dev, &err); } if (err) { error_propagate(errp, err); - css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); - ccw_dev->sch = NULL; - g_free(sch); + css_subch_assign(cssid, ssid, schid, devno, NULL); + goto out_err; } + + return; + +out_err: + dev->sch = NULL; + g_free(sch); } static int virtio_ccw_exit(VirtioCcwDevice *dev) { - CcwDevice *ccw_dev = CCW_DEVICE(dev); - SubchDev *sch = ccw_dev->sch; + SubchDev *sch = dev->sch; if (sch) { css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); @@ -721,11 +898,15 @@ static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp) DeviceState *qdev = DEVICE(ccw_dev); VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; virtio_net_set_netclient_name(&dev->vdev, qdev->id, object_get_typename(OBJECT(qdev))); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_net_instance_init(Object *obj) @@ -742,9 +923,13 @@ static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_blk_instance_init(Object *obj) @@ -764,6 +949,7 @@ static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *proxy = DEVICE(ccw_dev); + Error *err = NULL; char *bus_name; /* @@ -777,7 +963,10 @@ static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) } qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } @@ -793,9 +982,13 @@ static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_balloon_instance_init(Object *obj) @@ -816,6 +1009,7 @@ static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *qdev = DEVICE(ccw_dev); + Error *err = NULL; char *bus_name; /* @@ -829,7 +1023,10 @@ static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) } qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_scsi_instance_init(Object *obj) @@ -847,9 +1044,13 @@ static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void vhost_ccw_scsi_instance_init(Object *obj) @@ -884,9 +1085,7 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) */ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) { - CcwDevice *ccw_dev = to_ccw_dev_fast(d); - - return container_of(ccw_dev, VirtioCcwDevice, parent_obj); + return container_of(d, VirtioCcwDevice, parent_obj); } static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, @@ -906,7 +1105,6 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, ind_old = *ind_addr; ind_new = ind_old | to_be_set; } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); - trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new); cpu_physical_memory_unmap(ind_addr, len, 1, len); return ind_old; @@ -915,8 +1113,7 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, static void virtio_ccw_notify(DeviceState *d, uint16_t vector) { VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d); - CcwDevice *ccw_dev = to_ccw_dev_fast(d); - SubchDev *sch = ccw_dev->sch; + SubchDev *sch = dev->sch; uint64_t indicators; /* queue indicators + secondary indicators */ @@ -974,10 +1171,9 @@ static void virtio_ccw_reset(DeviceState *d) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - CcwDevice *ccw_dev = CCW_DEVICE(d); virtio_ccw_reset_virtio(dev, vdev); - css_reset_sch(ccw_dev->sch); + css_reset_sch(dev->sch); } static void virtio_ccw_vmstate_change(DeviceState *d, bool running) @@ -993,17 +1189,29 @@ static void virtio_ccw_vmstate_change(DeviceState *d, bool running) static bool virtio_ccw_query_guest_notifiers(DeviceState *d) { - CcwDevice *dev = CCW_DEVICE(d); + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA); } +static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + + /* Stop using the generic ioeventfd, we are doing eventfd handling + * ourselves below */ + dev->ioeventfd_disabled = assign; + if (assign) { + virtio_ccw_stop_ioeventfd(dev); + } + return virtio_ccw_set_guest2host_notifier(dev, n, assign, false); +} + static int virtio_ccw_get_mappings(VirtioCcwDevice *dev) { int r; - CcwDevice *ccw_dev = CCW_DEVICE(dev); - if (!ccw_dev->sch->thinint_active) { + if (!dev->sch->thinint_active) { return -EINVAL; } @@ -1125,8 +1333,7 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - CcwDevice *ccw_dev = CCW_DEVICE(d); - bool with_irqfd = ccw_dev->sch->thinint_active && kvm_irqfds_enabled(); + bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled(); int r, n; if (with_irqfd && assigned) { @@ -1185,8 +1392,7 @@ static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f) static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - CcwDevice *ccw_dev = CCW_DEVICE(d); - SubchDev *s = ccw_dev->sch; + SubchDev *s = dev->sch; VirtIODevice *vdev = virtio_ccw_get_vdev(s); subch_device_save(s, f); @@ -1220,8 +1426,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f) static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - CcwDevice *ccw_dev = CCW_DEVICE(d); - SubchDev *s = ccw_dev->sch; + SubchDev *s = dev->sch; VirtIODevice *vdev = virtio_ccw_get_vdev(s); int len; @@ -1266,12 +1471,11 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - CcwDevice *ccw_dev = CCW_DEVICE(d); - SubchDev *sch = ccw_dev->sch; + SubchDev *sch = dev->sch; int n = virtio_get_num_queues(vdev); if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) { - error_setg(errp, "The number of virtqueues %d " + error_setg(errp, "The nubmer of virtqueues %d " "exceeds ccw limit %d", n, VIRTIO_CCW_QUEUE_MAX); return; @@ -1311,7 +1515,7 @@ static void virtio_ccw_device_unplugged(DeviceState *d) /**************** Virtio-ccw Bus Device Descriptions *******************/ static Property virtio_ccw_net_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1340,7 +1544,7 @@ static const TypeInfo virtio_ccw_net = { }; static Property virtio_ccw_blk_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1369,7 +1573,7 @@ static const TypeInfo virtio_ccw_blk = { }; static Property virtio_ccw_serial_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1398,7 +1602,7 @@ static const TypeInfo virtio_ccw_serial = { }; static Property virtio_ccw_balloon_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1427,7 +1631,7 @@ static const TypeInfo virtio_ccw_balloon = { }; static Property virtio_ccw_scsi_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1457,7 +1661,7 @@ static const TypeInfo virtio_ccw_scsi = { #ifdef CONFIG_VHOST_SCSI static Property vhost_ccw_scsi_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, VIRTIO_CCW_MAX_REV), DEFINE_PROP_END_OF_LIST(), @@ -1495,7 +1699,7 @@ static void virtio_ccw_rng_instance_init(Object *obj) } static Property virtio_ccw_rng_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1542,17 +1746,29 @@ static int virtio_ccw_busdev_exit(DeviceState *dev) static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - VirtioCcwDevice *_dev = to_virtio_ccw_dev_fast(dev); + VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; + SubchDev *sch = _dev->sch; virtio_ccw_stop_ioeventfd(_dev); + + /* + * We should arrive here only for device_del, since we don't support + * direct hot(un)plug of channels, but only through virtio. + */ + assert(sch != NULL); + /* Subchannel is now disabled and no longer valid. */ + sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | + PMCW_FLAGS_MASK_DNV); + + css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); + + object_unparent(OBJECT(dev)); } static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - CCWDeviceClass *k = CCW_DEVICE_CLASS(dc); - k->unplug = virtio_ccw_busdev_unplug; dc->realize = virtio_ccw_busdev_realize; dc->exit = virtio_ccw_busdev_exit; dc->bus_type = TYPE_VIRTUAL_CSS_BUS; @@ -1560,13 +1776,44 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) static const TypeInfo virtio_ccw_device_info = { .name = TYPE_VIRTIO_CCW_DEVICE, - .parent = TYPE_CCW_DEVICE, + .parent = TYPE_DEVICE, .instance_size = sizeof(VirtioCcwDevice), .class_init = virtio_ccw_device_class_init, .class_size = sizeof(VirtIOCCWDeviceClass), .abstract = true, }; +/***************** Virtual-css Bus Bridge Device ********************/ +/* Only required to have the virtio bus as child in the system bus */ + +static int virtual_css_bridge_init(SysBusDevice *dev) +{ + /* nothing */ + return 0; +} + +static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = virtual_css_bridge_init; + hc->unplug = virtio_ccw_busdev_unplug; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + +static const TypeInfo virtual_css_bridge_info = { + .name = "virtual-css-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = virtual_css_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } +}; + /* virtio-ccw-bus */ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, @@ -1588,6 +1835,7 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) k->notify = virtio_ccw_notify; k->vmstate_change = virtio_ccw_vmstate_change; k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; + k->set_host_notifier = virtio_ccw_set_host_notifier; k->set_guest_notifiers = virtio_ccw_set_guest_notifiers; k->save_queue = virtio_ccw_save_queue; k->load_queue = virtio_ccw_load_queue; @@ -1596,11 +1844,6 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) k->device_plugged = virtio_ccw_device_plugged; k->post_plugged = virtio_ccw_post_plugged; k->device_unplugged = virtio_ccw_device_unplugged; - k->ioeventfd_started = virtio_ccw_ioeventfd_started; - k->ioeventfd_set_started = virtio_ccw_ioeventfd_set_started; - k->ioeventfd_disabled = virtio_ccw_ioeventfd_disabled; - k->ioeventfd_set_disabled = virtio_ccw_ioeventfd_set_disabled; - k->ioeventfd_assign = virtio_ccw_ioeventfd_assign; } static const TypeInfo virtio_ccw_bus_info = { @@ -1612,7 +1855,7 @@ static const TypeInfo virtio_ccw_bus_info = { #ifdef CONFIG_VIRTFS static Property virtio_ccw_9p_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1624,9 +1867,13 @@ static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp) { V9fsCCWState *dev = VIRTIO_9P_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data) @@ -1661,6 +1908,7 @@ static const TypeInfo virtio_ccw_9p_info = { static void virtio_ccw_register(void) { type_register_static(&virtio_ccw_bus_info); + type_register_static(&virtual_css_bus_info); type_register_static(&virtio_ccw_device_info); type_register_static(&virtio_ccw_serial); type_register_static(&virtio_ccw_blk); @@ -1671,6 +1919,7 @@ static void virtio_ccw_register(void) type_register_static(&vhost_ccw_scsi); #endif type_register_static(&virtio_ccw_rng); + type_register_static(&virtual_css_bridge_info); #ifdef CONFIG_VIRTFS type_register_static(&virtio_ccw_9p_info); #endif |