9ae3a8
From e25b1bfc8a6b74bf8474fe8d8e927abd1cacaa4f Mon Sep 17 00:00:00 2001
9ae3a8
From: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Date: Thu, 12 Sep 2013 09:39:30 +0200
9ae3a8
Subject: [PATCH 02/25] xhci: emulate intr endpoint intervals correctly
9ae3a8
9ae3a8
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
Message-id: <1378978772-21612-3-git-send-email-kraxel@redhat.com>
9ae3a8
Patchwork-id: 54337
9ae3a8
O-Subject: [RHEL-7 qemu-kvm PATCH 2/4] xhci: emulate intr endpoint intervals correctly
9ae3a8
Bugzilla: 1001604
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
RH-Acked-by: Hans de Goede <hdegoede@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
Respect the interval for interrupt endpoints, so we don't finish
9ae3a8
transfers as fast as possible but at the rate configured by the guest.
9ae3a8
9ae3a8
Fixes guest deadlocks triggered by interrupt storms.
9ae3a8
9ae3a8
Cc:
9ae3a8
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9ae3a8
(cherry picked from commit 4d7a81c06f5f17e019a2d3a18300500bd64f6f40)
9ae3a8
---
9ae3a8
 hw/usb/hcd-xhci.c | 44 +++++++++++++++++++++++++++++++++++++-------
9ae3a8
 1 file changed, 37 insertions(+), 7 deletions(-)
9ae3a8
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/usb/hcd-xhci.c |   44 +++++++++++++++++++++++++++++++++++++-------
9ae3a8
 1 files changed, 37 insertions(+), 7 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
9ae3a8
index 55bcfc4..ccf7cc5 100644
9ae3a8
--- a/hw/usb/hcd-xhci.c
9ae3a8
+++ b/hw/usb/hcd-xhci.c
9ae3a8
@@ -355,6 +355,7 @@ typedef struct XHCITransfer {
9ae3a8
     unsigned int streamid;
9ae3a8
     bool in_xfer;
9ae3a8
     bool iso_xfer;
9ae3a8
+    bool timed_xfer;
9ae3a8
 
9ae3a8
     unsigned int trb_count;
9ae3a8
     unsigned int trb_alloced;
9ae3a8
@@ -1787,6 +1788,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
9ae3a8
 
9ae3a8
     xfer->in_xfer = bmRequestType & USB_DIR_IN;
9ae3a8
     xfer->iso_xfer = false;
9ae3a8
+    xfer->timed_xfer = false;
9ae3a8
 
9ae3a8
     if (xhci_setup_packet(xfer) < 0) {
9ae3a8
         return -1;
9ae3a8
@@ -1802,6 +1804,17 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
9ae3a8
     return 0;
9ae3a8
 }
9ae3a8
 
9ae3a8
+static void xhci_calc_intr_kick(XHCIState *xhci, XHCITransfer *xfer,
9ae3a8
+                                XHCIEPContext *epctx, uint64_t mfindex)
9ae3a8
+{
9ae3a8
+    uint64_t asap = ((mfindex + epctx->interval - 1) &
9ae3a8
+                     ~(epctx->interval-1));
9ae3a8
+    uint64_t kick = epctx->mfindex_last + epctx->interval;
9ae3a8
+
9ae3a8
+    assert(epctx->interval != 0);
9ae3a8
+    xfer->mfindex_kick = MAX(asap, kick);
9ae3a8
+}
9ae3a8
+
9ae3a8
 static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
9ae3a8
                                XHCIEPContext *epctx, uint64_t mfindex)
9ae3a8
 {
9ae3a8
@@ -1824,8 +1837,8 @@ static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
-static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
9ae3a8
-                                XHCIEPContext *epctx, uint64_t mfindex)
9ae3a8
+static void xhci_check_intr_iso_kick(XHCIState *xhci, XHCITransfer *xfer,
9ae3a8
+                                     XHCIEPContext *epctx, uint64_t mfindex)
9ae3a8
 {
9ae3a8
     if (xfer->mfindex_kick > mfindex) {
9ae3a8
         qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock) +
9ae3a8
@@ -1850,18 +1863,30 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx
9ae3a8
     switch(epctx->type) {
9ae3a8
     case ET_INTR_OUT:
9ae3a8
     case ET_INTR_IN:
9ae3a8
+        xfer->pkts = 0;
9ae3a8
+        xfer->iso_xfer = false;
9ae3a8
+        xfer->timed_xfer = true;
9ae3a8
+        mfindex = xhci_mfindex_get(xhci);
9ae3a8
+        xhci_calc_intr_kick(xhci, xfer, epctx, mfindex);
9ae3a8
+        xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
9ae3a8
+        if (xfer->running_retry) {
9ae3a8
+            return -1;
9ae3a8
+        }
9ae3a8
+        break;
9ae3a8
     case ET_BULK_OUT:
9ae3a8
     case ET_BULK_IN:
9ae3a8
         xfer->pkts = 0;
9ae3a8
         xfer->iso_xfer = false;
9ae3a8
+        xfer->timed_xfer = false;
9ae3a8
         break;
9ae3a8
     case ET_ISO_OUT:
9ae3a8
     case ET_ISO_IN:
9ae3a8
         xfer->pkts = 1;
9ae3a8
         xfer->iso_xfer = true;
9ae3a8
+        xfer->timed_xfer = true;
9ae3a8
         mfindex = xhci_mfindex_get(xhci);
9ae3a8
         xhci_calc_iso_kick(xhci, xfer, epctx, mfindex);
9ae3a8
-        xhci_check_iso_kick(xhci, xfer, epctx, mfindex);
9ae3a8
+        xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
9ae3a8
         if (xfer->running_retry) {
9ae3a8
             return -1;
9ae3a8
         }
9ae3a8
@@ -1922,13 +1947,18 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
9ae3a8
 
9ae3a8
         trace_usb_xhci_xfer_retry(xfer);
9ae3a8
         assert(xfer->running_retry);
9ae3a8
-        if (xfer->iso_xfer) {
9ae3a8
-            /* retry delayed iso transfer */
9ae3a8
+        if (xfer->timed_xfer) {
9ae3a8
+            /* time to kick the transfer? */
9ae3a8
             mfindex = xhci_mfindex_get(xhci);
9ae3a8
-            xhci_check_iso_kick(xhci, xfer, epctx, mfindex);
9ae3a8
+            xhci_check_intr_iso_kick(xhci, xfer, epctx, mfindex);
9ae3a8
             if (xfer->running_retry) {
9ae3a8
                 return;
9ae3a8
             }
9ae3a8
+            xfer->timed_xfer = 0;
9ae3a8
+            xfer->running_retry = 1;
9ae3a8
+        }
9ae3a8
+        if (xfer->iso_xfer) {
9ae3a8
+            /* retry iso transfer */
9ae3a8
             if (xhci_setup_packet(xfer) < 0) {
9ae3a8
                 return;
9ae3a8
             }
9ae3a8
@@ -2014,7 +2044,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
9ae3a8
                 epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
9ae3a8
                 ep = xfer->packet.ep;
9ae3a8
             } else {
9ae3a8
-                if (!xfer->iso_xfer) {
9ae3a8
+                if (!xfer->timed_xfer) {
9ae3a8
                     fprintf(stderr, "xhci: error firing data transfer\n");
9ae3a8
                 }
9ae3a8
             }
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8