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 | } |
