diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 38704111be..79b5c369a2 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -87,8 +87,8 @@ struct VirtQueue /* Last used index value we have signalled on */ bool signalled_used_valid; - /* Notification enabled? */ - bool notification; + /* Nested host->guest notification disabled counter */ + unsigned int notification_disabled; uint16_t queue_index; @@ -201,7 +201,7 @@ static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) { hwaddr pa; - if (!vq->notification) { + if (vq->notification_disabled) { return; } pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]); @@ -210,7 +210,13 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) void virtio_queue_set_notification(VirtQueue *vq, int enable) { - vq->notification = enable; + if (enable) { + assert(vq->notification_disabled > 0); + vq->notification_disabled--; + } else { + vq->notification_disabled++; + } + if (virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) { vring_set_avail_event(vq, vring_avail_idx(vq)); } else if (enable) { @@ -959,7 +965,7 @@ void virtio_reset(void *opaque) virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR); vdev->vq[i].signalled_used = 0; vdev->vq[i].signalled_used_valid = false; - vdev->vq[i].notification = true; + vdev->vq[i].notification_disabled = 0; vdev->vq[i].vring.num = vdev->vq[i].vring.num_default; vdev->vq[i].inuse = 0; } @@ -1770,7 +1776,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) vdev->vq[i].vring.desc = qemu_get_be64(f); qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); vdev->vq[i].signalled_used_valid = false; - vdev->vq[i].notification = true; + vdev->vq[i].notification_disabled = 0; if (vdev->vq[i].vring.desc) { /* XXX virtio-1 devices */