aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/usb-uhci.c40
1 files changed, 28 insertions, 12 deletions
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 3231a3ec20..62c743d583 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -265,25 +265,41 @@ static void uhci_async_cancel_all(UHCIState *s)
static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token)
{
UHCIAsync *async = s->async_pending;
+ UHCIAsync *match = NULL;
+ int count = 0;
+
+ /*
+ * We're looking for the best match here. ie both td addr and token.
+ * Otherwise we return last good match. ie just token.
+ * It's ok to match just token because it identifies the transaction
+ * rather well, token includes: device addr, endpoint, size, etc.
+ *
+ * Also since we queue async transactions in reverse order by returning
+ * last good match we restores the order.
+ *
+ * It's expected that we wont have a ton of outstanding transactions.
+ * If we ever do we'd want to optimize this algorithm.
+ */
while (async) {
- if (async->td == addr) {
- if (async->token == token)
- return async;
-
- /*
- * TD was reused for a different transfer.
- * Invalidate the original one asap.
- */
- if (async->valid > 0) {
- async->valid = 0;
- dprintf("husb: bad reuse. td 0x%x\n", async->td);
+ if (async->token == token) {
+ /* Good match */
+ match = async;
+
+ if (async->td == addr) {
+ /* Best match */
+ break;
}
}
async = async->next;
+ count++;
}
- return NULL;
+
+ if (count > 64)
+ fprintf(stderr, "uhci: warning lots of async transactions\n");
+
+ return match;
}
static void uhci_attach(USBPort *port1, USBDevice *dev);