diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-12 11:27:57 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-12 11:27:57 -0800 |
commit | 57ea81971b7296b42fc77424af44c5915d3d4ae2 (patch) | |
tree | 42d848611084e69e08028340bf0c9be29557badd /drivers/usb/core/hub.c | |
parent | 342465f5337f7bd5b8bd3b6f939ac12b620cbb43 (diff) | |
parent | cbb4f5f435995a56ef770e35bfafb4bcff8f0ada (diff) |
Merge tag 'usb-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB and Thunderbolt updates from Greg KH:
"Here is the big set of USB and Thunderbolt driver changes for
5.17-rc1.
Nothing major in here, just lots of little updates and cleanups. These
include:
- some USB header fixes picked from Ingo's header-splitup work
- more USB4/Thunderbolt hardware support added
- USB gadget driver updates and additions
- USB typec additions (includes some acpi changes, which were acked
by the ACPI maintainer)
- core USB fixes as found by syzbot that were too late for 5.16-final
- USB dwc3 driver updates
- USB dwc2 driver updates
- platform_get_irq() conversions of some USB drivers
- other minor USB driver updates and additions
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (111 commits)
docs: ABI: fixed formatting in configfs-usb-gadget-uac2
usb: gadget: u_audio: Subdevice 0 for capture ctls
usb: gadget: u_audio: fix calculations for small bInterval
usb: dwc2: gadget: initialize max_speed from params
usb: dwc2: do not gate off the hardware if it does not support clock gating
usb: dwc3: qcom: Fix NULL vs IS_ERR checking in dwc3_qcom_probe
headers/deps: USB: Optimize <linux/usb/ch9.h> dependencies, remove <linux/device.h>
USB: common: debug: add needed kernel.h include
headers/prep: Fix non-standard header section: drivers/usb/host/ohci-tmio.c
headers/prep: Fix non-standard header section: drivers/usb/cdns3/core.h
headers/prep: usb: gadget: Fix namespace collision
USB: core: Fix bug in resuming hub's handling of wakeup requests
USB: Fix "slab-out-of-bounds Write" bug in usb_hcd_poll_rh_status
usb: dwc3: dwc3-qcom: Add missing platform_device_put() in dwc3_qcom_acpi_register_core
usb: gadget: clear related members when goto fail
usb: gadget: don't release an existing dev->buf
usb: dwc2: Simplify a bitmap declaration
usb: Remove usb_for_each_port()
usb: typec: port-mapper: Convert to the component framework
usb: Link the ports to the connectors they are attached to
...
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 00070a8a6507..47a1c8bddf86 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1110,7 +1110,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) } else { hub_power_on(hub, true); } - } + /* Give some time on remote wakeup to let links to transit to U0 */ + } else if (hub_is_superspeed(hub->hdev)) + msleep(20); + init2: /* @@ -1225,7 +1228,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) */ if (portchange || (hub_is_superspeed(hub->hdev) && port_resumed)) - set_bit(port1, hub->change_bits); + set_bit(port1, hub->event_bits); } else if (udev->persist_enabled) { #ifdef CONFIG_PM @@ -2777,6 +2780,8 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define PORT_INIT_TRIES 4 #endif /* CONFIG_USB_FEW_INIT_RETRIES */ +#define DETECT_DISCONNECT_TRIES 5 + #define HUB_ROOT_RESET_TIME 60 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 #define HUB_BH_RESET_TIME 50 @@ -3570,7 +3575,7 @@ static int finish_port_resume(struct usb_device *udev) * This routine should only be called when persist is enabled. */ static int wait_for_connected(struct usb_device *udev, - struct usb_hub *hub, int *port1, + struct usb_hub *hub, int port1, u16 *portchange, u16 *portstatus) { int status = 0, delay_ms = 0; @@ -3584,7 +3589,7 @@ static int wait_for_connected(struct usb_device *udev, } msleep(20); delay_ms += 20; - status = hub_port_status(hub, *port1, portstatus, portchange); + status = hub_port_status(hub, port1, portstatus, portchange); } dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms); return status; @@ -3690,7 +3695,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) } if (udev->persist_enabled) - status = wait_for_connected(udev, hub, &port1, &portchange, + status = wait_for_connected(udev, hub, port1, &portchange, &portstatus); status = check_port_resume_type(udev, @@ -5543,6 +5548,7 @@ static void port_event(struct usb_hub *hub, int port1) struct usb_device *udev = port_dev->child; struct usb_device *hdev = hub->hdev; u16 portstatus, portchange; + int i = 0; connect_change = test_bit(port1, hub->change_bits); clear_bit(port1, hub->event_bits); @@ -5619,17 +5625,27 @@ static void port_event(struct usb_hub *hub, int port1) connect_change = 1; /* - * Warm reset a USB3 protocol port if it's in - * SS.Inactive state. + * Avoid trying to recover a USB3 SS.Inactive port with a warm reset if + * the device was disconnected. A 12ms disconnect detect timer in + * SS.Inactive state transitions the port to RxDetect automatically. + * SS.Inactive link error state is common during device disconnect. */ - if (hub_port_warm_reset_required(hub, port1, portstatus)) { - dev_dbg(&port_dev->dev, "do warm reset\n"); - if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) + while (hub_port_warm_reset_required(hub, port1, portstatus)) { + if ((i++ < DETECT_DISCONNECT_TRIES) && udev) { + u16 unused; + + msleep(20); + hub_port_status(hub, port1, &portstatus, &unused); + dev_dbg(&port_dev->dev, "Wait for inactive link disconnect detect\n"); + continue; + } else if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) || udev->state == USB_STATE_NOTATTACHED) { + dev_dbg(&port_dev->dev, "do warm reset, port only\n"); if (hub_port_reset(hub, port1, NULL, HUB_BH_RESET_TIME, true) < 0) hub_port_disable(hub, port1, 1); } else { + dev_dbg(&port_dev->dev, "do warm reset, full device\n"); usb_unlock_port(port_dev); usb_lock_device(udev); usb_reset_device(udev); @@ -5637,6 +5653,7 @@ static void port_event(struct usb_hub *hub, int port1) usb_lock_port(port_dev); connect_change = 0; } + break; } if (connect_change) |