Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

virtio_ring: Make interrupt suppression spec compliant

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>
Cc: <stable@vger.kernel.org> # f277ec4 virtio_ring: shadow available
Cc: <stable@vger.kernel.org>
Signed-off-by: Ladi Prosek <lprosek@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Ladi Prosek and committed by
Michael S. Tsirkin
0ea1e4a6 a0be1db4

+9 -5
+9 -5
drivers/virtio/virtio_ring.c
··· 732 732 733 733 if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) { 734 734 vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; 735 - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); 735 + if (!vq->event) 736 + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); 736 737 } 737 738 738 739 } ··· 765 764 * entry. Always do both to keep code simple. */ 766 765 if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { 767 766 vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; 768 - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); 767 + if (!vq->event) 768 + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); 769 769 } 770 770 vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx); 771 771 END_USE(vq); ··· 834 832 * more to do. */ 835 833 /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to 836 834 * either clear the flags bit or point the event index at the next 837 - * entry. Always do both to keep code simple. */ 835 + * entry. Always update the event index to keep code simple. */ 838 836 if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { 839 837 vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; 840 - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); 838 + if (!vq->event) 839 + vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); 841 840 } 842 841 /* TODO: tune this threshold */ 843 842 bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4; ··· 956 953 /* No callback? Tell other side not to bother us. */ 957 954 if (!callback) { 958 955 vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; 959 - vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow); 956 + if (!vq->event) 957 + vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow); 960 958 } 961 959 962 960 /* Put everything in free lists. */