diff options
Diffstat (limited to 'drivers/virtio/virtio_ring.c')
-rw-r--r-- | drivers/virtio/virtio_ring.c | 59 |
1 files changed, 52 insertions, 7 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index fbd2ecde93e4..0db906b3c95d 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c | |||
@@ -21,6 +21,24 @@ | |||
21 | #include <linux/virtio_config.h> | 21 | #include <linux/virtio_config.h> |
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | 23 | ||
24 | /* virtio guest is communicating with a virtual "device" that actually runs on | ||
25 | * a host processor. Memory barriers are used to control SMP effects. */ | ||
26 | #ifdef CONFIG_SMP | ||
27 | /* Where possible, use SMP barriers which are more lightweight than mandatory | ||
28 | * barriers, because mandatory barriers control MMIO effects on accesses | ||
29 | * through relaxed memory I/O windows (which virtio does not use). */ | ||
30 | #define virtio_mb() smp_mb() | ||
31 | #define virtio_rmb() smp_rmb() | ||
32 | #define virtio_wmb() smp_wmb() | ||
33 | #else | ||
34 | /* We must force memory ordering even if guest is UP since host could be | ||
35 | * running on another CPU, but SMP barriers are defined to barrier() in that | ||
36 | * configuration. So fall back to mandatory barriers instead. */ | ||
37 | #define virtio_mb() mb() | ||
38 | #define virtio_rmb() rmb() | ||
39 | #define virtio_wmb() wmb() | ||
40 | #endif | ||
41 | |||
24 | #ifdef DEBUG | 42 | #ifdef DEBUG |
25 | /* For development, we want to crash whenever the ring is screwed. */ | 43 | /* For development, we want to crash whenever the ring is screwed. */ |
26 | #define BAD_RING(_vq, fmt, args...) \ | 44 | #define BAD_RING(_vq, fmt, args...) \ |
@@ -36,10 +54,9 @@ | |||
36 | panic("%s:in_use = %i\n", \ | 54 | panic("%s:in_use = %i\n", \ |
37 | (_vq)->vq.name, (_vq)->in_use); \ | 55 | (_vq)->vq.name, (_vq)->in_use); \ |
38 | (_vq)->in_use = __LINE__; \ | 56 | (_vq)->in_use = __LINE__; \ |
39 | mb(); \ | ||
40 | } while (0) | 57 | } while (0) |
41 | #define END_USE(_vq) \ | 58 | #define END_USE(_vq) \ |
42 | do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0) | 59 | do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; } while(0) |
43 | #else | 60 | #else |
44 | #define BAD_RING(_vq, fmt, args...) \ | 61 | #define BAD_RING(_vq, fmt, args...) \ |
45 | do { \ | 62 | do { \ |
@@ -221,13 +238,13 @@ static void vring_kick(struct virtqueue *_vq) | |||
221 | START_USE(vq); | 238 | START_USE(vq); |
222 | /* Descriptors and available array need to be set before we expose the | 239 | /* Descriptors and available array need to be set before we expose the |
223 | * new available array entries. */ | 240 | * new available array entries. */ |
224 | wmb(); | 241 | virtio_wmb(); |
225 | 242 | ||
226 | vq->vring.avail->idx += vq->num_added; | 243 | vq->vring.avail->idx += vq->num_added; |
227 | vq->num_added = 0; | 244 | vq->num_added = 0; |
228 | 245 | ||
229 | /* Need to update avail index before checking if we should notify */ | 246 | /* Need to update avail index before checking if we should notify */ |
230 | mb(); | 247 | virtio_mb(); |
231 | 248 | ||
232 | if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY)) | 249 | if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY)) |
233 | /* Prod other side to tell it about changes. */ | 250 | /* Prod other side to tell it about changes. */ |
@@ -286,7 +303,7 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len) | |||
286 | } | 303 | } |
287 | 304 | ||
288 | /* Only get used array entries after they have been exposed by host. */ | 305 | /* Only get used array entries after they have been exposed by host. */ |
289 | rmb(); | 306 | virtio_rmb(); |
290 | 307 | ||
291 | i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id; | 308 | i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id; |
292 | *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len; | 309 | *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len; |
@@ -324,7 +341,7 @@ static bool vring_enable_cb(struct virtqueue *_vq) | |||
324 | /* We optimistically turn back on interrupts, then check if there was | 341 | /* We optimistically turn back on interrupts, then check if there was |
325 | * more to do. */ | 342 | * more to do. */ |
326 | vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; | 343 | vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; |
327 | mb(); | 344 | virtio_mb(); |
328 | if (unlikely(more_used(vq))) { | 345 | if (unlikely(more_used(vq))) { |
329 | END_USE(vq); | 346 | END_USE(vq); |
330 | return false; | 347 | return false; |
@@ -334,6 +351,30 @@ static bool vring_enable_cb(struct virtqueue *_vq) | |||
334 | return true; | 351 | return true; |
335 | } | 352 | } |
336 | 353 | ||
354 | static void *vring_detach_unused_buf(struct virtqueue *_vq) | ||
355 | { | ||
356 | struct vring_virtqueue *vq = to_vvq(_vq); | ||
357 | unsigned int i; | ||
358 | void *buf; | ||
359 | |||
360 | START_USE(vq); | ||
361 | |||
362 | for (i = 0; i < vq->vring.num; i++) { | ||
363 | if (!vq->data[i]) | ||
364 | continue; | ||
365 | /* detach_buf clears data, so grab it now. */ | ||
366 | buf = vq->data[i]; | ||
367 | detach_buf(vq, i); | ||
368 | END_USE(vq); | ||
369 | return buf; | ||
370 | } | ||
371 | /* That should have freed everything. */ | ||
372 | BUG_ON(vq->num_free != vq->vring.num); | ||
373 | |||
374 | END_USE(vq); | ||
375 | return NULL; | ||
376 | } | ||
377 | |||
337 | irqreturn_t vring_interrupt(int irq, void *_vq) | 378 | irqreturn_t vring_interrupt(int irq, void *_vq) |
338 | { | 379 | { |
339 | struct vring_virtqueue *vq = to_vvq(_vq); | 380 | struct vring_virtqueue *vq = to_vvq(_vq); |
@@ -360,6 +401,7 @@ static struct virtqueue_ops vring_vq_ops = { | |||
360 | .kick = vring_kick, | 401 | .kick = vring_kick, |
361 | .disable_cb = vring_disable_cb, | 402 | .disable_cb = vring_disable_cb, |
362 | .enable_cb = vring_enable_cb, | 403 | .enable_cb = vring_enable_cb, |
404 | .detach_unused_buf = vring_detach_unused_buf, | ||
363 | }; | 405 | }; |
364 | 406 | ||
365 | struct virtqueue *vring_new_virtqueue(unsigned int num, | 407 | struct virtqueue *vring_new_virtqueue(unsigned int num, |
@@ -406,8 +448,11 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, | |||
406 | /* Put everything in free lists. */ | 448 | /* Put everything in free lists. */ |
407 | vq->num_free = num; | 449 | vq->num_free = num; |
408 | vq->free_head = 0; | 450 | vq->free_head = 0; |
409 | for (i = 0; i < num-1; i++) | 451 | for (i = 0; i < num-1; i++) { |
410 | vq->vring.desc[i].next = i+1; | 452 | vq->vring.desc[i].next = i+1; |
453 | vq->data[i] = NULL; | ||
454 | } | ||
455 | vq->data[i] = NULL; | ||
411 | 456 | ||
412 | return &vq->vq; | 457 | return &vq->vq; |
413 | } | 458 | } |