From a5488b93b57e8216684a0afe91c99157e993150d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 21 Sep 2012 18:57:32 -0300 Subject: [RHEL6 qemu-kvm PATCH 11/23] ehci: Schedule async-bh when IAAD bit gets set RH-Author: Hans de Goede Message-id: <1348253864-3050-11-git-send-email-hdegoede@redhat.com> Patchwork-id: 42186 O-Subject: [RHEL-6.4 qemu-kvm PATCH 10/22] ehci: Schedule async-bh when IAAD bit gets set Bugzilla: 805172 RH-Acked-by: Uri Lublin RH-Acked-by: Arnon Gilboa RH-Acked-by: Gerd Hoffmann After the "ehci: Print a warning when a queue unexpectedly contains packets on cancel" commit. Under certain reproducable conditions I was getting the following message: "EHCI: Warning queue not empty on queue reset". After aprox. 8 hours of debugging I've finally found the cause. The Linux EHCI driver has an IAAD watchdog, to work around certain EHCI hardware sometimes not acknowledging the doorbell at all. This watchdog has a timeout of 10 ms, which is less then the time between 2 runs through the async schedule when async_stepdown is at its highest value. Thus the watchdog can trigger, after which Linux clears the IAAD bit and re-uses the QH. IOW we were not properly detecting the unlink of the qh, due to us missing (ignoring for more then 10 ms) the IAAD command, which triggered the warning. RHEL-6: Since we don't have async_stepdown in RHEL-6, the chances of this happening in RHEL-6 are small, still we could hit this if we encounter > 10 ms latencies. Signed-off-by: Hans de Goede Upstream commit: a1c3e4b839f8e7ec7f1792b8a11c63ca845aa021 Conflicts: hw/usb-ehci.c --- hw/usb-ehci.c | 8 ++++++++ 1 file changed, 8 insertions(+) Signed-off-by: Eduardo Habkost --- hw/usb-ehci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index e5f6c78..22b106a 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -1064,6 +1064,14 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) ehci_set_usbsts(s, USBSTS_HALT); } + if ((val & USBCMD_IAAD) && (val & USBCMD_RUNSTOP)) { + /* + * Process IAAD immediately, otherwise the Linux IAAD watchdog may + * trigger and re-use a qh without us seeing the unlink. + */ + qemu_bh_schedule(s->async_bh); + } + /* not supporting dynamic frame list size at the moment */ if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { fprintf(stderr, "attempt to set frame list size -- value %d\n", -- 1.7.11.4