From dd0ef128669c29734a197ca9195e7ab64e20ba2c Mon Sep 17 00:00:00 2001 From: Ake Koomsin Date: Wed, 20 Jul 2022 20:13:03 +0900 Subject: [PATCH 1/3] e1000e: Fix possible interrupt loss when using MSI Commit "e1000e: Prevent MSI/MSI-X storms" introduced msi_causes_pending to prevent interrupt storms problem. It was tested with MSI-X. In case of MSI, the guest can rely solely on interrupts to clear ICR. Upon clearing all pending interrupts, msi_causes_pending gets cleared. However, when e1000e_itr_should_postpone() in e1000e_send_msi() returns true, MSI never gets fired by e1000e_intrmgr_on_throttling_timer() because msi_causes_pending is still set. This results in interrupt loss. To prevent this, we need to clear msi_causes_pending when MSI is going to get fired by the throttling timer. The guest can then receive interrupts eventually. Signed-off-by: Ake Koomsin Signed-off-by: Jason Wang --- hw/net/e1000e_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 2c51089a82..208e3e0d79 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -159,6 +159,8 @@ e1000e_intrmgr_on_throttling_timer(void *opaque) if (msi_enabled(timer->core->owner)) { trace_e1000e_irq_msi_notify_postponed(); + /* Clear msi_causes_pending to fire MSI eventually */ + timer->core->msi_causes_pending = 0; e1000e_set_interrupt_cause(timer->core, 0); } else { trace_e1000e_irq_legacy_notify_postponed(); From 2fdac348fd3d243bb964937236af3cc27ae7af2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Mon, 18 Jul 2022 14:05:45 +0200 Subject: [PATCH 2/3] vhost: Get vring base from vq, not svq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SVQ vring used idx usually match with the guest visible one, as long as all the guest buffers (GPA) maps to exactly one buffer within qemu's VA. However, as we can see in virtqueue_map_desc, a single guest buffer could map to many buffers in SVQ vring. Also, its also a mistake to rewind them at the source of migration. Since VirtQueue is able to migrate the inflight descriptors, its responsability of the destination to perform the rewind just in case it cannot report the inflight descriptors to the device. This makes easier to migrate between backends or to recover them in vhost devices that support set in flight descriptors. Fixes: 6d0b22266633 ("vdpa: Adapt vhost_vdpa_get_vring_base to SVQ") Signed-off-by: Eugenio Pérez Signed-off-by: Jason Wang --- hw/virtio/vhost-vdpa.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 291cd19054..bce64f45c2 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -1179,7 +1179,18 @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { struct vhost_vdpa *v = dev->opaque; + VirtQueue *vq = virtio_get_queue(dev->vdev, ring->index); + /* + * vhost-vdpa devices does not support in-flight requests. Set all of them + * as available. + * + * TODO: This is ok for networking, but other kinds of devices might + * have problems with these retransmissions. + */ + while (virtqueue_rewind(vq, 1)) { + continue; + } if (v->shadow_vqs_enabled) { /* * Device vring base was set at device start. SVQ base is handled by @@ -1195,21 +1206,10 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev, struct vhost_vring_state *ring) { struct vhost_vdpa *v = dev->opaque; - int vdpa_idx = ring->index - dev->vq_index; int ret; if (v->shadow_vqs_enabled) { - VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx); - - /* - * Setting base as last used idx, so destination will see as available - * all the entries that the device did not use, including the in-flight - * processing ones. - * - * TODO: This is ok for networking, but other kinds of devices might - * have problems with these retransmissions. - */ - ring->num = svq->last_used_idx; + ring->num = virtio_queue_get_last_avail_idx(dev->vdev, ring->index); return 0; } From 75a8ce64f6e37513698857fb4284170da163ed06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Fri, 22 Jul 2022 10:26:30 +0200 Subject: [PATCH 3/3] vdpa: Fix memory listener deletions of iova tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vhost_vdpa_listener_region_del is always deleting the first iova entry of the tree, since it's using the needle iova instead of the result's one. This was detected using a vga virtual device in the VM using vdpa SVQ. It makes some extra memory adding and deleting, so the wrong one was mapped / unmapped. This was undetected before since all the memory was mappend and unmapped totally without that device, but other conditions could trigger it too: * mem_region was with .iova = 0, .translated_addr = (correct GPA). * iova_tree_find_iova returned right result, but does not update mem_region. * iova_tree_remove always removed region with .iova = 0. Right iova were sent to the device. * Next map will fill the first region with .iova = 0, causing a mapping with the same iova and device complains, if the next action is a map. * Next unmap will cause to try to unmap again iova = 0, causing the device to complain that no region was mapped at iova = 0. Fixes: 34e3c94edaef ("vdpa: Add custom IOTLB translations to SVQ") Reported-by: Lei Yang Signed-off-by: Eugenio Pérez Signed-off-by: Jason Wang --- hw/virtio/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index bce64f45c2..3ff9ce3501 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -290,7 +290,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener, result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region); iova = result->iova; - vhost_iova_tree_remove(v->iova_tree, &mem_region); + vhost_iova_tree_remove(v->iova_tree, result); } vhost_vdpa_iotlb_batch_begin_once(v); ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize));