[U-Boot] [PATCH] usb: fix usb start problem with SMSC USB hub and Toshiba USB stick

Anatolij Gustschin
2010-08-31T18:45:14Z

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);
--
1.7.0.4