From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: netdev@vger.kernel.org
Cc: jasowang@redhat.com, mst@redhat.com,
Willem de Bruijn <willemb@google.com>
Subject: [PATCH net-next RFC 3/4] vhost: interrupt coalescing support
Date: Fri, 3 Mar 2017 09:39:08 -0500 [thread overview]
Message-ID: <20170303143909.80001-4-willemdebruijn.kernel@gmail.com> (raw)
In-Reply-To: <20170303143909.80001-1-willemdebruijn.kernel@gmail.com>
From: Willem de Bruijn <willemb@google.com>
Implement standard interrupt coalescing for vhost based drivers,
delaying interrupts up to a maximum latency or number of events.
Interrupt moderation is customary for network devices, where it
is specified as ethtool -K $DEV rx-frames N rx-usecs M. Add the
same variable to vhost and integrate into vhost_notify. Add a
timer to track the time bound.
The feature is configured from the guest over PCI. Add new control
operations VHOST_SET_VRING_COALESCE and VHOST_GET_VRING_COALESCE to
communicate these features between the hypervisor and vhost.
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
drivers/vhost/vhost.c | 76 +++++++++++++++++++++++++++++++++++++++++++++-
drivers/vhost/vhost.h | 12 ++++++++
include/uapi/linux/vhost.h | 11 +++++++
3 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 4269e621e254..55711f5ce2ae 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -312,6 +312,9 @@ static void vhost_vq_reset(struct vhost_dev *dev,
vq->busyloop_timeout = 0;
vq->umem = NULL;
vq->iotlb = NULL;
+ vq->max_coalesce_ktime = 0;
+ vq->max_coalesce_frames = 0;
+ vq->coalesce_frames = 0;
}
static int vhost_worker(void *data)
@@ -394,6 +397,22 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev)
vhost_vq_free_iovecs(dev->vqs[i]);
}
+void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq);
+static enum hrtimer_restart vhost_coalesce_timer(struct hrtimer *timer)
+{
+ struct vhost_virtqueue *vq =
+ container_of(timer, struct vhost_virtqueue, ctimer);
+
+ if (mutex_trylock(&vq->mutex)) {
+ vq->coalesce_frames = vq->max_coalesce_frames;
+ vhost_signal(vq->dev, vq);
+ mutex_unlock(&vq->mutex);
+ }
+
+ /* TODO: restart if lock failed and not held by handle_tx */
+ return HRTIMER_NORESTART;
+}
+
void vhost_dev_init(struct vhost_dev *dev,
struct vhost_virtqueue **vqs, int nvqs)
{
@@ -423,6 +442,8 @@ void vhost_dev_init(struct vhost_dev *dev,
vq->heads = NULL;
vq->dev = dev;
mutex_init(&vq->mutex);
+ hrtimer_init(&vq->ctimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ vq->ctimer.function = vhost_coalesce_timer;
vhost_vq_reset(dev, vq);
if (vq->handle_kick)
vhost_poll_init(&vq->poll, vq->handle_kick,
@@ -608,6 +629,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
int i;
for (i = 0; i < dev->nvqs; ++i) {
+ hrtimer_cancel(&dev->vqs[i]->ctimer);
if (dev->vqs[i]->error_ctx)
eventfd_ctx_put(dev->vqs[i]->error_ctx);
if (dev->vqs[i]->error)
@@ -1279,6 +1301,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
struct vhost_vring_state s;
struct vhost_vring_file f;
struct vhost_vring_addr a;
+ struct vhost_vring_coalesce c;
u32 idx;
long r;
@@ -1335,6 +1358,30 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
if (copy_to_user(argp, &s, sizeof s))
r = -EFAULT;
break;
+ case VHOST_SET_VRING_COALESCE:
+ if (copy_from_user(&c, argp, sizeof(c))) {
+ r = -EFAULT;
+ break;
+ }
+
+ if ((c.max_coalesce_frames && !c.max_coalesce_usecs) ||
+ (c.max_coalesce_usecs && !c.max_coalesce_frames) ||
+ (c.max_coalesce_usecs > 10000) ||
+ (c.max_coalesce_frames > 1024)) {
+ r = -EINVAL;
+ break;
+ }
+
+ vq->max_coalesce_ktime = ns_to_ktime(c.max_coalesce_usecs *
+ NSEC_PER_USEC);
+ vq->max_coalesce_frames = c.max_coalesce_frames;
+ break;
+ case VHOST_GET_VRING_COALESCE:
+ c.max_coalesce_usecs = ktime_to_us(vq->max_coalesce_ktime);
+ c.max_coalesce_frames = vq->max_coalesce_frames;
+ if (copy_to_user(argp, &c, sizeof(c)))
+ r = -EFAULT;
+ break;
case VHOST_SET_VRING_ADDR:
if (copy_from_user(&a, argp, sizeof a)) {
r = -EFAULT;
@@ -1418,6 +1465,11 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
break;
}
if (eventfp != vq->call) {
+ /* do not update while timer is active */
+ if (hrtimer_active(&vq->ctimer)) {
+ hrtimer_cancel(&vq->ctimer);
+ vhost_signal(vq->dev, vq);
+ }
filep = vq->call;
ctx = vq->call_ctx;
vq->call = eventfp;
@@ -2112,6 +2164,10 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
* signals at least once in 2^16 and remove this. */
if (unlikely((u16)(new - vq->signalled_used) < (u16)(new - old)))
vq->signalled_used_valid = false;
+
+ if (vq->max_coalesce_frames)
+ vq->coalesce_frames += count;
+
return 0;
}
@@ -2152,6 +2208,14 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
}
EXPORT_SYMBOL_GPL(vhost_add_used_n);
+static void vhost_coalesce_reset(struct vhost_virtqueue *vq)
+{
+ if (vq->max_coalesce_frames) {
+ vq->coalesce_frames = 0;
+ hrtimer_try_to_cancel(&vq->ctimer);
+ }
+}
+
static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
__u16 old, new;
@@ -2162,6 +2226,14 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
unlikely(vq->avail_idx == vq->last_avail_idx))
return true;
+ if (vq->coalesce_frames < vq->max_coalesce_frames) {
+ if (!hrtimer_active(&vq->ctimer))
+ hrtimer_start(&vq->ctimer, vq->max_coalesce_ktime,
+ HRTIMER_MODE_REL);
+ return false;
+ }
+ vhost_coalesce_reset(vq);
+
if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
__virtio16 flags;
/* Flush out used index updates. This is paired
@@ -2208,8 +2280,10 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
/* Signal the Guest tell them we used something up. */
- if (vq->call_ctx && vhost_notify(dev, vq))
+ if (vq->call_ctx && vhost_notify(dev, vq)) {
eventfd_signal(vq->call_ctx, 1);
+ vhost_coalesce_reset(vq);
+ }
}
EXPORT_SYMBOL_GPL(vhost_signal);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index a9cbbb148f46..cee25f376812 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -119,6 +119,18 @@ struct vhost_virtqueue {
/* Last used index value we have signalled on */
bool signalled_used_valid;
+ /* Maximum time to wait before genearting an interrupt */
+ ktime_t max_coalesce_ktime;
+
+ /* Maximum number of pending frames before generating an interrupt */
+ u32 max_coalesce_frames;
+
+ /* The number of frames pending an interrupt */
+ u32 coalesce_frames;
+
+ /* Timer used to trigger an coalesced interrupt */
+ struct hrtimer ctimer;
+
/* Log writes to used structure. */
bool log_used;
u64 log_addr;
diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h
index 60180c0b5dc6..a0f9e2b1545a 100644
--- a/include/uapi/linux/vhost.h
+++ b/include/uapi/linux/vhost.h
@@ -27,6 +27,11 @@ struct vhost_vring_file {
};
+struct vhost_vring_coalesce {
+ __u32 max_coalesce_usecs;
+ __u32 max_coalesce_frames;
+};
+
struct vhost_vring_addr {
unsigned int index;
/* Option flags. */
@@ -143,6 +148,12 @@ struct vhost_memory {
#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state)
#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+/* Set coalescing parameters for the ring. */
+#define VHOST_SET_VRING_COALESCE _IOW(VHOST_VIRTIO, 0x15, \
+ struct vhost_vring_coalesce)
+/* Get coalescing parameters for the ring. */
+#define VHOST_GET_VRING_COALESCE _IOW(VHOST_VIRTIO, 0x16, \
+ struct vhost_vring_coalesce)
/* The following ioctls use eventfd file descriptors to signal and poll
* for events. */
--
2.12.0.rc1.440.g5b76565f74-goog
next prev parent reply other threads:[~2017-03-03 14:47 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-03-03 14:39 [PATCH net-next RFC 0/4] virtio-net tx napi Willem de Bruijn
2017-03-03 14:39 ` [PATCH net-next RFC 1/4] virtio-net: napi helper functions Willem de Bruijn
2017-03-03 14:39 ` [PATCH net-next RFC 2/4] virtio-net: transmit napi Willem de Bruijn
2017-03-06 9:21 ` Jason Wang
2017-03-06 17:50 ` Willem de Bruijn
2017-03-06 18:55 ` David Miller
2017-03-06 19:33 ` Michael S. Tsirkin
2017-03-06 19:43 ` Willem de Bruijn
2017-03-03 14:39 ` Willem de Bruijn [this message]
2017-03-06 9:28 ` [PATCH net-next RFC 3/4] vhost: interrupt coalescing support Jason Wang
2017-03-06 17:31 ` Willem de Bruijn
2017-03-08 3:25 ` Jason Wang
2017-03-03 14:39 ` [PATCH net-next RFC 4/4] virtio-net: clean tx descriptors from rx napi Willem de Bruijn
2017-03-06 9:34 ` Jason Wang
2017-03-06 17:43 ` Willem de Bruijn
2017-03-06 18:04 ` Willem de Bruijn
2017-03-06 19:44 ` [PATCH net-next RFC 0/4] virtio-net tx napi Michael S. Tsirkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170303143909.80001-4-willemdebruijn.kernel@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=jasowang@redhat.com \
--cc=mst@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.