From patchwork Wed Dec 26 10:52:32 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Michael S. Tsirkin" X-Patchwork-Id: 208163 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 BB4B62C00C2 for ; Wed, 26 Dec 2012 22:16:29 +1100 (EST) Received: from localhost ([::1]:40453 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TnoYm-0000Qq-3b for incoming@patchwork.ozlabs.org; Wed, 26 Dec 2012 05:50:04 -0500 Received: from eggs.gnu.org ([208.118.235.92]:52903) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TnoY7-0007N6-Br for qemu-devel@nongnu.org; Wed, 26 Dec 2012 05:49:26 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TnoY4-0004cT-A6 for qemu-devel@nongnu.org; Wed, 26 Dec 2012 05:49:23 -0500 Received: from mx1.redhat.com ([209.132.183.28]:43974) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TnoY4-0004cO-2M for qemu-devel@nongnu.org; Wed, 26 Dec 2012 05:49:20 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id qBQAnJvh031444 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 26 Dec 2012 05:49:19 -0500 Received: from redhat.com (vpn1-4-149.ams2.redhat.com [10.36.4.149]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with SMTP id qBQAnHqp015676; Wed, 26 Dec 2012 05:49:18 -0500 Date: Wed, 26 Dec 2012 12:52:32 +0200 From: "Michael S. Tsirkin" To: qemu-devel@nongnu.org, asias@redhat.com, stefanha@redhat.com Message-ID: <0032762b76678fa65cf10e0c9bc610759fa3dc41.1356519046.git.mst@redhat.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Mutt-Fcc: =sent X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 5/8] virtio: backend virtqueue notifier masking 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 some backends (notably vhost) can mask events at their source in a way that is more efficient than masking through kvm. Specifically - masking in kvm uses rcu write side so it has high latency - in kvm on unmask we always send an interrupt masking at source does not have these issues. Add such support in virtio.h and use in virtio-pci. Signed-off-by: Michael S. Tsirkin --- hw/virtio-pci.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++------- hw/virtio.h | 13 ++++++++++ 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 1d77146..aad9d6d 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -510,6 +510,31 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, } } +static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector) +{ + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); + int ret; + ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); + return ret; +} + +static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, + unsigned int queue_no, + unsigned int vector) +{ + VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + EventNotifier *n = virtio_queue_get_guest_notifier(vq); + VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; + int ret; + + ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); + assert(ret == 0); +} + static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) { PCIDevice *dev = &proxy->pci_dev; @@ -531,6 +556,16 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) if (ret < 0) { goto undo; } + /* If guest supports masking, set up irqfd now. + * Otherwise, delay until unmasked in the frontend. + */ + if (proxy->vdev->guest_notifier_mask) { + ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + if (ret < 0) { + kvm_virtio_pci_vq_vector_release(proxy, vector); + goto undo; + } + } } return 0; @@ -540,6 +575,9 @@ undo: if (vector >= msix_nr_vectors_allocated(dev)) { continue; } + if (proxy->vdev->guest_notifier_mask) { + kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + } kvm_virtio_pci_vq_vector_release(proxy, vector); } return ret; @@ -560,6 +598,12 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) if (vector >= msix_nr_vectors_allocated(dev)) { continue; } + /* If guest supports masking, clean up irqfd now. + * Otherwise, it was cleaned when masked in the frontend. + */ + if (proxy->vdev->guest_notifier_mask) { + kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + } kvm_virtio_pci_vq_vector_release(proxy, vector); } } @@ -581,7 +625,19 @@ static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, } } - ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq); + /* If guest supports masking, irqfd is already setup, unmask it. + * Otherwise, set it up now. + */ + if (proxy->vdev->guest_notifier_mask) { + proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false); + /* Test after unmasking to avoid losing events. */ + if (proxy->vdev->guest_notifier_pending && + proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) { + event_notifier_set(n); + } + } else { + ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); + } return ret; } @@ -589,13 +645,14 @@ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, unsigned int queue_no, unsigned int vector) { - VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); - EventNotifier *n = virtio_queue_get_guest_notifier(vq); - VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; - int ret; - - ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq); - assert(ret == 0); + /* If guest supports masking, keep irqfd but mask it. + * Otherwise, clean it up now. + */ + if (proxy->vdev->guest_notifier_mask) { + proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true); + } else { + kvm_virtio_pci_irqfd_release(proxy, vector, queue_no); + } } static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, @@ -668,7 +725,11 @@ static void kvm_virtio_pci_vector_poll(PCIDevice *dev, } vq = virtio_get_queue(vdev, queue_no); notifier = virtio_queue_get_guest_notifier(vq); - if (event_notifier_test_and_clear(notifier)) { + if (vdev->guest_notifier_pending) { + if (vdev->guest_notifier_pending(vdev, queue_no)) { + msix_set_pending(dev, vector); + } + } else if (event_notifier_test_and_clear(notifier)) { msix_set_pending(dev, vector); } } diff --git a/hw/virtio.h b/hw/virtio.h index 329b426..b9f1873 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -126,6 +126,19 @@ struct VirtIODevice void (*set_config)(VirtIODevice *vdev, const uint8_t *config); void (*reset)(VirtIODevice *vdev); void (*set_status)(VirtIODevice *vdev, uint8_t val); + /* Test and clear event pending status. + * Should be called after unmask to avoid losing events. + * If backend does not support masking, + * must check in frontend instead. + */ + bool (*guest_notifier_pending)(VirtIODevice *vdev, int n); + /* Mask/unmask events from this vq. Any events reported + * while masked will become pending. + * If backend does not support masking, + * must mask in frontend instead. + */ + void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask); + VirtQueue *vq; const VirtIOBindings *binding; DeviceState *binding_opaque;