The USB core disables the USB 2.0 ports in several different error cases. It expects that all USB hubs will act like external hubs, and always return an interrupt event if a port change bit is set. External USB 2.0 and USB 3.0 hubs are level-triggered, so this works for them. However, xHCI roothubs are edge-triggered. If no port status change bits are set, and a new change bit is set, the xHCI host sends an interrupt and a Port Status Change Event. It will not generate another port event until all change bits are cleared and a new one is set. This opens up issues with the USB core port disabling code. Right now, it assumes that it can simply clear the port enable bit, and wait for the hub to send an interrupt when a change bit is set. If previous change bits weren't cleared, it's assumed to be fine because the hub will continue to remind the USB core about them through the interrupt endpoint. This doesn't work for USB 2.0 roothub ports under xHCI. If we don't atomically clear an already-set change bit as we disable the port, the xHC will not send an interrupt on a new change bit. This means that we'll lose device connect notifications. An example scenario: - hub_port_init notices a device connect, and resets the port - USB 2.0 reset fails because the device disconnected - xHC sets the connect status change (CSC) bit and reset change bit - hub_port_reset clears the reset change bit - hub_port_init immediately goes to disable the port without clearing the CSC bit - xHC disables the port - The device reconnects. However, the CSC bit is already set, so the xHC never interrupts with a Port Status Change event. We could attempt to clear any port status change bits in the USB core's port disable function before the port is disabled. However, that's racy because a change bit could be set in between any of the five necessary Clear Port Feature calls to clear a change bit. It's also not useful for external hubs (since they are level-triggered), so the atomic change bit clearing code belongs in the xHCI host hub code. This patch should be backported to stable kernels as old as 2.6.34, that contain the commit 6219c047d3fe18dee4916d6898fc94f5a7ffd156 "USB: xhci: Allow roothub ports to be disabled." Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx --- drivers/usb/host/xhci-hub.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a686cf4..7d9dcd6 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -340,6 +340,10 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, return; } + /* Clear all change bits, so that we get a device connect event. */ + port_status |= PORT_CSC | PORT_PEC | PORT_WRC | + PORT_OCC | PORT_RC | PORT_PLC | + PORT_CEC; /* Write 1 to disable the port */ xhci_writel(xhci, port_status | PORT_PE, addr); port_status = xhci_readl(xhci, addr); -- 1.7.9 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html