aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2020-07-02 02:51:58 +0100
committerMichael Brown <mcb30@ipxe.org>2020-07-02 03:06:50 +0100
commit5d6fb7282966e3b77e6bb187d171511e8348c3c9 (patch)
tree2c718322b3017cf9c485a79fc56bd4c82e7100e1
parentd5874c9f2b9c62b2d87b6c1cfafd61ef3d8cc67a (diff)
downloadipxe-5d6fb7282966e3b77e6bb187d171511e8348c3c9.zip
ipxe-5d6fb7282966e3b77e6bb187d171511e8348c3c9.tar.gz
ipxe-5d6fb7282966e3b77e6bb187d171511e8348c3c9.tar.bz2
[usb] Clear device endpoint halt before resetting host endpoint
Resetting the host endpoint may immediately restart any pending transfers for that endpoint. If the device endpoint halt has not yet been cleared, then this will probably result in a second failed transfer. This second failure may be detected within usb_endpoint_reset() while waiting for usb_clear_feature() to complete. The endpoint will subsequently be removed from the list of halted endpoints, causing the second failure to be effectively ignored and leaving the host endpoint in a permanently halted state. Fix by deferring the host endpoint reset until after the device endpoint is ready to accept new transfers. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/drivers/bus/usb.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c
index d8db384..d18751c 100644
--- a/src/drivers/bus/usb.c
+++ b/src/drivers/bus/usb.c
@@ -405,13 +405,6 @@ static int usb_endpoint_reset ( struct usb_endpoint *ep ) {
/* Sanity check */
assert ( ! list_empty ( &ep->halted ) );
- /* Reset endpoint */
- if ( ( rc = ep->host->reset ( ep ) ) != 0 ) {
- DBGC ( usb, "USB %s %s could not reset: %s\n",
- usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
- return rc;
- }
-
/* Clear transaction translator, if applicable */
if ( ( rc = usb_endpoint_clear_tt ( ep ) ) != 0 )
return rc;
@@ -427,6 +420,13 @@ static int usb_endpoint_reset ( struct usb_endpoint *ep ) {
return rc;
}
+ /* Reset endpoint */
+ if ( ( rc = ep->host->reset ( ep ) ) != 0 ) {
+ DBGC ( usb, "USB %s %s could not reset: %s\n",
+ usb->name, usb_endpoint_name ( ep ), strerror ( rc ) );
+ return rc;
+ }
+
/* Remove from list of halted endpoints */
list_del ( &ep->halted );
INIT_LIST_HEAD ( &ep->halted );