[U-Boot] [PATCH] Fix to make U-Boot work with more USB sticks
Simon Glass
sjg at chromium.org
Thu Dec 16 23:14:14 CET 2010
Hi Remy,
Thanks for the feedback. I will update the patch with your changes.
Unfortunately I don't have a lot of hardware to try, hence the list post. I
will be doing some more testing in January so will come back to it then. In
the meantime I am interested in views as to whether this makes a difference
on OHCI, different ARM chips, etc.
Regards,
Simon
On Sat, Dec 11, 2010 at 9:51 AM, Remy Bohmer <linux at bohmer.net> wrote:
> Hi Simon,
>
> 2010/12/10 Simon Glass <sjg at chromium.org>:
> > I am sending this to the list looking for comments. Testing has been
> > confined to just a few USB sticks - no USB hard drives, USB card
> > readers, etc. But there are reports on the mailing list of problems
> > with U-Boot's detection of USB mass storage devices.
>
> First impression is that it looks interesting, however I have a few
> remarks, see below.
>
> > This patch:
> >
> > 1. Increases the USB descriptor submission timeout to 3 seconds since the
> > original 1 second timeout seems arbitrary
> >
> > 2. Replaces the delay-based reset logic with logic which waits until it
> > sees the reset is successful, rather than blindly continuing
> >
> > 3. Resets and retries a USB mass storage device after it fails once, in
> > case even 3 seconds is not enough
>
> Can you please split this patch up to multiple patches, each solving a
> different issue?
>
> > BUG=chromiumos-6780
> > TEST=tried with four different USB sticks, including two which previously
> > failed
> > Change-Id: I5bd8891bff67a74b758e349f2a3b3575806eed59
> >
> > Signed-off-by: Simon Glass <sjg at chromium.org>
> > ---
> > common/usb.c | 176
> ++++++++++++++++++++++++++++++++++++-------
> > common/usb_storage.c | 55 +++++++++++---
> > drivers/usb/host/ehci-hcd.c | 20 ++++-
> > include/usb.h | 11 +++
> > 4 files changed, 217 insertions(+), 45 deletions(-)
> >
> > diff --git a/common/usb.c b/common/usb.c
> > index 9896f46..3265d5d 100644
> > --- a/common/usb.c
> > +++ b/common/usb.c
> > @@ -222,10 +222,14 @@ int usb_control_msg(struct usb_device *dev,
> unsigned int pipe,
> > int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
> > void *data, int len, int *actual_length, int
> timeout)
> > {
> > + int err;
> > +
> > if (len < 0)
> > return -1;
> > dev->status = USB_ST_NOT_PROC; /*not yet processed */
> > - submit_bulk_msg(dev, pipe, data, len);
> > + err = submit_bulk_msg(dev, pipe, data, len);
> > + if (err < 0)
> > + return err;
>
> Seems you only focused on the ehci-hcd driver. How does this change in
> behaviour impact other host controller drivers like, for example,
> ohci?
> Is any regression in those drivers possible or to be expected?
>
> >
> > -static int hub_port_reset(struct usb_device *dev, int port,
> > - unsigned short *portstat)
> > +/* brought this in from kernel 2.6.36 as it is a problem area. Some USB
> > +sticks do not operate properly with the previous reset code */
>
> Multi line comments should be written like
> /*
> * comment line 1
> * comment line 2
> */
> Please fix globally.
>
> > +#define PORT_RESET_TRIES 5
> > +#define SET_ADDRESS_TRIES 2
> > +#define GET_DESCRIPTOR_TRIES 2
> > +#define SET_CONFIG_TRIES (2 * (use_both_schemes + 1))
> > +#define USE_NEW_SCHEME(i) ((i) / 2 == old_scheme_first)
> > +
>
> > +#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
> > +#define HUB_SHORT_RESET_TIME 10
> > +#define HUB_LONG_RESET_TIME 200
> > +#define HUB_RESET_TIMEOUT 500
>
> How are these times estimated? Are these magic, or is there a deeper
> thought behind them?
>
> > +
> > +#define ENOTCONN 107
> > +
> > +static int hub_port_wait_reset(struct usb_device *dev, int port,
> > + unsigned int delay, unsigned short
> *portstatus_ret)
> > {
> > - int tries;
> > + int delay_time, ret;
> > struct usb_port_status portsts;
> > unsigned short portstatus, portchange;
> >
> > - USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port);
> > - for (tries = 0; tries < MAX_TRIES; tries++) {
> > -
> > - usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET);
> > - wait_ms(200);
> > + for (delay_time = 0;
> > + delay_time < HUB_RESET_TIMEOUT;
>
> You go from a 200msec timeout to a 500msec timeout. Is there a special
> reason for this?
>
> > + delay_time += delay) {
> > + /* wait to give the device a chance to reset */
> > + wait_ms(delay);
>
> The ' delay' argument of this routine is misleading since it does not
> specify a delay time, but the time between 2 polls on
> usb_get_port_status().
> The maximum delay is specified by HUB_RESET_TIMEOUT here.
>
> >
> > - if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
> > + /* read and decode port status */
> > + ret = usb_get_port_status(dev, port + 1, &portsts);
> > + if (ret < 0) {
> > USB_HUB_PRINTF("get_port_status failed status
> %lX\n",
> > dev->status);
> > - return -1;
> > + return ret;
> > }
> > portstatus = le16_to_cpu(portsts.wPortStatus);
> > portchange = le16_to_cpu(portsts.wPortChange);
> >
> > - USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
> > - portstatus, portchange,
> > - portspeed(portstatus));
> > + /* Device went away? */
> > + if (!(portstatus & USB_PORT_STAT_CONNECTION))
> > + return -ENOTCONN;
> >
> > - USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION =
> %d" \
> > - " USB_PORT_STAT_ENABLE %d\n",
> > - (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 :
> 0,
> > - (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0,
> > - (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0);
> > + /* bomb out completely if the connection bounced */
> > + if ((portchange & USB_PORT_STAT_C_CONNECTION))
> > + return -ENOTCONN;
> >
> > - if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
> > - !(portstatus & USB_PORT_STAT_CONNECTION))
> > - return -1;
> > + /* if we`ve finished resetting, then break out of the
> loop */
> > + if (!(portstatus & USB_PORT_STAT_RESET) &&
> > + (portstatus & USB_PORT_STAT_ENABLE)) {
> > + *portstatus_ret = portstatus;
> > + return 0;
> > + }
> >
> > - if (portstatus & USB_PORT_STAT_ENABLE)
> > - break;
> > + /* switch to the long delay after two short delay
> failures */
> > + if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
> > + delay = HUB_LONG_RESET_TIME;
>
> You are changing the 'delay' routine argument here. Why even specify
> it on the argument list if:
> * it does not do what to expect.
> * it gets overridden anyway.
>
> > + /* root hub ports have a slightly longer reset period
> > + * (from USB 2.0 spec, section 7.1.7.5)
> > + */
>
> wrong style multiline comment.
>
> > + if (!dev->parent) {
> > + delay = HUB_ROOT_RESET_TIME;
> > + }
>
> No parenthesis required.
>
> > - wait_ms(200);
> > + /* Some low speed devices have problems with the quick delay, so
> */
> > + /* be a bit pessimistic with those devices. RHbug #23670 */
>
> Multiline comment
>
> > + /* TRSTRCY = 10 ms; plus some extra */
>
> magic plus some extra magic...
>
> > diff --git a/common/usb_storage.c b/common/usb_storage.c
> > index 76949b8..0fb9c1b 100644
> > --- a/common/usb_storage.c
> > +++ b/common/usb_storage.c
> > @@ -158,9 +158,10 @@ struct us_data {
> > static struct us_data usb_stor[USB_MAX_STOR_DEV];
> >
> >
> > +/* start our error numbers after the USB ones */
> > #define USB_STOR_TRANSPORT_GOOD 0
> > -#define USB_STOR_TRANSPORT_FAILED -1
> > -#define USB_STOR_TRANSPORT_ERROR -2
> > +#define USB_STOR_TRANSPORT_FAILED (USB_ENEXTFREE)
> > +#define USB_STOR_TRANSPORT_ERROR (USB_ENEXTFREE-1)
>
> Weird way to define error codes...
> Please make it clearer without magic ids that needs to match magically
> to some ids in a header file (USB_ENEXTFREE = -3) (enum?)
>
> > int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
> > block_dev_desc_t *dev_desc);
> > @@ -213,6 +214,7 @@ int usb_stor_scan(int mode)
> > {
> > unsigned char i;
> > struct usb_device *dev;
> > + int result;
> >
> > /* GJ */
> > memset(usb_stor_buf, 0, sizeof(usb_stor_buf));
> > @@ -244,8 +246,21 @@ int usb_stor_scan(int mode)
> > /* ok, it is a storage devices
> > * get info and fill it in
> > */
>
> Bad style multiline comment
>
> > - if (usb_stor_get_info(dev,
> &usb_stor[usb_max_devs],
> > -
> &usb_dev_desc[usb_max_devs]) == 1)
> > + result = usb_stor_get_info(dev,
> &usb_stor[usb_max_devs],
> > +
> &usb_dev_desc[usb_max_devs]);
> > + if (result == USB_EDEVCRITICAL) {
>
> You are changing the behaviour for the ehci host controller only
> (since that one only knows USB_EDEVCRITICAL)
> Please make it suitable for all other host controller drivers as well,
> or patch those drivers also.
> The problems you are trying to fix are not likely to be for ehci only,
> since you modify generic code...
>
> > + /*
> > + * Something there, but failed badly.
> > + * Retry one more time. This happens
> > + * sometimes with some USB sticks,
> > + * e.g. Patriot Rage ID 13fe:3800
> > + */
> > + printf (".");
> > + usb_restart_device(dev); /* ignore
> return value */
> > + result = usb_stor_get_info(dev,
> &usb_stor[usb_max_devs],
> > +
> &usb_dev_desc[usb_max_devs]);
> > + }
> > + if (result == 1)
>
> Would a switch case or ' else if' not be nicer?
>
> > static int usb_request_sense(ccb *srb, struct us_data *ss)
> > {
> > + int result;
> > char *ptr;
> >
> > ptr = (char *)srb->pdata;
> > @@ -909,7 +928,12 @@ static int usb_request_sense(ccb *srb, struct
> us_data *ss)
> > srb->datalen = 18;
> > srb->pdata = &srb->sense_buf[0];
> > srb->cmdlen = 12;
> > - ss->transport(srb, ss);
> > + result = ss->transport(srb, ss);
> > + if (result < 0) {
> > + if (result != USB_EDEVCRITICAL)
> > + USB_STOR_PRINTF("Request Sense failed\n");
> > + return result;
>
> You are changing behaviour for ALL host controller driver types here.
> Are you sure you want this? (Better: again... please fix all
> drivers...)
>
> > + }
> > USB_STOR_PRINTF("Request Sense returned %02X %02X %02X\n",
> > srb->sense_buf[2], srb->sense_buf[12],
> > srb->sense_buf[13]);
>
> > @@ -1372,11 +1400,14 @@ int usb_stor_get_info(struct usb_device *dev,
> struct us_data *ss,
> > #endif /* CONFIG_USB_BIN_FIXUP */
> > USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",
> usb_stor_buf[2],
> > usb_stor_buf[3]);
> > - if (usb_test_unit_ready(pccb, ss)) {
> > + result = usb_test_unit_ready(pccb, ss);
> > + if (result) {
> > + if (result == USB_EDEVCRITICAL)
> > + return result;
>
> Please fix all drivers...
>
> > printf("Device NOT ready\n"
> > - " Request Sense returned %02X %02X %02X\n",
> > - pccb->sense_buf[2], pccb->sense_buf[12],
> > - pccb->sense_buf[13]);
> > + " Request Sense returned %02X %02X %02X\n",
> > + pccb->sense_buf[2], pccb->sense_buf[12],
> > + pccb->sense_buf[13]);
> > if (dev_desc->removable == 1) {
> > dev_desc->type = perq;
> > return 1;
> > diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> > index 13cd84a..1143cd6 100644
> > --- a/drivers/usb/host/ehci-hcd.c
> > +++ b/drivers/usb/host/ehci-hcd.c
> > @@ -330,6 +330,7 @@ ehci_submit_async(struct usb_device *dev, unsigned
> long pipe, void *buffer,
> > uint32_t c, toggle;
> > uint32_t cmd;
> > int ret = 0;
> > + int result = USB_EFAIL;
> >
> > #ifdef CONFIG_USB_EHCI_DATA_ALIGN
> > /* In case ehci host requires alignment for buffers */
> > @@ -342,8 +343,8 @@ ehci_submit_async(struct usb_device *dev, unsigned
> long pipe, void *buffer,
> > if (!align_buf)
> > return -1;
> > if ((int)align_buf & (CONFIG_USB_EHCI_DATA_ALIGN - 1))
> > - buffer = (void *)((int)align_buf +
> > - CONFIG_USB_EHCI_DATA_ALIGN -
> > + buffer = (void *)((int)align_buf +
> > + CONFIG_USB_EHCI_DATA_ALIGN -
> > ((int)align_buf &
> (CONFIG_USB_EHCI_DATA_ALIGN - 1)));
> > else
> > buffer = align_buf;
> > @@ -475,7 +476,10 @@ ehci_submit_async(struct usb_device *dev, unsigned
> long pipe, void *buffer,
> > goto fail;
> > }
> >
> > - /* Wait for TDs to be processed. */
> > + /*
> > + * Wait for TDs to be processed. We wait 3s since some USB
> > + * sticks can take a long time immediately after system reset
> > + */
>
> Cool... This multiline comment is correct ;-)
>
> > ts = get_timer(0);
> > vtd = td;
> > do {
> > @@ -484,7 +488,7 @@ ehci_submit_async(struct usb_device *dev, unsigned
> long pipe, void *buffer,
> > token = hc32_to_cpu(vtd->qt_token);
> > if (!(token & 0x80))
> > break;
> > - } while (get_timer(ts) < CONFIG_SYS_HZ);
> > + } while (get_timer(ts) < CONFIG_SYS_HZ * 3);
>
> Same valid for other host controller drivers?
>
> >
> > /* Disable async schedule. */
> > cmd = ehci_readl(&hcor->or_usbcmd);
> > @@ -497,6 +501,12 @@ ehci_submit_async(struct usb_device *dev, unsigned
> long pipe, void *buffer,
> > printf("EHCI fail timeout STD_ASS reset\n");
> > goto fail;
> > }
> > + /* check that the TD processing happened */
> > + if (token & 0x80) {
> > + printf("EHCI timed out on TD - token=%#x\n", token);
> > + result = USB_EDEVCRITICAL;
> > + goto fail;
> > + }
>
> this one too...
>
> > qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list |
> QH_LINK_TYPE_QH);
> >
> > @@ -559,7 +569,7 @@ fail:
> > td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
> > }
> > ehci_free(qh, sizeof(*qh));
> > - return -1;
> > + return result;
> > }
> >
> > static inline int min3(int a, int b, int c)
> > diff --git a/include/usb.h b/include/usb.h
> > index afd65e3..91aa441 100644
> > --- a/include/usb.h
> > +++ b/include/usb.h
> > @@ -42,6 +42,16 @@
> >
> > #define USB_CNTL_TIMEOUT 100 /* 100ms timeout */
> >
> > +/*
> > + * Errors we can report, e.g. return USB_EDEVCRITICAL
> > + * Use -ve numbers to fit in with usb_storage
>
> Yak...
>
> > + * U-Boot needs some unified numbers
> > + */
> > +#define USB_EOK 0 /* ok, no error */
> > +#define USB_EFAIL -1 /* general failure(!) */
> > +#define USB_EDEVCRITICAL -2 /* must reset device on hub */
> > +#define USB_ENEXTFREE -3 /* next free error number */
> > +
> > /* device request (setup) */
> > struct devrequest {
> > unsigned char requesttype;
> > @@ -198,6 +208,7 @@ int usb_get_class_descriptor(struct usb_device *dev,
> int ifnum,
> > int usb_clear_halt(struct usb_device *dev, int pipe);
> > int usb_string(struct usb_device *dev, int index, char *buf, size_t
> size);
> > int usb_set_interface(struct usb_device *dev, int interface, int
> alternate);
> > +int usb_restart_device(struct usb_device *dev);
> >
> > /* big endian -> little endian conversion */
> > /* some CPUs are already little endian e.g. the ARM920T */
>
> Kind regards,
>
> Remy
>
More information about the U-Boot
mailing list