aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio/virtio_ring.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2012-01-12 00:14:43 -0500
committerRusty Russell <rusty@rustcorp.com.au>2012-01-12 00:14:43 -0500
commitee7cd8981e15bcb365fc762afe3fc47b8242f630 (patch)
treedd680789368f78aae6fcfb521fe55d868eff3b5f /drivers/virtio/virtio_ring.c
parent3b720b8c865098c49c1570b6b5c7832bcfa6e6c2 (diff)
virtio: expose added descriptors immediately.
A virtio driver does virtqueue_add_buf() multiple times before finally calling virtqueue_kick(); previously we only exposed the added buffers in the virtqueue_kick() call. This means we don't need a memory barrier in virtqueue_add_buf(), but it reduces concurrency as the device (ie. host) can't see the buffers until the kick. In the unusual (but now possible) case where a driver does add_buf() and get_buf() without doing a kick, we do need to insert one before our counter wraps. Otherwise we could wrap num_added, and later on not realize that we have passed the marker where we should have kicked. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/virtio/virtio_ring.c')
-rw-r--r--drivers/virtio/virtio_ring.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 99dc9480f3fe..36bb6a613728 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -251,9 +251,20 @@ add_head:
251 251
252 /* Put entry in available array (but don't update avail->idx until they 252 /* Put entry in available array (but don't update avail->idx until they
253 * do sync). */ 253 * do sync). */
254 avail = ((vq->vring.avail->idx + vq->num_added++) & (vq->vring.num-1)); 254 avail = (vq->vring.avail->idx & (vq->vring.num-1));
255 vq->vring.avail->ring[avail] = head; 255 vq->vring.avail->ring[avail] = head;
256 256
257 /* Descriptors and available array need to be set before we expose the
258 * new available array entries. */
259 virtio_wmb(vq);
260 vq->vring.avail->idx++;
261 vq->num_added++;
262
263 /* This is very unlikely, but theoretically possible. Kick
264 * just in case. */
265 if (unlikely(vq->num_added == (1 << 16) - 1))
266 virtqueue_kick(_vq);
267
257 pr_debug("Added buffer head %i to %p\n", head, vq); 268 pr_debug("Added buffer head %i to %p\n", head, vq);
258 END_USE(vq); 269 END_USE(vq);
259 270
@@ -283,13 +294,10 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq)
283 * new available array entries. */ 294 * new available array entries. */
284 virtio_wmb(vq); 295 virtio_wmb(vq);
285 296
286 old = vq->vring.avail->idx; 297 old = vq->vring.avail->idx - vq->num_added;
287 new = vq->vring.avail->idx = old + vq->num_added; 298 new = vq->vring.avail->idx;
288 vq->num_added = 0; 299 vq->num_added = 0;
289 300
290 /* Need to update avail index before checking if we should notify */
291 virtio_mb(vq);
292
293 if (vq->event) { 301 if (vq->event) {
294 needs_kick = vring_need_event(vring_avail_event(&vq->vring), 302 needs_kick = vring_need_event(vring_avail_event(&vq->vring),
295 new, old); 303 new, old);