| From 0ea1e4a6d9b62cf29e210d2b4ba9fd43917522e3 Mon Sep 17 00:00:00 2001 |
| From: Ladi Prosek <lprosek@redhat.com> |
| Date: Wed, 31 Aug 2016 14:00:04 +0200 |
| Subject: virtio_ring: Make interrupt suppression spec compliant |
| |
| From: Ladi Prosek <lprosek@redhat.com> |
| |
| commit 0ea1e4a6d9b62cf29e210d2b4ba9fd43917522e3 upstream. |
| |
| According to the spec, if the VIRTIO_RING_F_EVENT_IDX feature bit is |
| negotiated the driver MUST set flags to 0. Not dirtying the available |
| ring in virtqueue_disable_cb also has a minor positive performance |
| impact, improving L1 dcache load missed by ~0.5% in vring_bench. |
| |
| Writes to the used event field (vring_used_event) are still unconditional. |
| |
| Cc: Michael S. Tsirkin <mst@redhat.com> |
| Signed-off-by: Ladi Prosek <lprosek@redhat.com> |
| Signed-off-by: Michael S. Tsirkin <mst@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/virtio/virtio_ring.c | 14 +++++++++----- |
| 1 file changed, 9 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/virtio/virtio_ring.c |
| +++ b/drivers/virtio/virtio_ring.c |
| @@ -732,7 +732,8 @@ void virtqueue_disable_cb(struct virtque |
| |
| if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) { |
| vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; |
| - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); |
| + if (!vq->event) |
| + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); |
| } |
| |
| } |
| @@ -764,7 +765,8 @@ unsigned virtqueue_enable_cb_prepare(str |
| * entry. Always do both to keep code simple. */ |
| if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { |
| vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; |
| - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); |
| + if (!vq->event) |
| + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); |
| } |
| vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx); |
| END_USE(vq); |
| @@ -832,10 +834,11 @@ bool virtqueue_enable_cb_delayed(struct |
| * more to do. */ |
| /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to |
| * either clear the flags bit or point the event index at the next |
| - * entry. Always do both to keep code simple. */ |
| + * entry. Always update the event index to keep code simple. */ |
| if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { |
| vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; |
| - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); |
| + if (!vq->event) |
| + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); |
| } |
| /* TODO: tune this threshold */ |
| bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4; |
| @@ -953,7 +956,8 @@ struct virtqueue *__vring_new_virtqueue( |
| /* No callback? Tell other side not to bother us. */ |
| if (!callback) { |
| vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; |
| - vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow); |
| + if (!vq->event) |
| + vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow); |
| } |
| |
| /* Put everything in free lists. */ |