aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/block/dataplane/virtio-blk.c4
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c7
-rw-r--r--hw/scsi/virtio-scsi.c2
-rw-r--r--hw/virtio/trace-events2
-rw-r--r--hw/virtio/virtio.c36
5 files changed, 31 insertions, 20 deletions
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 90ef557c8c..d1f9f63eaf 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -68,9 +68,7 @@ static void notify_guest_bh(void *opaque)
unsigned i = j + ctzl(bits);
VirtQueue *vq = virtio_get_queue(s->vdev, i);
- if (virtio_should_notify(s->vdev, vq)) {
- event_notifier_set(virtio_queue_get_guest_notifier(vq));
- }
+ virtio_notify_irqfd(s->vdev, vq);
bits &= bits - 1; /* clear right-most bit */
}
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index f2ea29dbc3..6b8d0f0024 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -95,13 +95,6 @@ static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n,
return 0;
}
-void virtio_scsi_dataplane_notify(VirtIODevice *vdev, VirtIOSCSIReq *req)
-{
- if (virtio_should_notify(vdev, req->vq)) {
- event_notifier_set(virtio_queue_get_guest_notifier(req->vq));
- }
-}
-
/* assumes s->ctx held */
static void virtio_scsi_clear_aio(VirtIOSCSI *s)
{
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 3e5ae6ac0f..10fd687193 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -69,7 +69,7 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size);
virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size);
if (s->dataplane_started && !s->dataplane_fenced) {
- virtio_scsi_dataplane_notify(vdev, req);
+ virtio_notify_irqfd(vdev, vq);
} else {
virtio_notify(vdev, vq);
}
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 8756cefa79..7b6f55e70e 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -5,7 +5,7 @@ virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "
virtqueue_flush(void *vq, unsigned int count) "vq %p count %u"
virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "vq %p elem %p in_num %u out_num %u"
virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p"
-virtio_irq(void *vq) "vq %p"
+virtio_notify_irqfd(void *vdev, void *vq) "vdev %p vq %p"
virtio_notify(void *vdev, void *vq) "vdev %p vq %p"
virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u"
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 138a414cbe..1af2de2714 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1330,13 +1330,6 @@ static void virtio_set_isr(VirtIODevice *vdev, int value)
}
}
-void virtio_irq(VirtQueue *vq)
-{
- trace_virtio_irq(vq);
- virtio_set_isr(vq->vdev, 0x1);
- virtio_notify_vector(vq->vdev, vq->vector);
-}
-
bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
{
uint16_t old, new;
@@ -1360,6 +1353,33 @@ bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
return !v || vring_need_event(vring_get_used_event(vq), new, old);
}
+void virtio_notify_irqfd(VirtIODevice *vdev, VirtQueue *vq)
+{
+ if (!virtio_should_notify(vdev, vq)) {
+ return;
+ }
+
+ trace_virtio_notify_irqfd(vdev, vq);
+
+ /*
+ * virtio spec 1.0 says ISR bit 0 should be ignored with MSI, but
+ * windows drivers included in virtio-win 1.8.0 (circa 2015) are
+ * incorrectly polling this bit during crashdump and hibernation
+ * in MSI mode, causing a hang if this bit is never updated.
+ * Recent releases of Windows do not really shut down, but rather
+ * log out and hibernate to make the next startup faster. Hence,
+ * this manifested as a more serious hang during shutdown with
+ *
+ * Next driver release from 2016 fixed this problem, so working around it
+ * is not a must, but it's easy to do so let's do it here.
+ *
+ * Note: it's safe to update ISR from any thread as it was switched
+ * to an atomic operation.
+ */
+ virtio_set_isr(vq->vdev, 0x1);
+ event_notifier_set(&vq->guest_notifier);
+}
+
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
{
if (!virtio_should_notify(vdev, vq)) {
@@ -1994,7 +2014,7 @@ static void virtio_queue_guest_notifier_read(EventNotifier *n)
{
VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
if (event_notifier_test_and_clear(n)) {
- virtio_irq(vq);
+ virtio_notify_vector(vq->vdev, vq->vector);
}
}