forked from Minki/linux
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: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
bf7035bf20
commit
a5c262c5fd
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user