Re: [PATCH v3] USB: hub.c: decrease the number of attempts of enumeration scheme

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dear Alan,
I tested the patch you provided.
Unfortunately, it takes about 40 seconds to reach the detection of
enumeration failure. so the PET test failed.
Now I'm checking which procedure took time.
                     :
[   77.469035] hrtimer: interrupt took 23800 ns
[  737.812782] *** Connect  PET       ***
[  759.854355] *** Exec PET App       ***
[  763.300951] usb 1-1.1: new full-speed USB device number 4 using ehci-platform
[  763.301248] usb 1-1.1: device descriptor read/64, error -32
[  763.383966] usb 1-1.1: new full-speed USB device number 5 using ehci-platform
[  763.384256] usb 1-1.1: device descriptor read/64, error -32
[  763.390282] usb 1-1-port1: attempt power cycle
[  765.586566] usb 1-1-port1: unable to enumerate USB device [-107]
[  816.850692] *** Setting Test Suite ***
[  835.593181] *** Ready OK Test Start***
[  838.822953] usb 1-1.1: new full-speed USB device number 7 using
ehci-platform [1]---start---------
[  844.037032] usb 1-1.1: device descriptor read/64, error -110
          [2]....... [2]-[1] = 5.2 second
[  844.121947] usb 1-1.1: new full-speed USB device number 8 using ehci-platform
[  849.156628] usb 1-1.1: device descriptor read/64, error -110
          [3]....... [3]-[2] = 5.1 second
[  849.163971] usb 1-1-port1: attempt power cycle
[  851.102959] usb 1-1.1: new full-speed USB device number 9 using ehci-platform
[  856.325028] usb 1-1.1: device descriptor read/64, error -110
          [4]....... [4]-[3] = 7.2 second
[  856.409962] usb 1-1.1: new full-speed USB device number 10 using
ehci-platform
[  867.281957] usb 1-1.1: device not accepting address 10, error -110
          [5]....... [5]-[4] = 10.9 second
[  867.365954] usb 1-1.1: new full-speed USB device number 11 using
ehci-platform
[  878.545941] usb 1-1.1: device not accepting address 11, error -110
          [6]....... [6]-[5] = 11.2 second
[  878.552808] usb 1-1-port1: unable to enumerate USB device
          [7]  total [7]-[1] = 39.7 second
[  899.489808] *** End of Test        ***

