Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: hub: Clean up use of port initialization schemes and retries

The SET_CONFIG_TRIES macro in hub.c is badly named; it controls the
number of port-initialization retry attempts rather than the number of
Set-Configuration attempts. Furthermore, the USE_NEW_SCHEME macro and
use_new_scheme() function are written in a very confusing manner,
making it almost impossible to figure out exactly what they do or
check that they are correct.

This patch renames SET_CONFIG_TRIES to PORT_INIT_TRIES, removes
USE_NEW_SCHEME entirely, and rewrites use_new_scheme() to be much more
transparent, with added comments explaining how it works. The patch
also pulls the single call site of use_new_scheme() out from the
Get-Descriptor retry loop (where it returns the same value each time)
and renames the local variable used to store the result.

The overall effect is a minor cleanup. However, there is one
functional change: If the "use_both_schemes" module parameter isn't
set (by default it is set), the existing code does only two retry
iterations. After this patch it will always perform four, regardless
of the parameter's value.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/20200928152050.GA134701@rowland.harvard.edu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
19502e69 59ee364b

+26 -23
+26 -23
drivers/usb/core/hub.c
··· 2708 2708 #define PORT_RESET_TRIES 5 2709 2709 #define SET_ADDRESS_TRIES 2 2710 2710 #define GET_DESCRIPTOR_TRIES 2 2711 - #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) 2712 - #define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)(scheme)) 2711 + #define PORT_INIT_TRIES 4 2713 2712 2714 2713 #define HUB_ROOT_RESET_TIME 60 /* times are in msec */ 2715 2714 #define HUB_SHORT_RESET_TIME 10 ··· 2716 2717 #define HUB_LONG_RESET_TIME 200 2717 2718 #define HUB_RESET_TIMEOUT 800 2718 2719 2719 - /* 2720 - * "New scheme" enumeration causes an extra state transition to be 2721 - * exposed to an xhci host and causes USB3 devices to receive control 2722 - * commands in the default state. This has been seen to cause 2723 - * enumeration failures, so disable this enumeration scheme for USB3 2724 - * devices. 2725 - */ 2726 2720 static bool use_new_scheme(struct usb_device *udev, int retry, 2727 2721 struct usb_port *port_dev) 2728 2722 { 2729 2723 int old_scheme_first_port = 2730 - port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME; 2724 + (port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME) || 2725 + old_scheme_first; 2731 2726 2727 + /* 2728 + * "New scheme" enumeration causes an extra state transition to be 2729 + * exposed to an xhci host and causes USB3 devices to receive control 2730 + * commands in the default state. This has been seen to cause 2731 + * enumeration failures, so disable this enumeration scheme for USB3 2732 + * devices. 2733 + */ 2732 2734 if (udev->speed >= USB_SPEED_SUPER) 2733 2735 return false; 2734 2736 2735 - return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first); 2737 + /* 2738 + * If use_both_schemes is set, use the first scheme (whichever 2739 + * it is) for the larger half of the retries, then use the other 2740 + * scheme. Otherwise, use the first scheme for all the retries. 2741 + */ 2742 + if (use_both_schemes && retry >= (PORT_INIT_TRIES + 1) / 2) 2743 + return old_scheme_first_port; /* Second half */ 2744 + return !old_scheme_first_port; /* First half or all */ 2736 2745 } 2737 2746 2738 2747 /* Is a USB 3.0 port in the Inactive or Compliance Mode state? ··· 4552 4545 const char *speed; 4553 4546 int devnum = udev->devnum; 4554 4547 const char *driver_name; 4548 + bool do_new_scheme; 4555 4549 4556 4550 /* root hub ports have a slightly longer reset period 4557 4551 * (from USB 2.0 spec, section 7.1.7.5) ··· 4665 4657 * first 8 bytes of the device descriptor to get the ep0 maxpacket 4666 4658 * value. 4667 4659 */ 4668 - for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) { 4669 - bool did_new_scheme = false; 4660 + do_new_scheme = use_new_scheme(udev, retry_counter, port_dev); 4670 4661 4671 - if (use_new_scheme(udev, retry_counter, port_dev)) { 4662 + for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) { 4663 + if (do_new_scheme) { 4672 4664 struct usb_device_descriptor *buf; 4673 4665 int r = 0; 4674 4666 4675 - did_new_scheme = true; 4676 4667 retval = hub_enable_device(udev); 4677 4668 if (retval < 0) { 4678 4669 dev_err(&udev->dev, ··· 4780 4773 * - read ep0 maxpacket even for high and low speed, 4781 4774 */ 4782 4775 msleep(10); 4783 - /* use_new_scheme() checks the speed which may have 4784 - * changed since the initial look so we cache the result 4785 - * in did_new_scheme 4786 - */ 4787 - if (did_new_scheme) 4776 + if (do_new_scheme) 4788 4777 break; 4789 4778 } 4790 4779 ··· 5109 5106 unit_load = 100; 5110 5107 5111 5108 status = 0; 5112 - for (i = 0; i < SET_CONFIG_TRIES; i++) { 5109 + for (i = 0; i < PORT_INIT_TRIES; i++) { 5113 5110 5114 5111 /* reallocate for each attempt, since references 5115 5112 * to the previous one can escape in various ways ··· 5242 5239 break; 5243 5240 5244 5241 /* When halfway through our retry count, power-cycle the port */ 5245 - if (i == (SET_CONFIG_TRIES / 2) - 1) { 5242 + if (i == (PORT_INIT_TRIES - 1) / 2) { 5246 5243 dev_info(&port_dev->dev, "attempt power cycle\n"); 5247 5244 usb_hub_set_port_power(hdev, hub, port1, false); 5248 5245 msleep(2 * hub_power_on_good_delay(hub)); ··· 5773 5770 bos = udev->bos; 5774 5771 udev->bos = NULL; 5775 5772 5776 - for (i = 0; i < SET_CONFIG_TRIES; ++i) { 5773 + for (i = 0; i < PORT_INIT_TRIES; ++i) { 5777 5774 5778 5775 /* ep0 maxpacket size may change; let the HCD know about it. 5779 5776 * Other endpoints will be handled by re-enumeration. */