From patchwork Fri Feb 22 12:10:00 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cornelia Huck X-Patchwork-Id: 222522 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 279622C029E for ; Fri, 22 Feb 2013 23:54:32 +1100 (EST) Received: from localhost ([::1]:54438 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U8rTA-0001tK-DG for incoming@patchwork.ozlabs.org; Fri, 22 Feb 2013 07:11:16 -0500 Received: from eggs.gnu.org ([208.118.235.92]:49091) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U8rS7-0001ko-Fw for qemu-devel@nongnu.org; Fri, 22 Feb 2013 07:10:16 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1U8rS2-0005Wi-8q for qemu-devel@nongnu.org; Fri, 22 Feb 2013 07:10:08 -0500 Received: from e06smtp17.uk.ibm.com ([195.75.94.113]:53897) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U8rS1-0005Ug-Ti for qemu-devel@nongnu.org; Fri, 22 Feb 2013 07:10:06 -0500 Received: from /spool/local by e06smtp17.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 22 Feb 2013 12:08:29 -0000 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp17.uk.ibm.com (192.168.101.147) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 22 Feb 2013 12:08:28 -0000 Received: from b06cxnps3074.portsmouth.uk.ibm.com (d06relay09.portsmouth.uk.ibm.com [9.149.109.194]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id 247D717D8056 for ; Fri, 22 Feb 2013 12:10:33 +0000 (GMT) Received: from d06av12.portsmouth.uk.ibm.com (d06av12.portsmouth.uk.ibm.com [9.149.37.247]) by b06cxnps3074.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r1MC9rfi23199850 for ; Fri, 22 Feb 2013 12:09:53 GMT Received: from d06av12.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av12.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id r1MCA2aV012832 for ; Fri, 22 Feb 2013 05:10:02 -0700 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av12.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id r1MCA0Gf012700; Fri, 22 Feb 2013 05:10:01 -0700 From: Cornelia Huck To: qemu-devel Date: Fri, 22 Feb 2013 13:10:00 +0100 Message-Id: <1361535000-39210-3-git-send-email-cornelia.huck@de.ibm.com> X-Mailer: git-send-email 1.7.12.4 In-Reply-To: <1361535000-39210-1-git-send-email-cornelia.huck@de.ibm.com> References: <1361535000-39210-1-git-send-email-cornelia.huck@de.ibm.com> X-TM-AS-MML: No X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13022212-0542-0000-0000-0000047B2C14 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 195.75.94.113 Cc: linux-s390 , KVM Subject: [Qemu-devel] [RFC PATCH v2 2/2] virtio-ccw: Wire up ioeventfd. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org On hosts that support ioeventfd, make use of it for host-to-guest notifications via diagnose 500. Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 2 +- hw/s390x/css.h | 1 + hw/s390x/virtio-ccw.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/s390x/virtio-ccw.h | 7 ++++ target-s390x/cpu.h | 16 +++++++ target-s390x/kvm.c | 18 ++++++++ 6 files changed, 157 insertions(+), 1 deletion(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 85f6f22..82e6746 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -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; diff --git a/hw/s390x/css.h b/hw/s390x/css.h index 85ed05d..b536ab5 100644 --- a/hw/s390x/css.h +++ b/hw/s390x/css.h @@ -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); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index d92e427..23b8092 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -63,6 +63,84 @@ 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); + s390_assign_subch_ioeventfd(event_notifier_get_fd(notifier), sch_id, + n, assign); + } 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; @@ -187,6 +265,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; @@ -313,10 +392,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; } @@ -566,6 +651,7 @@ static int virtio_ccw_net_init(VirtioCcwDevice *dev) static int virtio_ccw_net_exit(VirtioCcwDevice *dev) { + virtio_ccw_stop_ioeventfd(dev); virtio_net_exit(dev->vdev); return virtio_ccw_exit(dev); } @@ -584,6 +670,7 @@ static int virtio_ccw_blk_init(VirtioCcwDevice *dev) static int virtio_ccw_blk_exit(VirtioCcwDevice *dev) { + virtio_ccw_stop_ioeventfd(dev); virtio_blk_exit(dev->vdev); blockdev_mark_auto_del(dev->blk.conf.bs); return virtio_ccw_exit(dev); @@ -603,6 +690,7 @@ static int virtio_ccw_serial_init(VirtioCcwDevice *dev) static int virtio_ccw_serial_exit(VirtioCcwDevice *dev) { + virtio_ccw_stop_ioeventfd(dev); virtio_serial_exit(dev->vdev); return virtio_ccw_exit(dev); } @@ -621,6 +709,7 @@ static int virtio_ccw_balloon_init(VirtioCcwDevice *dev) static int virtio_ccw_balloon_exit(VirtioCcwDevice *dev) { + virtio_ccw_stop_ioeventfd(dev); virtio_balloon_exit(dev->vdev); return virtio_ccw_exit(dev); } @@ -639,6 +728,7 @@ static int virtio_ccw_scsi_init(VirtioCcwDevice *dev) static int virtio_ccw_scsi_exit(VirtioCcwDevice *dev) { + virtio_ccw_stop_ioeventfd(dev); virtio_scsi_exit(dev->vdev); return virtio_ccw_exit(dev); } @@ -688,15 +778,28 @@ 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); } +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 const VirtIOBindings virtio_ccw_bindings = { .notify = virtio_ccw_notify, .get_features = virtio_ccw_get_features, + .vmstate_change = virtio_ccw_vmstate_change, }; static Property virtio_ccw_net_properties[] = { @@ -708,6 +811,8 @@ static Property virtio_ccw_net_properties[] = { DEFINE_PROP_INT32("x-txburst", VirtioCcwDevice, net.txburst, TX_BURST), DEFINE_PROP_STRING("tx", VirtioCcwDevice, net.tx), + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, + VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), }; @@ -737,6 +842,8 @@ static Property virtio_ccw_blk_properties[] = { DEFINE_PROP_BIT("scsi", VirtioCcwDevice, blk.scsi, 0, true), #endif DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]), + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, + VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), }; @@ -763,6 +870,8 @@ static Property virtio_ccw_serial_properties[] = { DEFINE_PROP_UINT32("max_ports", VirtioCcwDevice, serial.max_virtserial_ports, 31), 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(), }; @@ -787,6 +896,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(), }; @@ -811,6 +922,8 @@ static const TypeInfo virtio_ccw_balloon = { static Property virtio_ccw_scsi_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_VIRTIO_SCSI_PROPERTIES(VirtioCcwDevice, host_features[0], scsi), + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, + VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), }; @@ -936,6 +1049,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 = { diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 48474b3..db83e0f 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -66,6 +66,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; @@ -78,6 +83,8 @@ struct VirtioCcwDevice { virtio_net_conf net; VirtIOSCSIConf scsi; VirtioBusState bus; + bool ioeventfd_started; + uint32_t flags; /* Guest provided values: */ hwaddr indicators; hwaddr indicators2; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index e450db7..3e891d4 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1068,6 +1068,7 @@ void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, uint32_t io_int_word); void kvm_s390_crw_mchk(S390CPU *cpu); void kvm_s390_enable_css_support(S390CPU *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, @@ -1082,6 +1083,11 @@ static inline void kvm_s390_crw_mchk(S390CPU *cpu) static inline void kvm_s390_enable_css_support(S390CPU *cpu) { } +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, @@ -1108,4 +1114,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 diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 3929771..76445d2 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -847,3 +847,21 @@ void kvm_s390_enable_css_support(S390CPU *cpu) r = kvm_vcpu_ioctl(CPU(cpu), KVM_ENABLE_CAP, &cap); assert(r == 0); } + +int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign) +{ + struct kvm_ioeventfd kick = { + .flags = KVM_IOEVENTFD_FLAG_CSS | KVM_IOEVENTFD_FLAG_DATAMATCH, + .fd = fd, + .datamatch = vq, + .addr = sch, + .len = 8, + }; + if (!kvm_check_extension(kvm_state, KVM_CAP_IOEVENTFD)) { + return -ENOSYS; + } + if (!assign) { + kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN; + } + return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); +}