2020年9月10日(木) 13:49 yasushi asano <yazzep@xxxxxxxxx>:
>
> Dear Alan
> Thank you for your kindness.
> I tried to minimize the amount of change so as not to affect other
> processing, but I understood that my fix was not appropriate.
> I'm testing the patch you offered using PET tool.
> Please wait a while.
>
> 2020年9月9日(水) 4:04 Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>:
> >
> > On Tue, Sep 08, 2020 at 12:50:52AM +0900, Yasushi Asano wrote:
> > > From: Yasushi Asano <yasano@xxxxxxxxxxxxxx>
> > >
> > > According to 6.7.22 A-UUT "Device No Response" for connection timeout
> > > of USB OTG and EH automated compliance plan v1.2, the enumeration
> > > failure has to be detected within 30 seconds. However, the old and new
> > > enumeration schemes made a total of 16 attempts, and each attempt can
> > > take 5 seconds to timeout, so it failed with PET test. Modify it to
> > > reduce the number of attempts to 5 and pass PET test.
> > >
> > > in case of old_schene_first=N and use_both_schemes=Y
> > > attempt 3 * new scheme, then 2 * old scheme
> > > in case of old_schene_first=Y and use_both_schemes=Y
> > > attempt 2 * old scheme, then 3 * new scheme
> >
> > There are several issues this patch does not take into account, such as
> > resets between retries and port-power cycling.  Also, you did not
> > restructure the code appropriately.
> >
> > Please review and test the patch below.  Does it do what you think it
> > should?
> >
> > Alan Stern
> >
> >
> > Index: usb-devel/drivers/usb/core/hub.c
> > ===================================================================
> > --- usb-devel.orig/drivers/usb/core/hub.c
> > +++ usb-devel/drivers/usb/core/hub.c
> > @@ -2707,9 +2707,7 @@ static unsigned hub_is_wusb(struct usb_h
> >
> >  #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, scheme)      ((i) / 2 == (int)(scheme))
> > +#define PORT_INIT_TRIES                5
> >
> >  #define HUB_ROOT_RESET_TIME    60      /* times are in msec */
> >  #define HUB_SHORT_RESET_TIME   10
> > @@ -2717,23 +2715,31 @@ static unsigned hub_is_wusb(struct usb_h
> >  #define HUB_LONG_RESET_TIME    200
> >  #define HUB_RESET_TIMEOUT      800
> >
> > -/*
> > - * "New scheme" enumeration causes an extra state transition to be
> > - * exposed to an xhci host and causes USB3 devices to receive control
> > - * commands in the default state.  This has been seen to cause
> > - * enumeration failures, so disable this enumeration scheme for USB3
> > - * devices.
> > - */
> >  static bool use_new_scheme(struct usb_device *udev, int retry,
> >                            struct usb_port *port_dev)
> >  {
> >         int old_scheme_first_port =
> > -               port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME;
> > +               (port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME) ||
> > +               old_scheme_first;
> >
> > +       /*
> > +        * "New scheme" enumeration causes an extra state transition to be
> > +        * exposed to an xhci host and causes USB3 devices to receive control
> > +        * commands in the default state.  This has been seen to cause
> > +        * enumeration failures, so disable this enumeration scheme for USB3
> > +        * devices.
> > +        */
> >         if (udev->speed >= USB_SPEED_SUPER)
> >                 return false;
> >
> > -       return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first);
> > +       /*
> > +        * If use_both_schemes is set, use the first scheme (whichever
> > +        * it is) for the larger half of the retries, then use the other
> > +        * scheme.  Otherwise, use the first scheme for all the retries.
> > +        */
> > +       if (use_both_schemes && retry >= (PORT_INIT_TRIES + 1) / 2)
> > +               return old_scheme_first_port;   /* Second half */
> > +       return !old_scheme_first_port;          /* First half or all */
> >  }
> >
> >  /* Is a USB 3.0 port in the Inactive or Compliance Mode state?
> > @@ -4539,12 +4545,13 @@ hub_port_init(struct usb_hub *hub, struc
> >         struct usb_device       *hdev = hub->hdev;
> >         struct usb_hcd          *hcd = bus_to_hcd(hdev->bus);
> >         struct usb_port         *port_dev = hub->ports[port1 - 1];
> > -       int                     retries, operations, retval, i;
> > +       int                     operations, retval, i;
> >         unsigned                delay = HUB_SHORT_RESET_TIME;
> >         enum usb_device_speed   oldspeed = udev->speed;
> >         const char              *speed;
> >         int                     devnum = udev->devnum;
> >         const char              *driver_name;
> > +       bool                    do_new_scheme;
> >
> >         /* root hub ports have a slightly longer reset period
> >          * (from USB 2.0 spec, section 7.1.7.5)
> > @@ -4657,130 +4664,106 @@ hub_port_init(struct usb_hub *hub, struc
> >          * first 8 bytes of the device descriptor to get the ep0 maxpacket
> >          * value.
> >          */
> > -       for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
> > -               bool did_new_scheme = false;
> > -
> > -               if (use_new_scheme(udev, retry_counter, port_dev)) {
> > -                       struct usb_device_descriptor *buf;
> > -                       int r = 0;
> > +       do_new_scheme = use_new_scheme(udev, retry_counter, port_dev);
> >
> > -                       did_new_scheme = true;
> > -                       retval = hub_enable_device(udev);
> > -                       if (retval < 0) {
> > -                               dev_err(&udev->dev,
> > -                                       "hub failed to enable device, error %d\n",
> > -                                       retval);
> > -                               goto fail;
> > -                       }
> > +       if (do_new_scheme) {
> > +               struct usb_device_descriptor *buf;
> > +               int r = 0;
> > +
> > +               retval = hub_enable_device(udev);
> > +               if (retval < 0) {
> > +                       dev_err(&udev->dev,
> > +                               "hub failed to enable device, error %d\n",
> > +                               retval);
> > +                       goto fail;
> > +               }
> >
> >  #define GET_DESCRIPTOR_BUFSIZE 64
> > -                       buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
> > -                       if (!buf) {
> > -                               retval = -ENOMEM;
> > -                               continue;
> > -                       }
> > +               buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
> > +               if (!buf) {
> > +                       retval = -ENOMEM;
> > +                       goto fail;
> > +               }
> >
> > -                       /* Retry on all errors; some devices are flakey.
> > -                        * 255 is for WUSB devices, we actually need to use
> > -                        * 512 (WUSB1.0[4.8.1]).
> > -                        */
> > -                       for (operations = 0; operations < 3; ++operations) {
> > -                               buf->bMaxPacketSize0 = 0;
> > -                               r = usb_control_msg(udev, usb_rcvaddr0pipe(),
> > -                                       USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
> > -                                       USB_DT_DEVICE << 8, 0,
> > -                                       buf, GET_DESCRIPTOR_BUFSIZE,
> > -                                       initial_descriptor_timeout);
> > -                               switch (buf->bMaxPacketSize0) {
> > -                               case 8: case 16: case 32: case 64: case 255:
> > -                                       if (buf->bDescriptorType ==
> > -                                                       USB_DT_DEVICE) {
> > -                                               r = 0;
> > -                                               break;
> > -                                       }
> > -                                       fallthrough;
> > -                               default:
> > -                                       if (r == 0)
> > -                                               r = -EPROTO;
> > -                                       break;
> > -                               }
> > -                               /*
> > -                                * Some devices time out if they are powered on
> > -                                * when already connected. They need a second
> > -                                * reset. But only on the first attempt,
> > -                                * lest we get into a time out/reset loop
> > -                                */
> > -                               if (r == 0 || (r == -ETIMEDOUT &&
> > -                                               retries == 0 &&
> > -                                               udev->speed > USB_SPEED_FULL))
> > -                                       break;
> > +               /*
> > +                * 255 is for WUSB devices, we actually need to use
> > +                * 512 (WUSB1.0[4.8.1]).
> > +                */
> > +               buf->bMaxPacketSize0 = 0;
> > +               r = usb_control_msg(udev, usb_rcvaddr0pipe(),
> > +                       USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
> > +                       USB_DT_DEVICE << 8, 0,
> > +                       buf, GET_DESCRIPTOR_BUFSIZE,
> > +                       initial_descriptor_timeout);
> > +               switch (buf->bMaxPacketSize0) {
> > +               case 8: case 16: case 32: case 64: case 255:
> > +                       if (buf->bDescriptorType == USB_DT_DEVICE) {
> > +                               r = 0;
> > +                               break;
> >                         }
> > -                       udev->descriptor.bMaxPacketSize0 =
> > -                                       buf->bMaxPacketSize0;
> > +                       fallthrough;
> > +               default:
> > +                       if (r == 0)
> > +                               r = -EPROTO;
> > +                       if (r != -ENODEV)
> > +                               dev_err(&udev->dev, "device descriptor read/64, error %d\n", r);
> > +                       retval = r;
> >                         kfree(buf);
> > +                       goto fail;
> > +               }
> > +               udev->descriptor.bMaxPacketSize0 = buf->bMaxPacketSize0;
> > +               kfree(buf);
> >
> > -                       retval = hub_port_reset(hub, port1, udev, delay, false);
> > -                       if (retval < 0)         /* error or disconnect */
> > -                               goto fail;
> > -                       if (oldspeed != udev->speed) {
> > -                               dev_dbg(&udev->dev,
> > -                                       "device reset changed speed!\n");
> > -                               retval = -ENODEV;
> > -                               goto fail;
> > -                       }
> > -                       if (r) {
> > -                               if (r != -ENODEV)
> > -                                       dev_err(&udev->dev, "device descriptor read/64, error %d\n",
> > -                                                       r);
> > -                               retval = -EMSGSIZE;
> > -                               continue;
> > -                       }
> > +               retval = hub_port_reset(hub, port1, udev, delay, false);
> > +               if (retval < 0)         /* error or disconnect */
> > +                       goto fail;
> > +               if (oldspeed != udev->speed) {
> > +                       dev_dbg(&udev->dev, "device reset changed speed!\n");
> > +                       retval = -ENODEV;
> > +                       goto fail;
> > +               }
> >  #undef GET_DESCRIPTOR_BUFSIZE
> > +       }
> > +
> > +       /*
> > +        * If device is WUSB, we already assigned an
> > +        * unauthorized address in the Connect Ack sequence;
> > +        * authorization will assign the final address.
> > +        */
> > +       if (udev->wusb == 0) {
> > +               for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
> > +                       retval = hub_set_address(udev, devnum);
> > +                       if (retval >= 0)
> > +                               break;
> > +                       msleep(200);
> > +               }
> > +               if (retval < 0) {
> > +                       if (retval != -ENODEV)
> > +                               dev_err(&udev->dev, "device not accepting address %d, error %d\n",
> > +                                               devnum, retval);
> > +                       goto fail;
> > +               }
> > +               if (udev->speed >= USB_SPEED_SUPER) {
> > +                       devnum = udev->devnum;
> > +                       dev_info(&udev->dev,
> > +                                       "%s SuperSpeed%s%s USB device number %d using %s\n",
> > +                                       (udev->config) ? "reset" : "new",
> > +                                (udev->speed == USB_SPEED_SUPER_PLUS) ?
> > +                                               "Plus Gen 2" : " Gen 1",
> > +                                (udev->rx_lanes == 2 && udev->tx_lanes == 2) ?
> > +                                               "x2" : "",
> > +                                devnum, driver_name);
> >                 }
> >
> >                 /*
> > -                * If device is WUSB, we already assigned an
> > -                * unauthorized address in the Connect Ack sequence;
> > -                * authorization will assign the final address.
> > +                * cope with hardware quirkiness:
> > +                *  - let SET_ADDRESS settle, some device hardware wants it
> > +                *  - read ep0 maxpacket even for high and low speed,
> >                  */
> > -               if (udev->wusb == 0) {
> > -                       for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
> > -                               retval = hub_set_address(udev, devnum);
> > -                               if (retval >= 0)
> > -                                       break;
> > -                               msleep(200);
> > -                       }
> > -                       if (retval < 0) {
> > -                               if (retval != -ENODEV)
> > -                                       dev_err(&udev->dev, "device not accepting address %d, error %d\n",
> > -                                                       devnum, retval);
> > -                               goto fail;
> > -                       }
> > -                       if (udev->speed >= USB_SPEED_SUPER) {
> > -                               devnum = udev->devnum;
> > -                               dev_info(&udev->dev,
> > -                                               "%s SuperSpeed%s%s USB device number %d using %s\n",
> > -                                               (udev->config) ? "reset" : "new",
> > -                                        (udev->speed == USB_SPEED_SUPER_PLUS) ?
> > -                                                       "Plus Gen 2" : " Gen 1",
> > -                                        (udev->rx_lanes == 2 && udev->tx_lanes == 2) ?
> > -                                                       "x2" : "",
> > -                                        devnum, driver_name);
> > -                       }
> > -
> > -                       /* cope with hardware quirkiness:
> > -                        *  - let SET_ADDRESS settle, some device hardware wants it
> > -                        *  - read ep0 maxpacket even for high and low speed,
> > -                        */
> > -                       msleep(10);
> > -                       /* use_new_scheme() checks the speed which may have
> > -                        * changed since the initial look so we cache the result
> > -                        * in did_new_scheme
> > -                        */
> > -                       if (did_new_scheme)
> > -                               break;
> > -               }
> > +               msleep(10);
> > +       }
> >
> > +       if (!do_new_scheme) {
> >                 retval = usb_get_device_descriptor(udev, 8);
> >                 if (retval < 8) {
> >                         if (retval != -ENODEV)
> > @@ -4804,7 +4787,6 @@ hub_port_init(struct usb_hub *hub, struc
> >                                         retval);
> >                                 retval = 0;
> >                         }
> > -                       break;
> >                 }
> >         }
> >         if (retval)
> > @@ -5106,7 +5088,7 @@ static void hub_port_connect(struct usb_
> >                 unit_load = 100;
> >
> >         status = 0;
> > -       for (i = 0; i < SET_CONFIG_TRIES; i++) {
> > +       for (i = 0; i < PORT_INIT_TRIES; i++) {
> >
> >                 /* reallocate for each attempt, since references
> >                  * to the previous one can escape in various ways
> > @@ -5239,7 +5221,7 @@ loop:
> >                         break;
> >
> >                 /* When halfway through our retry count, power-cycle the port */
> > -               if (i == (SET_CONFIG_TRIES / 2) - 1) {
> > +               if (i == (PORT_INIT_TRIES / 2) - 1) {
> >                         dev_info(&port_dev->dev, "attempt power cycle\n");
> >                         usb_hub_set_port_power(hdev, hub, port1, false);
> >                         msleep(2 * hub_power_on_good_delay(hub));
> > @@ -5770,7 +5752,7 @@ static int usb_reset_and_verify_device(s
> >         bos = udev->bos;
> >         udev->bos = NULL;
> >
> > -       for (i = 0; i < SET_CONFIG_TRIES; ++i) {
> > +       for (i = 0; i < PORT_INIT_TRIES; ++i) {
> >
> >                 /* ep0 maxpacket size may change; let the HCD know about it.
> >                  * Other endpoints will be handled by re-enumeration. */
> >




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux