summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-10-15 09:51:18 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-10-15 09:51:18 -0700
commitc6dbef7307629cce855aa6b482b60cbf7777ed88 (patch)
treed8d13630bd57090173ad9f0c5f8e3bfb392964c9 /drivers/usb/core/hub.c
parentade7afe3e606f9f6ff0e6deefce140157f75540b (diff)
parent93578a25d4e21603518daf27a5f9caa4bf79de68 (diff)
downloadlinux-c6dbef7307629cce855aa6b482b60cbf7777ed88.tar.bz2
Merge tag 'usb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY/Thunderbolt driver updates from Greg KH: "Here is the big set of USB, PHY, and Thunderbolt driver updates for 5.10-rc1. Lots of tiny different things for these subsystems are in here, including: - phy driver updates - thunderbolt / USB 4 updates and additions - USB gadget driver updates - xhci fixes and updates - typec driver additions and updates - api conversions to various drivers for core kernel api changes - new USB control message functions to make it harder to get wrong, as found by syzbot (took 2 tries to get it right) - lots of tiny USB driver fixes and updates all over the place All of these have been in linux-next for a while, with the exception of the last "obviously correct" patch that updated a FALLTHROUGH comment that got merged last weekend" * tag 'usb-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (374 commits) usb: musb: gadget: Use fallthrough pseudo-keyword usb: typec: Add QCOM PMIC typec detection driver USB: serial: option: add Cellient MPL200 card usb: typec: tcpci_maxim: Add support for Sink FRS usb: typec: tcpci: Implement callbacks for FRS usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS) usb: typec: tcpci_maxim: Chip level TCPC driver usb: typec: tcpci: Add set_vbus tcpci callback usb: typec: tcpci: Add a getter method to retrieve tcpm_port reference usbip: vhci_hcd: fix calling usb_hcd_giveback_urb() with irqs enabled usb: cdc-acm: add quirk to blacklist ETAS ES58X devices USB: serial: ftdi_sio: use cur_altsetting for consistency USB: serial: option: Add Telit FT980-KS composition USB: core: remove polling for /sys/kernel/debug/usb/devices usb: typec: add support for STUSB160x Type-C controller family usb: typec: add typec_find_pwr_opmode usb: typec: hd3ss3220: Use OF graph API to get the connector fwnode dt-bindings: usb: renesas,usb3-peri: Document HS and SS data bus dt-bindings: usb: convert ti,hd3ss3220 bindings to json-schema usb: dwc2: Fix INTR OUT transfers in DDMA mode. ...
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c62
1 files changed, 38 insertions, 24 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5b768b80d1ee..17202b2ee063 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2705,11 +2705,20 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
}
+#ifdef CONFIG_USB_FEW_INIT_RETRIES
+#define PORT_RESET_TRIES 2
+#define SET_ADDRESS_TRIES 1
+#define GET_DESCRIPTOR_TRIES 1
+#define GET_MAXPACKET0_TRIES 1
+#define PORT_INIT_TRIES 4
+
+#else
#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 GET_MAXPACKET0_TRIES 3
+#define PORT_INIT_TRIES 4
+#endif /* CONFIG_USB_FEW_INIT_RETRIES */
#define HUB_ROOT_RESET_TIME 60 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
@@ -2717,23 +2726,31 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
#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?
@@ -4545,6 +4562,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
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,14 +4675,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* 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;
+ do_new_scheme = use_new_scheme(udev, retry_counter, port_dev);
- if (use_new_scheme(udev, retry_counter, port_dev)) {
+ for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
+ if (do_new_scheme) {
struct usb_device_descriptor *buf;
int r = 0;
- did_new_scheme = true;
retval = hub_enable_device(udev);
if (retval < 0) {
dev_err(&udev->dev,
@@ -4684,7 +4701,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* 255 is for WUSB devices, we actually need to use
* 512 (WUSB1.0[4.8.1]).
*/
- for (operations = 0; operations < 3; ++operations) {
+ for (operations = 0; operations < GET_MAXPACKET0_TRIES;
+ ++operations) {
buf->bMaxPacketSize0 = 0;
r = usb_control_msg(udev, usb_rcvaddr0pipe(),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
@@ -4773,11 +4791,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* - 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)
+ if (do_new_scheme)
break;
}
@@ -5106,7 +5120,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
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 +5253,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 - 1) / 2) {
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 +5784,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
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. */