aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2011-05-19 19:10:44 -0400
committerRusty Russell <rusty@rustcorp.com.au>2011-05-29 21:44:15 -0400
commita5c262c5fd83ece01bd649fb08416c501d4c59d7 (patch)
tree295ddc61d59236b6521f5587e2e78ccb8da5d97a /drivers
parentbf7035bf20563a6cadcb9e870406e7b21daf5e30 (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/virtio/virtio_ring.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index b0043fb26a4d..a5fadc40c448 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -82,6 +82,9 @@ struct vring_virtqueue
82 /* Host supports indirect buffers */ 82 /* Host supports indirect buffers */
83 bool indirect; 83 bool indirect;
84 84
85 /* Host publishes avail event idx */
86 bool event;
87
85 /* Number of free buffers */ 88 /* Number of free buffers */
86 unsigned int num_free; 89 unsigned int num_free;
87 /* Head of free buffer list. */ 90 /* Head of free buffer list. */
@@ -237,18 +240,22 @@ EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
237void virtqueue_kick(struct virtqueue *_vq) 240void virtqueue_kick(struct virtqueue *_vq)
238{ 241{
239 struct vring_virtqueue *vq = to_vvq(_vq); 242 struct vring_virtqueue *vq = to_vvq(_vq);
243 u16 new, old;
240 START_USE(vq); 244 START_USE(vq);
241 /* Descriptors and available array need to be set before we expose the 245 /* Descriptors and available array need to be set before we expose the
242 * new available array entries. */ 246 * new available array entries. */
243 virtio_wmb(); 247 virtio_wmb();
244 248
245 vq->vring.avail->idx += vq->num_added; 249 old = vq->vring.avail->idx;
250 new = vq->vring.avail->idx = old + vq->num_added;
246 vq->num_added = 0; 251 vq->num_added = 0;
247 252
248 /* Need to update avail index before checking if we should notify */ 253 /* Need to update avail index before checking if we should notify */
249 virtio_mb(); 254 virtio_mb();
250 255
251 if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY)) 256 if (vq->event ?
257 vring_need_event(vring_avail_event(&vq->vring), new, old) :
258 !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
252 /* Prod other side to tell it about changes. */ 259 /* Prod other side to tell it about changes. */
253 vq->notify(&vq->vq); 260 vq->notify(&vq->vq);
254 261
@@ -324,6 +331,14 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
324 ret = vq->data[i]; 331 ret = vq->data[i];
325 detach_buf(vq, i); 332 detach_buf(vq, i);
326 vq->last_used_idx++; 333 vq->last_used_idx++;
334 /* If we expect an interrupt for the next entry, tell host
335 * by writing event index and flush out the write before
336 * the read in the next get_buf call. */
337 if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
338 vring_used_event(&vq->vring) = vq->last_used_idx;
339 virtio_mb();
340 }
341
327 END_USE(vq); 342 END_USE(vq);
328 return ret; 343 return ret;
329} 344}
@@ -345,7 +360,11 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
345 360
346 /* We optimistically turn back on interrupts, then check if there was 361 /* We optimistically turn back on interrupts, then check if there was
347 * more to do. */ 362 * more to do. */
363 /* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
364 * either clear the flags bit or point the event index at the next
365 * entry. Always do both to keep code simple. */
348 vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; 366 vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
367 vring_used_event(&vq->vring) = vq->last_used_idx;
349 virtio_mb(); 368 virtio_mb();
350 if (unlikely(more_used(vq))) { 369 if (unlikely(more_used(vq))) {
351 END_USE(vq); 370 END_USE(vq);
@@ -438,6 +457,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
438#endif 457#endif
439 458
440 vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC); 459 vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
460 vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
441 461
442 /* No callback? Tell other side not to bother us. */ 462 /* No callback? Tell other side not to bother us. */
443 if (!callback) 463 if (!callback)
@@ -472,6 +492,8 @@ void vring_transport_features(struct virtio_device *vdev)
472 switch (i) { 492 switch (i) {
473 case VIRTIO_RING_F_INDIRECT_DESC: 493 case VIRTIO_RING_F_INDIRECT_DESC:
474 break; 494 break;
495 case VIRTIO_RING_F_EVENT_IDX:
496 break;
475 default: 497 default:
476 /* We don't understand this bit. */ 498 /* We don't understand this bit. */
477 clear_bit(i, vdev->features); 499 clear_bit(i, vdev->features);