Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed8acd13 authored by Kai-Heng Feng's avatar Kai-Heng Feng Committed by Greg Kroah-Hartman
Browse files

USB: Wait for extra delay time after USB_PORT_FEAT_RESET for quirky hub



commit 781f0766cc41a9dd2e5d118ef4b1d5d89430257b upstream.

Devices connected under Terminus Technology Inc. Hub (1a40:0101) may
fail to work after the system resumes from suspend:
[  206.063325] usb 3-2.4: reset full-speed USB device number 4 using xhci_hcd
[  206.143691] usb 3-2.4: device descriptor read/64, error -32
[  206.351671] usb 3-2.4: device descriptor read/64, error -32

Info for this hub:
T:  Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=480 MxCh= 4
D:  Ver= 2.00 Cls=09(hub  ) Sub=00 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=1a40 ProdID=0101 Rev=01.11
S:  Product=USB 2.0 Hub
C:  #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub

Some expirements indicate that the USB devices connected to the hub are
innocent, it's the hub itself is to blame. The hub needs extra delay
time after it resets its port.

Hence wait for extra delay, if the device is connected to this quirky
hub.

Signed-off-by: default avatarKai-Heng Feng <kai.heng.feng@canonical.com>
Cc: stable <stable@vger.kernel.org>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 20aa051f
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -4687,6 +4687,8 @@
					prevent spurious wakeup);
					prevent spurious wakeup);
				n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a
				n = USB_QUIRK_DELAY_CTRL_MSG (Device needs a
					pause after every control message);
					pause after every control message);
				o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra
					delay after resetting its port);
			Example: quirks=0781:5580:bk,0a5c:5834:gij
			Example: quirks=0781:5580:bk,0a5c:5834:gij


	usbhid.mousepoll=
	usbhid.mousepoll=
+11 −3
Original line number Original line Diff line number Diff line
@@ -2791,6 +2791,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
	int i, status;
	int i, status;
	u16 portchange, portstatus;
	u16 portchange, portstatus;
	struct usb_port *port_dev = hub->ports[port1 - 1];
	struct usb_port *port_dev = hub->ports[port1 - 1];
	int reset_recovery_time;


	if (!hub_is_superspeed(hub->hdev)) {
	if (!hub_is_superspeed(hub->hdev)) {
		if (warm) {
		if (warm) {
@@ -2882,11 +2883,18 @@ static int hub_port_reset(struct usb_hub *hub, int port1,


done:
done:
	if (status == 0) {
	if (status == 0) {
		/* TRSTRCY = 10 ms; plus some extra */
		if (port_dev->quirks & USB_PORT_QUIRK_FAST_ENUM)
		if (port_dev->quirks & USB_PORT_QUIRK_FAST_ENUM)
			usleep_range(10000, 12000);
			usleep_range(10000, 12000);
		else
		else {
			msleep(10 + 40);
			/* TRSTRCY = 10 ms; plus some extra */
			reset_recovery_time = 10 + 40;

			/* Hub needs extra delay after resetting its port. */
			if (hub->hdev->quirks & USB_QUIRK_HUB_SLOW_RESET)
				reset_recovery_time += 100;

			msleep(reset_recovery_time);
		}


		if (udev) {
		if (udev) {
			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
			struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+6 −0
Original line number Original line Diff line number Diff line
@@ -128,6 +128,9 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp)
			case 'n':
			case 'n':
				flags |= USB_QUIRK_DELAY_CTRL_MSG;
				flags |= USB_QUIRK_DELAY_CTRL_MSG;
				break;
				break;
			case 'o':
				flags |= USB_QUIRK_HUB_SLOW_RESET;
				break;
			/* Ignore unrecognized flag characters */
			/* Ignore unrecognized flag characters */
			}
			}
		}
		}
@@ -380,6 +383,9 @@ static const struct usb_device_id usb_quirk_list[] = {
	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
			USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
			USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },


	/* Terminus Technology Inc. Hub */
	{ USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET },

	/* Corsair K70 RGB */
	/* Corsair K70 RGB */
	{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
	{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },


+3 −0
Original line number Original line Diff line number Diff line
@@ -66,4 +66,7 @@
/* Device needs a pause after every control message. */
/* Device needs a pause after every control message. */
#define USB_QUIRK_DELAY_CTRL_MSG		BIT(13)
#define USB_QUIRK_DELAY_CTRL_MSG		BIT(13)


/* Hub needs extra delay after resetting its port. */
#define USB_QUIRK_HUB_SLOW_RESET		BIT(14)

#endif /* __LINUX_USB_QUIRKS_H */
#endif /* __LINUX_USB_QUIRKS_H */