
Checking the status field of the qTD token in the current code do not take into acount cases where endpoint stall (halted) bit is set together with some other status bits. As a result clearing stall on an endpoint won't be done if other status bits were set.
E.g. 'usb start' often fails with Toshiba USB stick 0x930/0x6545 connected to the SMSC USB 2.0 hub 0x424/0x2514. Debugging the issue showed that while bulk IN transfers with length of 13 or 18 the status field of the qTD token sometimes indicates trans- action error (XactErr) and sometimes additionally endpoint halted state. In the latter case resetting the USB device in error recovery code fails as no clear stall request on the endpoint will be done. The patch fixes status field checking code to properly handle endpoint halted state.
However this fix is not enough to solve 'usb start' problem with hub/stick combination mentioned above. Running with lot of debug code in ehci_submit_async() I've never seen the problem with usb stick recognition. After removing this debug code the similar problem sometimes showed up again. Therefore the patch also adds delay in ehci_submit_async() for above-mentioned hub/stick combination. Even without this delay the fix is an improvement since it fixes the problem with board freezy after subsequent failed 'usb start/stop' cycles as it was observed on mpc5121ads board.
Signed-off-by: Anatolij Gustschin agust@denx.de --- common/usb_storage.c | 5 +++-- drivers/usb/host/ehci-hcd.c | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/common/usb_storage.c b/common/usb_storage.c index 76949b8..5ca92c3 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -680,7 +680,8 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us) result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT * 5); /* special handling of STALL in DATA phase */ - if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { + if ((result < 0) && + (us->pusb_dev->status & (USB_ST_STALLED | USB_ST_CRC_ERR))) { USB_STOR_PRINTF("DATA:stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, @@ -710,7 +711,7 @@ again:
/* special handling of STALL in STATUS phase */ if ((result < 0) && (retry < 1) && - (us->pusb_dev->status & USB_ST_STALLED)) { + (us->pusb_dev->status & (USB_ST_STALLED | USB_ST_CRC_ERR))) { USB_STOR_PRINTF("STATUS:stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 37d056e..7463a75 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -430,6 +430,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, usbsts = ehci_readl(&hcor->or_usbsts); ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));
+ if (dev->descriptor.idVendor == 0x930 && + dev->descriptor.idProduct == 0x6545 && + dev->parent->descriptor.idVendor == 0x424 && + dev->parent->descriptor.idProduct == 0x2514) + wait_ms(10); + /* Enable async. schedule. */ cmd = ehci_readl(&hcor->or_usbcmd); cmd |= CMD_ASE; @@ -490,6 +496,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, break; default: dev->status = USB_ST_CRC_ERR; + if ((token & 0x40) == 0x40) + dev->status |= USB_ST_STALLED; break; } dev->act_len = length - ((token >> 16) & 0x7fff);