From patchwork Wed Jul 18 15:07:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 1211671 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 3ED52E0079 for ; Wed, 18 Jul 2012 15:09:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754847Ab2GRPJI (ORCPT ); Wed, 18 Jul 2012 11:09:08 -0400 Received: from e06smtp13.uk.ibm.com ([195.75.94.109]:56970 "EHLO e06smtp13.uk.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752628Ab2GRPIw (ORCPT ); Wed, 18 Jul 2012 11:08:52 -0400 Received: from /spool/local by e06smtp13.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 18 Jul 2012 16:08:51 +0100 Received: from d06nrmr1307.portsmouth.uk.ibm.com (9.149.38.129) by e06smtp13.uk.ibm.com (192.168.101.143) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 18 Jul 2012 16:08:48 +0100 Received: from d06av05.portsmouth.uk.ibm.com (d06av05.portsmouth.uk.ibm.com [9.149.37.229]) by d06nrmr1307.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q6IF8msG2727940 for ; Wed, 18 Jul 2012 16:08:48 +0100 Received: from d06av05.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av05.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q6IF8l1V012333 for ; Wed, 18 Jul 2012 09:08:47 -0600 Received: from localhost (sig-9-145-185-169.de.ibm.com [9.145.185.169]) by d06av05.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q6IF8kAj012314; Wed, 18 Jul 2012 09:08:47 -0600 From: Stefan Hajnoczi To: Cc: , Anthony Liguori , Kevin Wolf , Paolo Bonzini , "Michael S. Tsirkin" , Asias He , Khoa Huynh , Stefan Hajnoczi Subject: [RFC v9 27/27] virtio-blk: add EVENT_IDX support to dataplane Date: Wed, 18 Jul 2012 16:07:54 +0100 Message-Id: <1342624074-24650-28-git-send-email-stefanha@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1342624074-24650-1-git-send-email-stefanha@linux.vnet.ibm.com> References: <1342624074-24650-1-git-send-email-stefanha@linux.vnet.ibm.com> x-cbid: 12071815-2966-0000-0000-000004C24102 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This patch adds support for the VIRTIO_RING_F_EVENT_IDX feature for interrupt mitigation. virtio-blk doesn't do anything fancy with it so we may not see a performance improvement. This patch will allow newer guest kernels to run successfully. Signed-off-by: Stefan Hajnoczi --- hw/dataplane/vring.h | 65 ++++++++++++++++++++++++++++++++++++++++---------- hw/virtio-blk.c | 16 ++++++------- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/hw/dataplane/vring.h b/hw/dataplane/vring.h index bbf8c86..d939a22 100644 --- a/hw/dataplane/vring.h +++ b/hw/dataplane/vring.h @@ -14,6 +14,8 @@ typedef struct { struct vring vr; /* virtqueue vring mapped to host memory */ __u16 last_avail_idx; /* last processed avail ring index */ __u16 last_used_idx; /* last processed used ring index */ + uint16_t signalled_used; /* EVENT_IDX state */ + bool signalled_used_valid; } Vring; static inline unsigned int vring_get_num(Vring *vring) @@ -63,6 +65,8 @@ static void vring_setup(Vring *vring, VirtIODevice *vdev, int n) vring->last_avail_idx = 0; vring->last_used_idx = 0; + vring->signalled_used = 0; + vring->signalled_used_valid = false; fprintf(stderr, "vring physical=%#lx desc=%p avail=%p used=%p\n", (unsigned long)virtio_queue_get_ring_addr(vdev, n), @@ -75,21 +79,48 @@ static bool vring_more_avail(Vring *vring) return vring->vr.avail->idx != vring->last_avail_idx; } -/* Hint to disable guest->host notifies */ -static void vring_disable_cb(Vring *vring) +/* Toggle guest->host notifies */ +static void vring_set_notification(VirtIODevice *vdev, Vring *vring, bool enable) { - vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY; + if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { + if (enable) { + vring_avail_event(&vring->vr) = vring->vr.avail->idx; + } + } else if (enable) { + vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY; + } else { + vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY; + } } -/* Re-enable guest->host notifies - * - * Returns false if there are more descriptors in the ring. - */ -static bool vring_enable_cb(Vring *vring) +/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */ +static bool vring_should_notify(VirtIODevice *vdev, Vring *vring) { - vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY; - __sync_synchronize(); /* mb() */ - return !vring_more_avail(vring); + uint16_t old, new; + bool v; + /* Flush out used index updates. This is paired + * with the barrier that the Guest executes when enabling + * interrupts. */ + __sync_synchronize(); /* smp_mb() */ + + if ((vdev->guest_features & VIRTIO_F_NOTIFY_ON_EMPTY) && + unlikely(vring->vr.avail->idx == vring->last_avail_idx)) { + return true; + } + + if (!(vdev->guest_features & VIRTIO_RING_F_EVENT_IDX)) { + return !(vring->vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT); + } + old = vring->signalled_used; + v = vring->signalled_used_valid; + new = vring->signalled_used = vring->last_used_idx; + vring->signalled_used_valid = true; + + if (unlikely(!v)) { + return true; + } + + return vring_need_event(vring_used_event(&vring->vr), new, old); } /* This is stolen from linux-2.6/drivers/vhost/vhost.c. */ @@ -178,7 +209,7 @@ static bool get_indirect(Vring *vring, * * Stolen from linux-2.6/drivers/vhost/vhost.c. */ -static int vring_pop(Vring *vring, +static int vring_pop(VirtIODevice *vdev, Vring *vring, struct iovec iov[], struct iovec *iov_end, unsigned int *out_num, unsigned int *in_num) { @@ -214,6 +245,10 @@ static int vring_pop(Vring *vring, exit(1); } + if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) { + vring_avail_event(&vring->vr) = vring->vr.avail->idx; + } + /* When we start there are none of either input nor output. */ *out_num = *in_num = 0; @@ -279,6 +314,7 @@ static int vring_pop(Vring *vring, static void vring_push(Vring *vring, unsigned int head, int len) { struct vring_used_elem *used; + uint16_t new; /* The virtqueue contains a ring of used buffers. Get a pointer to the * next entry in that used ring. */ @@ -289,7 +325,10 @@ static void vring_push(Vring *vring, unsigned int head, int len) /* Make sure buffer is written before we update index. */ __sync_synchronize(); /* smp_wmb() */ - vring->vr.used->idx = ++vring->last_used_idx; + new = vring->vr.used->idx = ++vring->last_used_idx; + if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) { + vring->signalled_used_valid = false; + } } #endif /* VRING_H */ diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index cff2298..a3e3d8c 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -96,11 +96,9 @@ static int get_raw_posix_fd_hack(VirtIOBlock *s) /* Raise an interrupt to signal guest, if necessary */ static void virtio_blk_notify_guest(VirtIOBlock *s) { - /* Always notify when queue is empty (when feature acknowledge) */ - if ((s->vring.vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) && - (s->vring.vr.avail->idx != s->vring.last_avail_idx || - !(s->vdev.guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)))) - return; + if (!vring_should_notify(&s->vdev, &s->vring)) { + return; + } /* Try to issue the ioctl() directly for speed */ if (likely(virtio_queue_try_notify_from_thread(s->vq))) { @@ -307,10 +305,10 @@ static bool handle_notify(EventHandler *handler) for (;;) { /* Disable guest->host notifies to avoid unnecessary vmexits */ - vring_disable_cb(&s->vring); + vring_set_notification(&s->vdev, &s->vring, false); for (;;) { - head = vring_pop(&s->vring, iov, end, &out_num, &in_num); + head = vring_pop(&s->vdev, &s->vring, iov, end, &out_num, &in_num); if (head < 0) { break; /* no more requests */ } @@ -327,7 +325,9 @@ static bool handle_notify(EventHandler *handler) /* Re-enable guest->host notifies and stop processing the vring. * But if the guest has snuck in more descriptors, keep processing. */ - if (likely(vring_enable_cb(&s->vring))) { + vring_set_notification(&s->vdev, &s->vring, true); + __sync_synchronize(); /* smp_mb() */ + if (!vring_more_avail(&s->vring)) { break; } } else { /* head == -ENOBUFS, cannot continue since iovecs[] is depleted */