Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

virtio fix for 2.4

Fixes migration in virtio 1 mode.
We still have a known bug with memory hotplug, it doesn't
look like we can fix that in time for 2.4.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Wed 05 Aug 2015 15:57:39 BST using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"

* remotes/mst/tags/for_upstream:
  virtio: fix 1.0 virtqueue migration

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index ee4e07c..788b556 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1049,6 +1049,61 @@
     return (vdev->host_features >> 32) != 0;
 }
 
+static bool virtio_virtqueue_needed(void *opaque)
+{
+    VirtIODevice *vdev = opaque;
+
+    return virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1);
+}
+
+static void put_virtqueue_state(QEMUFile *f, void *pv, size_t size)
+{
+    VirtIODevice *vdev = pv;
+    int i;
+
+    for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+        qemu_put_be64(f, vdev->vq[i].vring.avail);
+        qemu_put_be64(f, vdev->vq[i].vring.used);
+    }
+}
+
+static int get_virtqueue_state(QEMUFile *f, void *pv, size_t size)
+{
+    VirtIODevice *vdev = pv;
+    int i;
+
+    for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+        vdev->vq[i].vring.avail = qemu_get_be64(f);
+        vdev->vq[i].vring.used = qemu_get_be64(f);
+    }
+    return 0;
+}
+
+static VMStateInfo vmstate_info_virtqueue = {
+    .name = "virtqueue_state",
+    .get = get_virtqueue_state,
+    .put = put_virtqueue_state,
+};
+
+static const VMStateDescription vmstate_virtio_virtqueues = {
+    .name = "virtio/virtqueues",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = &virtio_virtqueue_needed,
+    .fields = (VMStateField[]) {
+        {
+            .name         = "virtqueues",
+            .version_id   = 0,
+            .field_exists = NULL,
+            .size         = 0,
+            .info         = &vmstate_info_virtqueue,
+            .flags        = VMS_SINGLE,
+            .offset       = 0,
+        },
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_virtio_device_endian = {
     .name = "virtio/device_endian",
     .version_id = 1,
@@ -1082,6 +1137,7 @@
     .subsections = (const VMStateDescription*[]) {
         &vmstate_virtio_device_endian,
         &vmstate_virtio_64bit_features,
+        &vmstate_virtio_virtqueues,
         NULL
     }
 };
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 59f0763..cccae89 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -272,6 +272,12 @@
     return __virtio_has_feature(vdev->guest_features, fbit);
 }
 
+static inline bool virtio_host_has_feature(VirtIODevice *vdev,
+                                           unsigned int fbit)
+{
+    return __virtio_has_feature(vdev->host_features, fbit);
+}
+
 static inline bool virtio_is_big_endian(VirtIODevice *vdev)
 {
     if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {