return vdev;
}
+static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n,
+ bool assign, bool set_handler)
+{
+ VirtQueue *vq = virtio_get_queue(dev->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;
+
+ 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(event_notifier_get_fd(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(event_notifier_get_fd(notifier), sch_id,
+ n, assign);
+ event_notifier_cleanup(notifier);
+ }
+ return r;
+}
+
+static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
+{
+ int n, r;
+
+ if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) ||
+ dev->ioeventfd_started) {
+ return;
+ }
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(dev->vdev, n)) {
+ continue;
+ }
+ r = virtio_ccw_set_guest2host_notifier(dev, n, true, true);
+ if (r < 0) {
+ goto assign_error;
+ }
+ }
+ dev->ioeventfd_started = true;
+ return;
+
+ assign_error:
+ while (--n >= 0) {
+ if (!virtio_queue_get_num(dev->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 void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
+{
+ int n, r;
+
+ if (!dev->ioeventfd_started) {
+ return;
+ }
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(dev->vdev, n)) {
+ continue;
+ }
+ r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
+ assert(r >= 0);
+ }
+ dev->ioeventfd_started = false;
+}
+
VirtualCssBus *virtual_css_bus_init(void)
{
VirtualCssBus *cbus;
}
break;
case CCW_CMD_VDEV_RESET:
+ virtio_ccw_stop_ioeventfd(dev);
virtio_reset(dev->vdev);
ret = 0;
break;
ret = -EFAULT;
} else {
status = ldub_phys(ccw.cda);
+ if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ virtio_ccw_stop_ioeventfd(dev);
+ }
virtio_set_status(dev->vdev, status);
if (dev->vdev->status == 0) {
virtio_reset(dev->vdev);
}
+ if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
+ virtio_ccw_start_ioeventfd(dev);
+ }
sch->curr_status.scsw.count = ccw.count - sizeof(status);
ret = 0;
}
{
SubchDev *sch = dev->sch;
+ virtio_ccw_stop_ioeventfd(dev);
if (sch) {
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
g_free(sch);
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ virtio_ccw_stop_ioeventfd(dev);
virtio_reset(dev->vdev);
css_reset_sch(dev->sch);
dev->indicators = 0;
dev->indicators2 = 0;
}
+static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
+{
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+
+ if (running) {
+ virtio_ccw_start_ioeventfd(dev);
+ } else {
+ virtio_ccw_stop_ioeventfd(dev);
+ }
+}
+
/**************** Virtio-ccw Bus Device Descriptions *******************/
static Property virtio_ccw_net_properties[] = {
DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf),
DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial),
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
static Property virtio_ccw_balloon_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
bus_class->max_dev = 1;
k->notify = virtio_ccw_notify;
k->get_features = virtio_ccw_get_features;
+ k->vmstate_change = virtio_ccw_vmstate_change;
}
static const TypeInfo virtio_ccw_bus_info = {