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