Loading hw/s390x/css.c +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ int css_create_css_image(uint8_t cssid, bool default_image) return 0; } static uint16_t css_build_subchannel_id(SubchDev *sch) uint16_t css_build_subchannel_id(SubchDev *sch) { if (channel_subsys->max_cssid > 0) { return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1; Loading hw/s390x/css.h +1 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno, SubchDev *sch); void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type); uint16_t css_build_subchannel_id(SubchDev *sch); void css_reset(void); void css_reset_sch(SubchDev *sch); void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid); Loading hw/s390x/virtio-ccw.c +117 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,90 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) 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; Loading Loading @@ -187,6 +271,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } break; case CCW_CMD_VDEV_RESET: virtio_ccw_stop_ioeventfd(dev); virtio_reset(dev->vdev); ret = 0; break; Loading Loading @@ -309,10 +394,16 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) 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; } Loading Loading @@ -540,6 +631,7 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev) { 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); Loading Loading @@ -801,12 +893,24 @@ static void virtio_ccw_reset(DeviceState *d) { 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[] = { Loading @@ -814,6 +918,8 @@ 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(), }; Loading @@ -840,6 +946,8 @@ static Property virtio_ccw_blk_properties[] = { 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(), }; Loading @@ -866,6 +974,8 @@ static Property virtio_ccw_serial_properties[] = { 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(), }; Loading @@ -891,6 +1001,8 @@ static const TypeInfo virtio_ccw_serial = { 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(), }; Loading @@ -917,6 +1029,8 @@ static Property virtio_ccw_scsi_properties[] = { 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(), }; Loading Loading @@ -980,6 +1094,8 @@ static Property virtio_ccw_rng_properties[] = { 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(), }; Loading Loading @@ -1107,6 +1223,7 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) 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 = { Loading hw/s390x/virtio-ccw.h +7 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,11 @@ typedef struct VirtIOCCWDeviceClass { /* Change here if we want to support more feature bits. */ #define VIRTIO_CCW_FEATURE_SIZE 1 /* Performance improves when virtqueue kick processing is decoupled from the * vcpu thread using ioeventfd for some devices. */ #define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT) struct VirtioCcwDevice { DeviceState parent_obj; SubchDev *sch; Loading @@ -76,6 +81,8 @@ struct VirtioCcwDevice { char *bus_id; uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE]; VirtioBusState bus; bool ioeventfd_started; uint32_t flags; /* Guest provided values: */ hwaddr indicators; hwaddr indicators2; Loading target-s390x/cpu.h +16 −0 Original line number Diff line number Diff line Loading @@ -1081,6 +1081,7 @@ void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, void kvm_s390_crw_mchk(S390CPU *cpu); void kvm_s390_enable_css_support(S390CPU *cpu); int kvm_s390_get_registers_partial(CPUState *cpu); int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign); #else static inline void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, Loading @@ -1099,6 +1100,11 @@ static inline int kvm_s390_get_registers_partial(CPUState *cpu) { return -ENOSYS; } static inline int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign) { return -ENOSYS; } #endif static inline void s390_io_interrupt(S390CPU *cpu, Loading @@ -1125,4 +1131,14 @@ static inline void s390_crw_mchk(S390CPU *cpu) } } static inline int s390_assign_subch_ioeventfd(int fd, uint32_t sch_id, int vq, bool assign) { if (kvm_enabled()) { return kvm_s390_assign_subch_ioeventfd(fd, sch_id, vq, assign); } else { return -ENOSYS; } } #endif Loading
hw/s390x/css.c +1 −1 Original line number Diff line number Diff line Loading @@ -68,7 +68,7 @@ int css_create_css_image(uint8_t cssid, bool default_image) return 0; } static uint16_t css_build_subchannel_id(SubchDev *sch) uint16_t css_build_subchannel_id(SubchDev *sch) { if (channel_subsys->max_cssid > 0) { return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1; Loading
hw/s390x/css.h +1 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,7 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno, SubchDev *sch); void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type); uint16_t css_build_subchannel_id(SubchDev *sch); void css_reset(void); void css_reset_sch(SubchDev *sch); void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid); Loading
hw/s390x/virtio-ccw.c +117 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,90 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) 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; Loading Loading @@ -187,6 +271,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } break; case CCW_CMD_VDEV_RESET: virtio_ccw_stop_ioeventfd(dev); virtio_reset(dev->vdev); ret = 0; break; Loading Loading @@ -309,10 +394,16 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) 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; } Loading Loading @@ -540,6 +631,7 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev) { 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); Loading Loading @@ -801,12 +893,24 @@ static void virtio_ccw_reset(DeviceState *d) { 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[] = { Loading @@ -814,6 +918,8 @@ 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(), }; Loading @@ -840,6 +946,8 @@ static Property virtio_ccw_blk_properties[] = { 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(), }; Loading @@ -866,6 +974,8 @@ static Property virtio_ccw_serial_properties[] = { 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(), }; Loading @@ -891,6 +1001,8 @@ static const TypeInfo virtio_ccw_serial = { 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(), }; Loading @@ -917,6 +1029,8 @@ static Property virtio_ccw_scsi_properties[] = { 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(), }; Loading Loading @@ -980,6 +1094,8 @@ static Property virtio_ccw_rng_properties[] = { 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(), }; Loading Loading @@ -1107,6 +1223,7 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) 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 = { Loading
hw/s390x/virtio-ccw.h +7 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,11 @@ typedef struct VirtIOCCWDeviceClass { /* Change here if we want to support more feature bits. */ #define VIRTIO_CCW_FEATURE_SIZE 1 /* Performance improves when virtqueue kick processing is decoupled from the * vcpu thread using ioeventfd for some devices. */ #define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT) struct VirtioCcwDevice { DeviceState parent_obj; SubchDev *sch; Loading @@ -76,6 +81,8 @@ struct VirtioCcwDevice { char *bus_id; uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE]; VirtioBusState bus; bool ioeventfd_started; uint32_t flags; /* Guest provided values: */ hwaddr indicators; hwaddr indicators2; Loading
target-s390x/cpu.h +16 −0 Original line number Diff line number Diff line Loading @@ -1081,6 +1081,7 @@ void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, void kvm_s390_crw_mchk(S390CPU *cpu); void kvm_s390_enable_css_support(S390CPU *cpu); int kvm_s390_get_registers_partial(CPUState *cpu); int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign); #else static inline void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, Loading @@ -1099,6 +1100,11 @@ static inline int kvm_s390_get_registers_partial(CPUState *cpu) { return -ENOSYS; } static inline int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign) { return -ENOSYS; } #endif static inline void s390_io_interrupt(S390CPU *cpu, Loading @@ -1125,4 +1131,14 @@ static inline void s390_crw_mchk(S390CPU *cpu) } } static inline int s390_assign_subch_ioeventfd(int fd, uint32_t sch_id, int vq, bool assign) { if (kvm_enabled()) { return kvm_s390_assign_subch_ioeventfd(fd, sch_id, vq, assign); } else { return -ENOSYS; } } #endif