From 3c3302a82a69e181b967a8bef2678d6250b42321 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Fri, 21 Sep 2012 18:57:37 -0300
Subject: [RHEL6 qemu-kvm PATCH 16/23] ehci: Walk async schedule before and
 after migration

RH-Author: Hans de Goede <hdegoede@redhat.com>
Message-id: <1348253864-3050-16-git-send-email-hdegoede@redhat.com>
Patchwork-id: 42191
O-Subject: [RHEL-6.4 qemu-kvm PATCH 15/22] ehci: Walk async schedule before and after migration
Bugzilla: 805172
RH-Acked-by: Uri Lublin <uril@redhat.com>
RH-Acked-by: Arnon Gilboa <agilboa@redhat.com>
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Upstream commit: ceab6f96454fe6589d1b09ce64403c041d79f9d9
Conflicts: hw/usb-ehci.c
---
 hw/usb-ehci.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/usb-ehci.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 0546d43..a52814b 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -28,6 +28,7 @@
 #include "pci.h"
 #include "monitor.h"
 #include "trace.h"
+#include "sysemu.h"
 
 #define EHCI_DEBUG   0
 
@@ -2287,6 +2288,32 @@ static int usb_ehci_post_load(void *opaque, int version_id)
     return 0;
 }
 
+static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
+{
+    EHCIState *ehci = opaque;
+
+    /*
+     * We don't migrate the EHCIQueue-s, instead we rebuild them for the
+     * schedule in guest memory. We must do the rebuilt ASAP, so that
+     * USB-devices which have async handled packages have a packet in the
+     * ep queue to match the completion with.
+     */
+    if (state == RUN_STATE_RUNNING) {
+        ehci_advance_async_state(ehci);
+    }
+
+    /*
+     * The schedule rebuilt from guest memory could cause the migration dest
+     * to miss a QH unlink, and fail to cancel packets, since the unlinked QH
+     * will never have existed on the destination. Therefor we must flush the
+     * async schedule on savevm to catch any not yet noticed unlinks.
+     */
+    if (state == RUN_STATE_SAVE_VM) {
+        ehci_advance_async_state(ehci);
+        ehci_queues_rip_unseen(ehci, 1);
+    }
+}
+
 static const VMStateDescription vmstate_ehci = {
     .name        = "ehci",
     .version_id  = 1,
@@ -2418,6 +2445,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
     QTAILQ_INIT(&s->pqueues);
 
     qemu_register_reset(ehci_reset, s);
+    qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
 
     s->mem = cpu_register_io_memory(ehci_readfn, ehci_writefn, s);
 
-- 
1.7.11.4

