Message ID | 1547658452-18036-1-git-send-email-glogow@fbihome.de (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [v3] usb: warm-reset ports on hub resume, if requested | expand |
Just adding some CC of commit signers from get_maintainer.pl Am 16.01.19 um 18:07 schrieb Jan-Marek Glogowski: > On plug-in of my USB-C device, its USB_SS_PORT_LS_SS_INACTIVE > link state bit is set. Greping all the kernel for this bit shows > that the port status requests a warm-reset this way. > > This just happens, if its the only device on that hub and the > hub resumes, so we don't call port_event, which would otherwise > warm-reset ports. The device works ok without this patch, if > there is already any other device connected to the hub. > > Signed-off-by: Jan-Marek Glogowski <glogow@fbihome.de> > --- > > v1: This always warm-resets the ports in hub_activate, independent of the > "enum hub_activation_type". Just had a single device to test. > > v2: I had the idea about the working device, if there is already a device > connected to the hub and that a resume only on "type == HUB_RESUME" should > be sufficient. This still works for me, but I didn't follow all the > hub_activate callers everywhere and I'm definitly still missing a lot of > knowledge about USB stuff. There is also HUB_RESET_RESUME with a slightly > different code path. I don't know how to trigger this. > > v3: code unchanged to v2, so I could abandon my explanation mail, which I > was typing when Gregs mail arrived. > > --- > drivers/usb/core/hub.c | 21 +++++++++++++++------ > 1 file changed, 15 insertions(+), 6 deletions(-) > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c > index 1d1e61e..e0cc740 100644 > --- a/drivers/usb/core/hub.c > +++ b/drivers/usb/core/hub.c > @@ -108,6 +108,16 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); > static void hub_release(struct kref *kref); > static int usb_reset_and_verify_device(struct usb_device *udev); > static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); > +static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, > + u16 portstatus); > +static int hub_port_reset(struct usb_hub *hub, int port1, > + struct usb_device *udev, unsigned int delay, bool warm); > + > +#define HUB_ROOT_RESET_TIME 60 /* times are in msec */ > +#define HUB_SHORT_RESET_TIME 10 > +#define HUB_BH_RESET_TIME 50 > +#define HUB_LONG_RESET_TIME 200 > +#define HUB_RESET_TIMEOUT 800 > > static inline char *portspeed(struct usb_hub *hub, int portstatus) > { > @@ -1122,6 +1132,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) > USB_SS_PORT_LS_POLLING)) > need_debounce_delay = true; > > + if (type == HUB_RESUME && > + hub_port_warm_reset_required(hub, port1, portstatus)) > + hub_port_reset(hub, port1, udev, > + HUB_BH_RESET_TIME, true); > + > /* Clear status-change flags; we'll debounce later */ > if (portchange & USB_PORT_STAT_C_CONNECTION) { > need_debounce_delay = true; > @@ -2653,12 +2668,6 @@ static unsigned hub_is_wusb(struct usb_hub *hub) > #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) > #define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)scheme) > > -#define HUB_ROOT_RESET_TIME 60 /* times are in msec */ > -#define HUB_SHORT_RESET_TIME 10 > -#define HUB_BH_RESET_TIME 50 > -#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 >
On 18.01.2019 13:28, Jan-Marek Glogowski wrote: > Just adding some CC of commit signers from get_maintainer.pl > > Am 16.01.19 um 18:07 schrieb Jan-Marek Glogowski: >> On plug-in of my USB-C device, its USB_SS_PORT_LS_SS_INACTIVE >> link state bit is set. Greping all the kernel for this bit shows >> that the port status requests a warm-reset this way. >> >> This just happens, if its the only device on that hub and the >> hub resumes, so we don't call port_event, which would otherwise >> warm-reset ports. The device works ok without this patch, if >> there is already any other device connected to the hub. >> I've heard about issues with bad port redrivers/retimers causing similar issues at resume. One reason why port_event() isn't called is that hub thread failed to report any activity for those ports. At bus resume we start polling the roothub, which calls xhci_hub_status_data(). This function will check if there are any interesting changes going on, and mark these ports. If no activity then it asks usb core to stop roothub polling. xhci_hub_status_data() does not check for USB_PORT_LS_SS_INACTIVE, or compliance mode, or USB3 polling state, which all would need more attention. Could make sense to add those. Does the below code help your situation? diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index e2eece6..70f9b26 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1458,7 +1458,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; struct xhci_bus_state *bus_state; - bool reset_change = false; + bool poll_roothub = false; struct xhci_hub *rhub; struct xhci_port **ports; @@ -1491,16 +1491,23 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) trace_xhci_hub_status_data(i, temp); if ((temp & mask) != 0 || - (bus_state->port_c_suspend & 1 << i) || - (bus_state->resume_done[i] && time_after_eq( + (bus_state->port_c_suspend & 1 << i) || + (temp & PORT_PLS_MASK) == XDEV_COMP_MODE || + (temp & PORT_PLS_MASK) == XDEV_INACTIVE || + (bus_state->resume_done[i] && time_after_eq( jiffies, bus_state->resume_done[i]))) { buf[(i + 1) / 8] |= 1 << (i + 1) % 8; status = 1; } - if ((temp & PORT_RC)) - reset_change = true; + /* + * don't stop roothub polling if port is in polling state as it + * can end up in compliance mode without issuing any event + */ + if ((temp & PORT_RC) || + (temp & PORT_PLS_MASK) == XDEV_POLLING) + poll_roothub = true; } - if (!status && !reset_change) { + if (!status && !poll_roothub) { xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); } -Mathias
Am 25.01.19 um 16:14 schrieb Mathias Nyman: > On 18.01.2019 13:28, Jan-Marek Glogowski wrote: >> Just adding some CC of commit signers from get_maintainer.pl >> >> Am 16.01.19 um 18:07 schrieb Jan-Marek Glogowski: >>> On plug-in of my USB-C device, its USB_SS_PORT_LS_SS_INACTIVE >>> link state bit is set. Greping all the kernel for this bit shows >>> that the port status requests a warm-reset this way. >>> >>> This just happens, if its the only device on that hub and the >>> hub resumes, so we don't call port_event, which would otherwise >>> warm-reset ports. The device works ok without this patch, if >>> there is already any other device connected to the hub. >>> > > I've heard about issues with bad port redrivers/retimers causing similar issues > at resume. > > One reason why port_event() isn't called is that hub thread failed to report > any activity for those ports. > > At bus resume we start polling the roothub, which calls > xhci_hub_status_data(). This function will check if there are any interesting > changes going on, and mark these ports. > If no activity then it asks usb core to stop roothub polling. > > xhci_hub_status_data() does not check for USB_PORT_LS_SS_INACTIVE, or compliance mode, > or USB3 polling state, which all would need more attention. > > Could make sense to add those. > Does the below code help your situation? > > diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c > index e2eece6..70f9b26 100644 > --- a/drivers/usb/host/xhci-hub.c > +++ b/drivers/usb/host/xhci-hub.c > @@ -1458,7 +1458,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) > struct xhci_hcd *xhci = hcd_to_xhci(hcd); > int max_ports; > struct xhci_bus_state *bus_state; > - bool reset_change = false; > + bool poll_roothub = false; > struct xhci_hub *rhub; > struct xhci_port **ports; > > @@ -1491,16 +1491,23 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) > trace_xhci_hub_status_data(i, temp); > > if ((temp & mask) != 0 || > - (bus_state->port_c_suspend & 1 << i) || > - (bus_state->resume_done[i] && time_after_eq( > + (bus_state->port_c_suspend & 1 << i) || > + (temp & PORT_PLS_MASK) == XDEV_COMP_MODE || > + (temp & PORT_PLS_MASK) == XDEV_INACTIVE || > + (bus_state->resume_done[i] && time_after_eq( > jiffies, bus_state->resume_done[i]))) { > buf[(i + 1) / 8] |= 1 << (i + 1) % 8; > status = 1; > } > - if ((temp & PORT_RC)) > - reset_change = true; > + /* > + * don't stop roothub polling if port is in polling state as it > + * can end up in compliance mode without issuing any event > + */ > + if ((temp & PORT_RC) || > + (temp & PORT_PLS_MASK) == XDEV_POLLING) > + poll_roothub = true; > } > - if (!status && !reset_change) { > + if (!status && !poll_roothub) { > xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); > clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); > } > No changes for me with this patch. This is still from 5.0rc2. >>>> Test-Script (./r) #!/bin/sh set -e LSMOD="$(lsmod)" rm_mod() { if echo "$LSMOD" | grep -q "$1"; then sudo rmmod "$1" fi } rm_mod uas rm_mod usb_storage rm_mod xhci_pci rm_mod xhci_hcd rm_mod usbcore if [ "$#" -eq 1 ]; then sudo dmesg -C sudo insmod core/usbcore.ko dyndbg=+mfp sudo insmod xhci-hcd.ko dyndbg=+mfp sudo insmod xhci-pci.ko dyndbg=+mfp fi <<<< Run "./r 1" [ 2311.984239] ACPI: bus type USB registered [ 2311.984255] usbcore: registered new interface driver usbfs [ 2311.984260] usbcore: registered new interface driver hub [ 2311.984277] usbcore: registered new device driver usb [ 2312.006999] xhci_hcd 0000:00:14.0: xHCI Host Controller [ 2312.007003] xhci_hcd 0000:00:14.0: new USB bus registered, assigned bus number 1 [ 2312.007016] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Halt the HC [ 2312.007020] xhci_hcd:xhci_gen_setup: xhci_hcd 0000:00:14.0: Resetting HCD [ 2312.007021] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Reset the HC [ 2312.008020] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Wait for controller to be ready for doorbell rings [ 2312.008021] xhci_hcd:xhci_gen_setup: xhci_hcd 0000:00:14.0: Reset complete [ 2312.008023] xhci_hcd:xhci_gen_setup: xhci_hcd 0000:00:14.0: Enabling 64-bit DMA addresses. [ 2312.008023] xhci_hcd:xhci_gen_setup: xhci_hcd 0000:00:14.0: Calling HCD init [ 2312.008024] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: xhci_init [ 2312.008026] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: xHCI doesn't need link TRB QUIRK [ 2312.008028] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Supported page size register = 0x1 [ 2312.008029] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Supported page size of 4K [ 2312.008030] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: HCD page size set to 4K [ 2312.008032] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // xHC can handle at most 64 device slots. [ 2312.008033] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Setting Max device slots reg = 0x40. [ 2312.008036] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Device context base array address = 0x44f2c9000 (DMA), 000000000d5687b1 (virt) [ 2312.008038] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Allocated command ring at 0000000004285dce [ 2312.008039] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: First segment DMA is 0x44ebd4000 [ 2312.008041] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Setting command ring address to 0x000000044ebd4001 [ 2312.008044] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Doorbell array is located at offset 0x3000 from cap regs base addr [ 2312.008045] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Allocating event ring [ 2312.008047] xhci_hcd:xhci_check_trb_in_td_math: xhci_hcd 0000:00:14.0: TRB math tests passed. [ 2312.008049] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Write ERST size = 1 to ir_set 0 (some bits preserved) [ 2312.008050] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Set ERST entries to point to event ring. [ 2312.008051] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Set ERST base address for ir_set 0 = 0x45324d000 [ 2312.008055] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Write event ring dequeue pointer, preserving EHB bit [ 2312.008056] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Wrote ERST address to ir_set 0. [ 2312.008057] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Allocating 34 scratchpad buffers [ 2312.008084] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Ext Cap 0000000059b07030, port offset = 1, count = 16, revision = 0x2 [ 2312.008086] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:1 PSIE:2 PLT:0 PFD:0 LP:0 PSIM:12 [ 2312.008088] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:2 PSIE:1 PLT:0 PFD:0 LP:0 PSIM:1500 [ 2312.008090] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:3 PSIE:2 PLT:0 PFD:0 LP:0 PSIM:480 [ 2312.008091] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: xHCI 1.0: support USB2 hardware lpm [ 2312.008094] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Ext Cap 0000000061bddd60, port offset = 17, count = 6, revision = 0x3 [ 2312.008096] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:4 PSIE:3 PLT:0 PFD:1 LP:0 PSIM:5 [ 2312.008098] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:5 PSIE:3 PLT:0 PFD:1 LP:0 PSIM:10 [ 2312.008100] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:6 PSIE:2 PLT:0 PFD:1 LP:0 PSIM:1248 [ 2312.008102] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:7 PSIE:2 PLT:0 PFD:1 LP:0 PSIM:2496 [ 2312.008103] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:8 PSIE:2 PLT:0 PFD:1 LP:0 PSIM:4992 [ 2312.008105] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:9 PSIE:2 PLT:0 PFD:1 LP:0 PSIM:1457 [ 2312.008107] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:10 PSIE:2 PLT:0 PFD:1 LP:0 PSIM:2915 [ 2312.008109] xhci_hcd:xhci_add_in_port: xhci_hcd 0000:00:14.0: PSIV:11 PSIE:2 PLT:0 PFD:1 LP:0 PSIM:5830 [ 2312.008110] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Found 16 USB 2.0 ports and 6 USB 3.0 ports. [ 2312.008112] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Finished xhci_init [ 2312.008113] xhci_hcd:xhci_gen_setup: xhci_hcd 0000:00:14.0: Called HCD init [ 2312.008114] xhci_hcd 0000:00:14.0: hcc params 0x20007fc1 hci version 0x110 quirks 0x0000000000009810 [ 2312.008115] xhci_pci:xhci_pci_setup: xhci_hcd 0000:00:14.0: Got SBRN 49 [ 2312.008118] xhci_hcd 0000:00:14.0: cache line size of 64 is not supported [ 2312.008119] xhci_pci:xhci_pci_reinit: xhci_hcd 0000:00:14.0: Finished xhci_pci_reinit [ 2312.008120] usbcore:usb_add_hcd: xhci_hcd 0000:00:14.0: supports USB remote wakeup [ 2312.008121] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: xhci_run [ 2312.008123] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Failed to enable MSI-X [ 2312.008165] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: ERST deq = 64'h453d7b000 [ 2312.008166] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Set the interrupt modulation register [ 2312.008169] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Enable interrupts, cmd = 0x4. [ 2312.008171] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Enabling event ring interrupter 00000000e794492e by writing 0x2 to irq_pending [ 2312.008172] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Finished xhci_run for USB2 roothub [ 2312.008267] usbcore:usb_get_langid: usb usb1: default language 0x0409 [ 2312.008273] usbcore:usb_new_device: usb usb1: udev 1, busnum 1, minor = 0 [ 2312.008275] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 5.00 [ 2312.008276] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 2312.008277] usb usb1: Product: xHCI Host Controller [ 2312.008277] usb usb1: Manufacturer: Linux 5.0.0-rc2+ xhci-hcd [ 2312.008278] usb usb1: SerialNumber: 0000:00:14.0 [ 2312.008336] usbcore:usb_probe_device: usb usb1: usb_probe_device [ 2312.008337] usbcore:usb_choose_configuration: usb usb1: configuration #1 chosen from 1 choice [ 2312.008339] xhci_hcd:xhci_check_args: xHCI xhci_add_endpoint called for root hub [ 2312.008340] xhci_hcd:xhci_check_args: xHCI xhci_check_bandwidth called for root hub [ 2312.008345] usbcore:usb_set_configuration: usb usb1: adding 1-0:1.0 (config #1, interface 0) [ 2312.008359] usbcore:usb_probe_interface: hub 1-0:1.0: usb_probe_interface [ 2312.008360] usbcore:usb_probe_interface: hub 1-0:1.0: usb_probe_interface - got id [ 2312.008361] hub 1-0:1.0: USB hub found [ 2312.008377] hub 1-0:1.0: 16 ports detected [ 2312.008378] usbcore:hub_configure: hub 1-0:1.0: standalone hub [ 2312.008379] usbcore:hub_configure: hub 1-0:1.0: no power switching (usb 1.0) [ 2312.008380] usbcore:hub_configure: hub 1-0:1.0: individual port over-current protection [ 2312.008381] usbcore:hub_configure: hub 1-0:1.0: Single TT [ 2312.008382] usbcore:hub_configure: hub 1-0:1.0: TT requires at most 8 FS bit times (666 ns) [ 2312.008383] usbcore:hub_configure: hub 1-0:1.0: power on to power good time: 20ms [ 2312.008387] usbcore:hub_configure: hub 1-0:1.0: local power source is good [ 2312.014022] usbcore:hub_power_on: hub 1-0:1.0: trying to enable port power on non-switchable hub [ 2312.014038] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 0 status = 0x2a0 [ 2312.014045] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 1 status = 0x2a0 [ 2312.014050] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 2 status = 0x2a0 [ 2312.014056] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 3 status = 0x2a0 [ 2312.014061] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 4 status = 0x2a0 [ 2312.014066] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 5 status = 0x2a0 [ 2312.014071] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 6 status = 0x2a0 [ 2312.014076] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 7 status = 0x2a0 [ 2312.014081] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 8 status = 0x2a0 [ 2312.014086] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 9 status = 0x2a0 [ 2312.014092] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 10 status = 0x2a0 [ 2312.014097] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 11 status = 0x2a0 [ 2312.014102] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 12 status = 0x2a0 [ 2312.014107] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 13 status = 0x2a0 [ 2312.014112] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 14 status = 0x2a0 [ 2312.014117] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 15 status = 0x2a0 [ 2312.014203] xhci_hcd 0000:00:14.0: xHCI Host Controller [ 2312.014206] xhci_hcd 0000:00:14.0: new USB bus registered, assigned bus number 2 [ 2312.014208] xhci_hcd 0000:00:14.0: Host supports USB 3.1 Enhanced SuperSpeed [ 2312.014209] usbcore:usb_add_hcd: xhci_hcd 0000:00:14.0: supports USB remote wakeup [ 2312.014214] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: // Turn on HC, cmd = 0x5. [ 2312.014216] xhci_hcd:xhci_dbg_trace: xhci_hcd 0000:00:14.0: Finished xhci_run for USB3 roothub [ 2312.014231] usbcore:usb_parse_endpoint: usb usb2: skipped 1 descriptor after endpoint [ 2312.014234] usbcore:usb_get_langid: usb usb2: default language 0x0409 [ 2312.014240] usbcore:usb_new_device: usb usb2: udev 1, busnum 2, minor = 128 [ 2312.014242] usb usb2: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 5.00 [ 2312.014243] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1 [ 2312.014244] usb usb2: Product: xHCI Host Controller [ 2312.014245] usb usb2: Manufacturer: Linux 5.0.0-rc2+ xhci-hcd [ 2312.014246] usb usb2: SerialNumber: 0000:00:14.0 [ 2312.014298] usbcore:usb_probe_device: usb usb2: usb_probe_device [ 2312.014300] usbcore:usb_choose_configuration: usb usb2: configuration #1 chosen from 1 choice [ 2312.014302] xhci_hcd:xhci_check_args: xHCI xhci_add_endpoint called for root hub [ 2312.014303] xhci_hcd:xhci_check_args: xHCI xhci_check_bandwidth called for root hub [ 2312.014309] usbcore:usb_set_configuration: usb usb2: adding 2-0:1.0 (config #1, interface 0) [ 2312.014323] usbcore:usb_probe_interface: hub 2-0:1.0: usb_probe_interface [ 2312.014324] usbcore:usb_probe_interface: hub 2-0:1.0: usb_probe_interface - got id [ 2312.014325] hub 2-0:1.0: USB hub found [ 2312.014337] hub 2-0:1.0: 6 ports detected [ 2312.014338] usbcore:hub_configure: hub 2-0:1.0: standalone hub [ 2312.014339] usbcore:hub_configure: hub 2-0:1.0: no power switching (usb 1.0) [ 2312.014340] usbcore:hub_configure: hub 2-0:1.0: individual port over-current protection [ 2312.014341] usbcore:hub_configure: hub 2-0:1.0: TT requires at most 8 FS bit times (666 ns) [ 2312.014342] usbcore:hub_configure: hub 2-0:1.0: power on to power good time: 20ms [ 2312.014346] usbcore:hub_configure: hub 2-0:1.0: local power source is good [ 2312.014433] usbcore:link_peers_report: usb usb2-port1: peered to usb1-port1 [ 2312.014515] usbcore:link_peers_report: usb usb2-port2: peered to usb1-port6 [ 2312.014765] usbcore:link_peers_report: usb usb2-port3: peered to usb1-port3 [ 2312.015100] usbcore:link_peers: usb: failed to peer usb2-port4 and usb1-port1 by location (usb2-port4:none) (usb1-port1:usb2-port1) [ 2312.015102] usbcore:link_peers_report: usb usb2-port4: failed to peer to usb1-port1 (-16) [ 2312.015102] usb: port power management may be unreliable [ 2312.015258] usbcore:link_peers_report: usb usb2-port5: peered to usb1-port5 [ 2312.015403] usbcore:link_peers: usb: failed to peer usb2-port6 and usb1-port3 by location (usb2-port6:none) (usb1-port3:usb2-port3) [ 2312.015404] usbcore:link_peers_report: usb usb2-port6: failed to peer to usb1-port3 (-16) [ 2312.015408] usbcore:hub_power_on: hub 2-0:1.0: trying to enable port power on non-switchable hub [ 2312.015420] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 0 status = 0x802a0 [ 2312.015431] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 1 status = 0x802a0 [ 2312.015437] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 2 status = 0x2a0 [ 2312.015443] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 3 status = 0x802a0 [ 2312.015449] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 4 status = 0x802a0 [ 2312.015455] xhci_hcd:xhci_set_port_power: xhci_hcd 0000:00:14.0: set port power, actual port 5 status = 0x802a0 [ 2312.121249] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 0 status = 0x802a0 [ 2312.121254] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2002a0 [ 2312.121270] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 0 status = 0x2a0 [ 2312.121276] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121352] xhci_hcd:xhci_clear_port_change_bit: xhci_hcd 0000:00:14.0: clear port warm(BH) reset change, actual port 0 status = 0x2a0 [ 2312.121372] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 1 status = 0x2a0 [ 2312.121377] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121441] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 1 status = 0x802a0 [ 2312.121446] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2002a0 [ 2312.121463] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 2 status = 0x2a0 [ 2312.121468] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121524] xhci_hcd:xhci_clear_port_change_bit: xhci_hcd 0000:00:14.0: clear port warm(BH) reset change, actual port 1 status = 0x2a0 [ 2312.121546] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 3 status = 0x2a0 [ 2312.121551] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121611] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 2 status = 0x2a0 [ 2312.121615] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2312.121632] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 4 status = 0x2a0 [ 2312.121637] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121692] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 3 status = 0x802a0 [ 2312.121697] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2002a0 [ 2312.121719] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 5 status = 0x2a0 [ 2312.121724] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121785] xhci_hcd:xhci_clear_port_change_bit: xhci_hcd 0000:00:14.0: clear port warm(BH) reset change, actual port 3 status = 0x2a0 [ 2312.121804] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 6 status = 0x2a0 [ 2312.121809] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121862] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 4 status = 0x802a0 [ 2312.121867] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2002a0 [ 2312.121889] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 7 status = 0x2a0 [ 2312.121894] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.121940] xhci_hcd:xhci_clear_port_change_bit: xhci_hcd 0000:00:14.0: clear port warm(BH) reset change, actual port 4 status = 0x2a0 [ 2312.121972] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 8 status = 0x2a0 [ 2312.121977] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122011] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 5 status = 0x802a0 [ 2312.122016] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2002a0 [ 2312.122064] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 9 status = 0x2a0 [ 2312.122069] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122090] xhci_hcd:xhci_clear_port_change_bit: xhci_hcd 0000:00:14.0: clear port warm(BH) reset change, actual port 5 status = 0x2a0 [ 2312.122145] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 10 status = 0x2a0 [ 2312.122150] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122230] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 11 status = 0x2a0 [ 2312.122234] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122311] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 12 status = 0x2a0 [ 2312.122317] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122351] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 13 status = 0x2a0 [ 2312.122355] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122380] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 14 status = 0x2a0 [ 2312.122384] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122407] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 15 status = 0x2a0 [ 2312.122411] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x100 [ 2312.122438] usbcore:hub_event: hub 1-0:1.0: state 7 ports 16 chg 0000 evt 0000 [ 2312.122450] usbcore:hub_suspend: hub 1-0:1.0: hub_suspend [ 2312.122465] usbcore:hcd_bus_suspend: usb usb1: bus auto-suspend, wakeup 1 [ 2312.122504] xhci_hcd:xhci_hub_status_data: xhci_hcd 0000:00:14.0: xhci_hub_status_data: stopping port polling. [ 2312.225254] usbcore:hub_event: hub 2-0:1.0: state 7 ports 6 chg 0000 evt 0000 [ 2312.225284] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 0 status = 0xe0002a0 [ 2312.225319] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 1 status = 0xe0002a0 [ 2312.225339] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 2 status = 0xe0002a0 [ 2312.225360] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 3 status = 0xe0002a0 [ 2312.225378] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 4 status = 0xe0002a0 [ 2312.225396] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 5 status = 0xe0002a0 [ 2312.225408] usbcore:hub_suspend: hub 2-0:1.0: hub_suspend [ 2312.225423] usbcore:hcd_bus_suspend: usb usb2: bus auto-suspend, wakeup 1 [ 2312.225447] xhci_hcd:xhci_hub_status_data: xhci_hcd 0000:00:14.0: xhci_hub_status_data: stopping port polling. USB device is plugged here [ 2316.733514] xhci_hcd:handle_port_status: xhci_hcd 0000:00:14.0: Port Status Change Event for port 19 [ 2316.733525] xhci_hcd:handle_port_status: xhci_hcd 0000:00:14.0: resume root hub [ 2316.733540] xhci_hcd:handle_port_status: xhci_hcd 0000:00:14.0: handle_port_status: starting port polling. [ 2316.733604] usbcore:usb_remote_wakeup: usb usb2: usb wakeup-resume [ 2316.733613] usbcore:hcd_bus_resume: usb usb2: usb auto-resume [ 2316.733634] usbcore:hub_resume: hub 2-0:1.0: hub_resume [ 2316.733651] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 0 status = 0x2a0 [ 2316.733656] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.733686] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 1 status = 0x2a0 [ 2316.733690] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.733705] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 2 status = 0x4002c0 [ 2316.733710] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x4002c0 [ 2316.733728] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 3 status = 0x2a0 [ 2316.733732] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.733747] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 4 status = 0x2a0 [ 2316.733751] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.733768] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 5 status = 0x2a0 [ 2316.733772] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.733796] usbcore:hub_event: hub 2-0:1.0: state 7 ports 6 chg 0000 evt 0000 [ 2316.733812] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 0 status = 0xe0002a0 [ 2316.733835] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 1 status = 0xe0002a0 [ 2316.733850] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 2 status = 0xe4002c0 [ 2316.733867] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 3 status = 0xe0002a0 [ 2316.733883] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 4 status = 0xe0002a0 [ 2316.733899] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 5 status = 0xe0002a0 [ 2316.733911] usbcore:hub_suspend: hub 2-0:1.0: hub_suspend [ 2316.733926] usbcore:hcd_bus_suspend: usb usb2: bus auto-suspend, wakeup 1 [ 2316.733945] usbcore:hcd_bus_suspend: usb usb2: suspend raced with wakeup event [ 2316.733950] usbcore:hcd_bus_resume: usb usb2: usb auto-resume [ 2316.749178] usbcore:hub_resume: hub 2-0:1.0: hub_resume [ 2316.749193] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 0 status = 0x2a0 [ 2316.749197] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.749227] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 1 status = 0x2a0 [ 2316.749231] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.749247] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 2 status = 0x4002c0 [ 2316.749251] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x4002c0 [ 2316.749266] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 3 status = 0x2a0 [ 2316.749270] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.749283] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 4 status = 0x2a0 [ 2316.749288] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.749303] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: get port status, actual port 5 status = 0x2a0 [ 2316.749307] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: Get port status returned 0x2a0 [ 2316.749328] usbcore:hub_event: hub 2-0:1.0: state 7 ports 6 chg 0000 evt 0000 [ 2316.749345] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 0 status = 0xe0002a0 [ 2316.749361] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 1 status = 0xe0002a0 [ 2316.749376] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 2 status = 0xe4002c0 [ 2316.749391] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 3 status = 0xe0002a0 [ 2316.749407] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 4 status = 0xe0002a0 [ 2316.749422] xhci_hcd:xhci_hub_control: xhci_hcd 0000:00:14.0: set port remote wake mask, actual port 5 status = 0xe0002a0 ....
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1d1e61e..e0cc740 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -108,6 +108,16 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); static void hub_release(struct kref *kref); static int usb_reset_and_verify_device(struct usb_device *udev); static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); +static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1, + u16 portstatus); +static int hub_port_reset(struct usb_hub *hub, int port1, + struct usb_device *udev, unsigned int delay, bool warm); + +#define HUB_ROOT_RESET_TIME 60 /* times are in msec */ +#define HUB_SHORT_RESET_TIME 10 +#define HUB_BH_RESET_TIME 50 +#define HUB_LONG_RESET_TIME 200 +#define HUB_RESET_TIMEOUT 800 static inline char *portspeed(struct usb_hub *hub, int portstatus) { @@ -1122,6 +1132,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) USB_SS_PORT_LS_POLLING)) need_debounce_delay = true; + if (type == HUB_RESUME && + hub_port_warm_reset_required(hub, port1, portstatus)) + hub_port_reset(hub, port1, udev, + HUB_BH_RESET_TIME, true); + /* Clear status-change flags; we'll debounce later */ if (portchange & USB_PORT_STAT_C_CONNECTION) { need_debounce_delay = true; @@ -2653,12 +2668,6 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) #define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)scheme) -#define HUB_ROOT_RESET_TIME 60 /* times are in msec */ -#define HUB_SHORT_RESET_TIME 10 -#define HUB_BH_RESET_TIME 50 -#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
On plug-in of my USB-C device, its USB_SS_PORT_LS_SS_INACTIVE link state bit is set. Greping all the kernel for this bit shows that the port status requests a warm-reset this way. This just happens, if its the only device on that hub and the hub resumes, so we don't call port_event, which would otherwise warm-reset ports. The device works ok without this patch, if there is already any other device connected to the hub. Signed-off-by: Jan-Marek Glogowski <glogow@fbihome.de> --- v1: This always warm-resets the ports in hub_activate, independent of the "enum hub_activation_type". Just had a single device to test. v2: I had the idea about the working device, if there is already a device connected to the hub and that a resume only on "type == HUB_RESUME" should be sufficient. This still works for me, but I didn't follow all the hub_activate callers everywhere and I'm definitly still missing a lot of knowledge about USB stuff. There is also HUB_RESET_RESUME with a slightly different code path. I don't know how to trigger this. v3: code unchanged to v2, so I could abandon my explanation mail, which I was typing when Gregs mail arrived. --- drivers/usb/core/hub.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)