Skip to content

Commit 98d74f9

Browse files
matnymangregkh
authored andcommitted
xhci: fix 10 second timeout on removal of PCI hotpluggable xhci controllers
PCI hotpluggable xhci controllers such as some Alpine Ridge solutions will remove the xhci controller from the PCI bus when the last USB device is disconnected. Add a flag to indicate that the host is being removed to avoid queueing configure_endpoint commands for the dropped endpoints. For PCI hotplugged controllers this will prevent 5 second command timeouts For static xhci controllers the configure_endpoint command is not needed in the removal case as everything will be returned, freed, and the controller is reset. For now the flag is only set for PCI connected host controllers. Cc: <stable@vger.kernel.org> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7150406 commit 98d74f9

File tree

4 files changed

+9
-4
lines changed

4 files changed

+9
-4
lines changed

drivers/usb/host/xhci-pci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ static void xhci_pci_remove(struct pci_dev *dev)
304304
struct xhci_hcd *xhci;
305305

306306
xhci = hcd_to_xhci(pci_get_drvdata(dev));
307+
xhci->xhc_state |= XHCI_STATE_REMOVING;
307308
if (xhci->shared_hcd) {
308309
usb_remove_hcd(xhci->shared_hcd);
309310
usb_put_hcd(xhci->shared_hcd);

drivers/usb/host/xhci-ring.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4004,7 +4004,8 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
40044004
int reserved_trbs = xhci->cmd_ring_reserved_trbs;
40054005
int ret;
40064006

4007-
if (xhci->xhc_state) {
4007+
if ((xhci->xhc_state & XHCI_STATE_DYING) ||
4008+
(xhci->xhc_state & XHCI_STATE_HALTED)) {
40084009
xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n");
40094010
return -ESHUTDOWN;
40104011
}

drivers/usb/host/xhci.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ static int xhci_start(struct xhci_hcd *xhci)
147147
"waited %u microseconds.\n",
148148
XHCI_MAX_HALT_USEC);
149149
if (!ret)
150-
xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING);
150+
/* clear state flags. Including dying, halted or removing */
151+
xhci->xhc_state = 0;
151152

152153
return ret;
153154
}
@@ -2773,7 +2774,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
27732774
if (ret <= 0)
27742775
return ret;
27752776
xhci = hcd_to_xhci(hcd);
2776-
if (xhci->xhc_state & XHCI_STATE_DYING)
2777+
if ((xhci->xhc_state & XHCI_STATE_DYING) ||
2778+
(xhci->xhc_state & XHCI_STATE_REMOVING))
27772779
return -ENODEV;
27782780

27792781
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
@@ -3820,7 +3822,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
38203822

38213823
mutex_lock(&xhci->mutex);
38223824

3823-
if (xhci->xhc_state) /* dying or halted */
3825+
if (xhci->xhc_state) /* dying, removing or halted */
38243826
goto out;
38253827

38263828
if (!udev->slot_id) {

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,7 @@ struct xhci_hcd {
16051605
*/
16061606
#define XHCI_STATE_DYING (1 << 0)
16071607
#define XHCI_STATE_HALTED (1 << 1)
1608+
#define XHCI_STATE_REMOVING (1 << 2)
16081609
/* Statistics */
16091610
int error_bitmask;
16101611
unsigned int quirks;

0 commit comments

Comments
 (0)