From patchwork Mon Apr 25 16:57:15 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cornelia Huck X-Patchwork-Id: 8930741 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id A9164BF29F for ; Mon, 25 Apr 2016 17:01:22 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D11FE201E4 for ; Mon, 25 Apr 2016 17:01:21 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C28BB2015A for ; Mon, 25 Apr 2016 17:01:19 +0000 (UTC) Received: from localhost ([::1]:33003 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aujst-000769-8L for patchwork-qemu-devel@patchwork.kernel.org; Mon, 25 Apr 2016 13:01:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38824) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aujpH-0007Cb-2o for qemu-devel@nongnu.org; Mon, 25 Apr 2016 12:57:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aujpC-0007Sf-Pu for qemu-devel@nongnu.org; Mon, 25 Apr 2016 12:57:35 -0400 Received: from e06smtp07.uk.ibm.com ([195.75.94.103]:50914) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aujpC-0007RW-Da for qemu-devel@nongnu.org; Mon, 25 Apr 2016 12:57:30 -0400 Received: from localhost by e06smtp07.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 25 Apr 2016 17:57:28 +0100 Received: from d06dlp01.portsmouth.uk.ibm.com (9.149.20.13) by e06smtp07.uk.ibm.com (192.168.101.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 25 Apr 2016 17:57:23 +0100 X-IBM-Helo: d06dlp01.portsmouth.uk.ibm.com X-IBM-MailFrom: cornelia.huck@de.ibm.com X-IBM-RcptTo: qemu-devel@nongnu.org Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by d06dlp01.portsmouth.uk.ibm.com (Postfix) with ESMTP id 5D2FA17D805D for ; Mon, 25 Apr 2016 17:58:13 +0100 (BST) Received: from d06av08.portsmouth.uk.ibm.com (d06av08.portsmouth.uk.ibm.com [9.149.37.249]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u3PGvNbv5767524 for ; Mon, 25 Apr 2016 16:57:23 GMT Received: from d06av08.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u3PGvM8n013226 for ; Mon, 25 Apr 2016 10:57:23 -0600 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u3PGvL3R013203 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA256 bits=256 verify=NO); Mon, 25 Apr 2016 10:57:22 -0600 From: Cornelia Huck To: qemu-devel@nongnu.org Date: Mon, 25 Apr 2016 18:57:15 +0200 Message-Id: <1461603440-67287-2-git-send-email-cornelia.huck@de.ibm.com> X-Mailer: git-send-email 2.6.6 In-Reply-To: <1461603440-67287-1-git-send-email-cornelia.huck@de.ibm.com> References: <1461603440-67287-1-git-send-email-cornelia.huck@de.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16042516-0029-0000-0000-000014462A85 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.75.94.103 Subject: [Qemu-devel] [PATCH for-2.7 1/6] virtio-bus: common ioeventfd infrastructure X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: famz@redhat.com, mst@redhat.com, borntraeger@de.ibm.com, stefanha@redhat.com, Cornelia Huck , pbonzini@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Introduce a set of ioeventfd callbacks on the virtio-bus level that can be implemented by the individual transports. At the virtio-bus level, do common handling for host notifiers (which is actually most of it). Two things of note: - When setting the host notifier, we only switch from/to the generic ioeventfd handler. This fixes a latent bug where we had no ioeventfd assigned for a certain window. - We always iterate over all possible virtio queues, even though ccw (currently) has a lower limit. It does not really matter here. Signed-off-by: Cornelia Huck --- hw/virtio/virtio-bus.c | 132 +++++++++++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-bus.h | 30 ++++++++++ 2 files changed, 162 insertions(+) diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 574f0e2..1313760 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -146,6 +146,138 @@ void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config) } } +/* + * This function handles both assigning the ioeventfd handler and + * registering it with the kernel. + * assign: register/deregister ioeventfd with the kernel + * set_handler: use the generic ioeventfd handler + */ +static int set_host_notifier_internal(DeviceState *proxy, VirtioBusState *bus, + int n, bool assign, bool set_handler) +{ + VirtIODevice *vdev = virtio_bus_get_device(bus); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + int r = 0; + + 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 = k->ioeventfd_assign(proxy, notifier, 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); + k->ioeventfd_assign(proxy, notifier, n, assign); + event_notifier_cleanup(notifier); + } + return r; +} + +void virtio_bus_start_ioeventfd(VirtioBusState *bus) +{ + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); + DeviceState *proxy = DEVICE(BUS(bus)->parent); + VirtIODevice *vdev; + int n, r; + + if (!k->ioeventfd_started || k->ioeventfd_started(proxy)) { + return; + } + if (k->ioeventfd_disabled(proxy)) { + return; + } + vdev = virtio_bus_get_device(bus); + for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = set_host_notifier_internal(proxy, bus, n, true, true); + if (r < 0) { + goto assign_error; + } + } + k->ioeventfd_set_started(proxy, true, false); + return; + +assign_error: + while (--n >= 0) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + + r = set_host_notifier_internal(proxy, bus, n, false, false); + assert(r >= 0); + } + k->ioeventfd_set_started(proxy, false, true); + error_report("%s: failed. Fallback to userspace (slower).", __func__); +} + +void virtio_bus_stop_ioeventfd(VirtioBusState *bus) +{ + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); + DeviceState *proxy = DEVICE(BUS(bus)->parent); + VirtIODevice *vdev; + int n, r; + + if (!k->ioeventfd_started || !k->ioeventfd_started(proxy)) { + return; + } + vdev = virtio_bus_get_device(bus); + for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = set_host_notifier_internal(proxy, bus, n, false, false); + assert(r >= 0); + } + k->ioeventfd_set_started(proxy, false, false); +} + +/* + * This function switches from/to the generic ioeventfd handler. + * assign==false means 'use generic ioeventfd handler'. + */ +int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) +{ + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); + DeviceState *proxy = DEVICE(BUS(bus)->parent); + VirtIODevice *vdev = virtio_bus_get_device(bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + + if (!k->ioeventfd_started) { + return -ENOSYS; + } + if (assign) { + /* + * Stop using the generic ioeventfd, we are doing eventfd handling + * ourselves below + */ + k->ioeventfd_set_disabled(proxy, true); + } + /* + * Just switch the handler, don't deassign the ioeventfd. + * Otherwise, there's a window where we don't have an + * ioeventfd and we may end up with a notification where + * we don't expect one. + */ + virtio_queue_set_host_notifier_fd_handler(vq, assign, !assign); + if (!assign) { + /* Use generic ioeventfd handler again. */ + k->ioeventfd_set_disabled(proxy, false); + } + return 0; +} + static char *virtio_bus_get_dev_path(DeviceState *dev) { BusState *bus = qdev_get_parent_bus(dev); diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index 3f2c136..9637f80 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -71,6 +71,29 @@ typedef struct VirtioBusClass { void (*device_unplugged)(DeviceState *d); int (*query_nvectors)(DeviceState *d); /* + * ioeventfd handling: if the transport implements ioeventfd_started, + * it must implement the other ioeventfd callbacks as well + */ + /* Returns true if the ioeventfd has been started for the device. */ + bool (*ioeventfd_started)(DeviceState *d); + /* + * Sets the 'ioeventfd started' state after the ioeventfd has been + * started/stopped for the device. err signifies whether an error + * had occurred. + */ + void (*ioeventfd_set_started)(DeviceState *d, bool started, bool err); + /* Returns true if the ioeventfd has been disabled for the device. */ + bool (*ioeventfd_disabled)(DeviceState *d); + /* Sets the 'ioeventfd disabled' state for the device. */ + void (*ioeventfd_set_disabled)(DeviceState *d, bool disabled); + /* + * Assigns/deassigns the ioeventfd backing for the transport on + * the device for queue number n. Returns an error value on + * failure. + */ + int (*ioeventfd_assign)(DeviceState *d, EventNotifier *notifier, + int n, bool assign); + /* * Does the transport have variable vring alignment? * (ie can it ever call virtio_queue_set_align()?) * Note that changing this will break migration for this transport. @@ -111,4 +134,11 @@ static inline VirtIODevice *virtio_bus_get_device(VirtioBusState *bus) return (VirtIODevice *)qdev; } +/* Start the ioeventfd. */ +void virtio_bus_start_ioeventfd(VirtioBusState *bus); +/* Stop the ioeventfd. */ +void virtio_bus_stop_ioeventfd(VirtioBusState *bus); +/* Switch from/to the generic ioeventfd handler */ +int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign); + #endif /* VIRTIO_BUS_H */