From 13fcbb9d8c0a3919aafaf839ac392c049c726229 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 17 Nov 2011 10:23:00 +0100 Subject: [PATCH] usb-uhci: fix race against host controller While processing a frame, the host controller will write to the queue head's element link field. The following sequence could then happen when two consecutive sends occur to the same pipe. controller SeaBIOS --------------------------------------------------------------------- td->link = UHCI_PTR_TERM; td->ctrl |= TD_CTRL_ACTIVE; read TD from memory wait_td(td); td->ctrl &= ~TD_CTRL_ACTIVE; write back td->ctrl exit usb_send_bulk restart usb_send_bulk pipe->qh.element = &tds; pipe->qh.element = td->link; ... go on and set up the first td ... write back pipe->qh.element td->ctrl |= TD_CTRL_ACTIVE; Once the host controller has written UHCI_PTR_TERM to the element link, subsequent tds would never be processed. This is surprisingly frequent when the two consecutive sends are in the OUT direction (and just as surprisingly, it seems like it never happens in the IN direction). To fix this, at the end of the processing do not wait for each single TD to become inactive, but for the host controller to invalidate the element link (which implies it's done with all TDs). Signed-off-by: Paolo Bonzini --- src/usb-uhci.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/usb-uhci.c b/src/usb-uhci.c index 4702695..242f3ba 100644 --- a/src/usb-uhci.c +++ b/src/usb-uhci.c @@ -483,16 +483,8 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) data += transfer; datasize -= transfer; } - int i; - for (i=0; itoggle, !!toggle); - return 0; + return wait_pipe(pipe, 5000); fail: dprintf(1, "uhci_send_bulk failed\n"); SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM); -- 2.25.1