Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5c262c5 authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by Rusty Russell
Browse files

virtio_ring: support event idx feature



Support for the new event idx feature:
1. When enabling interrupts, publish the current avail index
   value to the host to get interrupts on the next update.
2. Use the new avail_event feature to reduce the number
   of exits from the guest.

Simple test with the simulator:

[virtio]# time ./virtio_test
spurious wakeus: 0x7

real    0m0.169s
user    0m0.140s
sys     0m0.019s
[virtio]# time ./virtio_test --no-event-idx
spurious wakeus: 0x11

real    0m0.649s
user    0m0.295s
sys     0m0.335s

Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent bf7035bf
Loading
Loading
Loading
Loading
+24 −2
Original line number Original line Diff line number Diff line
@@ -82,6 +82,9 @@ struct vring_virtqueue
	/* Host supports indirect buffers */
	/* Host supports indirect buffers */
	bool indirect;
	bool indirect;


	/* Host publishes avail event idx */
	bool event;

	/* Number of free buffers */
	/* Number of free buffers */
	unsigned int num_free;
	unsigned int num_free;
	/* Head of free buffer list. */
	/* Head of free buffer list. */
@@ -237,18 +240,22 @@ EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
void virtqueue_kick(struct virtqueue *_vq)
void virtqueue_kick(struct virtqueue *_vq)
{
{
	struct vring_virtqueue *vq = to_vvq(_vq);
	struct vring_virtqueue *vq = to_vvq(_vq);
	u16 new, old;
	START_USE(vq);
	START_USE(vq);
	/* Descriptors and available array need to be set before we expose the
	/* Descriptors and available array need to be set before we expose the
	 * new available array entries. */
	 * new available array entries. */
	virtio_wmb();
	virtio_wmb();


	vq->vring.avail->idx += vq->num_added;
	old = vq->vring.avail->idx;
	new = vq->vring.avail->idx = old + vq->num_added;
	vq->num_added = 0;
	vq->num_added = 0;


	/* Need to update avail index before checking if we should notify */
	/* Need to update avail index before checking if we should notify */
	virtio_mb();
	virtio_mb();


	if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
	if (vq->event ?
	    vring_need_event(vring_avail_event(&vq->vring), new, old) :
	    !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
		/* Prod other side to tell it about changes. */
		/* Prod other side to tell it about changes. */
		vq->notify(&vq->vq);
		vq->notify(&vq->vq);


@@ -324,6 +331,14 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
	ret = vq->data[i];
	ret = vq->data[i];
	detach_buf(vq, i);
	detach_buf(vq, i);
	vq->last_used_idx++;
	vq->last_used_idx++;
	/* If we expect an interrupt for the next entry, tell host
	 * by writing event index and flush out the write before
	 * the read in the next get_buf call. */
	if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
		vring_used_event(&vq->vring) = vq->last_used_idx;
		virtio_mb();
	}

	END_USE(vq);
	END_USE(vq);
	return ret;
	return ret;
}
}
@@ -345,7 +360,11 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)


	/* We optimistically turn back on interrupts, then check if there was
	/* We optimistically turn back on interrupts, then check if there was
	 * more to do. */
	 * more to do. */
	/* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
	 * either clear the flags bit or point the event index at the next
	 * entry. Always do both to keep code simple. */
	vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
	vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
	vring_used_event(&vq->vring) = vq->last_used_idx;
	virtio_mb();
	virtio_mb();
	if (unlikely(more_used(vq))) {
	if (unlikely(more_used(vq))) {
		END_USE(vq);
		END_USE(vq);
@@ -438,6 +457,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
#endif
#endif


	vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
	vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
	vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);


	/* No callback?  Tell other side not to bother us. */
	/* No callback?  Tell other side not to bother us. */
	if (!callback)
	if (!callback)
@@ -472,6 +492,8 @@ void vring_transport_features(struct virtio_device *vdev)
		switch (i) {
		switch (i) {
		case VIRTIO_RING_F_INDIRECT_DESC:
		case VIRTIO_RING_F_INDIRECT_DESC:
			break;
			break;
		case VIRTIO_RING_F_EVENT_IDX:
			break;
		default:
		default:
			/* We don't understand this bit. */
			/* We don't understand this bit. */
			clear_bit(i, vdev->features);
			clear_bit(i, vdev->features);