diff options
| -rw-r--r-- | drivers/virtio/virtio_ring.c | 26 |
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); | |||
| 237 | void virtqueue_kick(struct virtqueue *_vq) | 240 | void 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); |
