summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbryanv <bryanv@FreeBSD.org>2013-09-01 04:16:43 +0000
committerbryanv <bryanv@FreeBSD.org>2013-09-01 04:16:43 +0000
commitf175a1e7f9ee74ccf0005d916bdd3fc622355974 (patch)
tree04428f70dac94ec59e4e25ed5c69c4687625024c
parentee4b8e07a829f3d8f11cf458601290079e0ed62f (diff)
downloadFreeBSD-src-f175a1e7f9ee74ccf0005d916bdd3fc622355974.zip
FreeBSD-src-f175a1e7f9ee74ccf0005d916bdd3fc622355974.tar.gz
Add support for postponing VirtIO virtqueue interrupts
Partial support for the EVENT_IDX feature was added a while ago, but this commit adds an interface for the device driver to hint how long (in terms of descriptors) the next interrupt should be delayed. The first user of this will be used to reduce VirtIO net's Tx completion interrupts.
-rw-r--r--sys/dev/virtio/virtqueue.c32
-rw-r--r--sys/dev/virtio/virtqueue.h12
2 files changed, 32 insertions, 12 deletions
diff --git a/sys/dev/virtio/virtqueue.c b/sys/dev/virtio/virtqueue.c
index a82426e..beff14c 100644
--- a/sys/dev/virtio/virtqueue.c
+++ b/sys/dev/virtio/virtqueue.c
@@ -127,7 +127,7 @@ static uint16_t vq_ring_enqueue_segments(struct virtqueue *,
static int vq_ring_use_indirect(struct virtqueue *, int);
static void vq_ring_enqueue_indirect(struct virtqueue *, void *,
struct sglist *, int, int);
-static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t);
+static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t);
static int vq_ring_must_notify_host(struct virtqueue *);
static void vq_ring_notify_host(struct virtqueue *);
static void vq_ring_free_chain(struct virtqueue *, uint16_t);
@@ -440,28 +440,38 @@ virtqueue_enable_intr(struct virtqueue *vq)
}
int
-virtqueue_postpone_intr(struct virtqueue *vq)
+virtqueue_postpone_intr(struct virtqueue *vq, vq_postpone_t hint)
{
uint16_t ndesc, avail_idx;
- /*
- * Request the next interrupt be postponed until at least half
- * of the available descriptors have been consumed.
- */
avail_idx = vq->vq_ring.avail->idx;
- ndesc = (uint16_t)(avail_idx - vq->vq_used_cons_idx) / 2;
+ ndesc = (uint16_t)(avail_idx - vq->vq_used_cons_idx);
+
+ switch (hint) {
+ case VQ_POSTPONE_SHORT:
+ ndesc /= 4;
+ break;
+ case VQ_POSTPONE_LONG:
+ ndesc *= 3 / 4;
+ break;
+ case VQ_POSTPONE_EMPTIED:
+ break;
+ }
return (vq_ring_enable_interrupt(vq, ndesc));
}
+/*
+ * Note this is only considered a hint to the host.
+ */
void
virtqueue_disable_intr(struct virtqueue *vq)
{
- /*
- * Note this is only considered a hint to the host.
- */
- if ((vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) == 0)
+ if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) {
+ vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx -
+ vq->vq_nentries - 1;
+ } else
vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
}
diff --git a/sys/dev/virtio/virtqueue.h b/sys/dev/virtio/virtqueue.h
index 128a10a..0d4ed94 100644
--- a/sys/dev/virtio/virtqueue.h
+++ b/sys/dev/virtio/virtqueue.h
@@ -41,6 +41,16 @@ struct sglist;
/* Device callback for a virtqueue interrupt. */
typedef void virtqueue_intr_t(void *);
+/*
+ * Hint on how long the next interrupt should be postponed. This is
+ * only used when the EVENT_IDX feature is negotiated.
+ */
+typedef enum {
+ VQ_POSTPONE_SHORT,
+ VQ_POSTPONE_LONG,
+ VQ_POSTPONE_EMPTIED /* Until all available desc are used. */
+} vq_postpone_t;
+
#define VIRTQUEUE_MAX_NAME_SZ 32
/* One for each virtqueue the device wishes to allocate. */
@@ -73,7 +83,7 @@ int virtqueue_reinit(struct virtqueue *vq, uint16_t size);
int virtqueue_intr_filter(struct virtqueue *vq);
void virtqueue_intr(struct virtqueue *vq);
int virtqueue_enable_intr(struct virtqueue *vq);
-int virtqueue_postpone_intr(struct virtqueue *vq);
+int virtqueue_postpone_intr(struct virtqueue *vq, vq_postpone_t hint);
void virtqueue_disable_intr(struct virtqueue *vq);
/* Get physical address of the virtqueue ring. */
OpenPOWER on IntegriCloud