Skip to content

Commit d77efd7

Browse files
matnymangregkh
authored andcommitted
xhci: fix stale flag preventig URBs after link state error is cleared
commit b69dfca upstream. A usb device caught behind a link in ss.Inactive error state needs to be reset to recover. A VDEV_PORT_ERROR flag is used to track this state, preventing new transfers from being queued until error is cleared. This flag may be left uncleared if link goes to error state between two resets, and print the following message: "xhci_hcd 0000:00:14.0: Can't queue urb, port error, link inactive" Fix setting and clearing the flag. The flag is cleared after hub driver has successfully reset the device when hcd->reset_device is called. xhci-hcd issues an internal "reset device" command in this callback, and clear all flags once the command completes successfully. This command may complete with a context state error if slot was recently reset and is already in the defauilt state. This is treated as a success but flag was left uncleared. The link state field is also unreliable if port is currently in reset, so don't set the flag in active reset cases. Also clear the flag immediately when link is no longer in ss.Inactive state and port event handler detects a completed reset. This issue was discovered while debugging kernel bugzilla issue 220491. It is likely one small part of the problem, causing some of the failures, but root cause remains unknown Link: https://bugzilla.kernel.org/show_bug.cgi?id=220491 Fixes: b8c3b71 ("usb: xhci: Don't try to recover an endpoint if port is in error state.") Cc: stable@vger.kernel.org Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://patch.msgid.link/20251107162819.1362579-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7cfb628 commit d77efd7

File tree

2 files changed

+11
-5
lines changed

2 files changed

+11
-5
lines changed

drivers/usb/host/xhci-ring.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,7 @@ static void xhci_cavium_reset_phy_quirk(struct xhci_hcd *xhci)
19501950

19511951
static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
19521952
{
1953+
struct xhci_virt_device *vdev = NULL;
19531954
struct usb_hcd *hcd;
19541955
u32 port_id;
19551956
u32 portsc, cmd_reg;
@@ -1981,6 +1982,9 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
19811982
goto cleanup;
19821983
}
19831984

1985+
if (port->slot_id)
1986+
vdev = xhci->devs[port->slot_id];
1987+
19841988
/* We might get interrupts after shared_hcd is removed */
19851989
if (port->rhub == &xhci->usb3_rhub && xhci->shared_hcd == NULL) {
19861990
xhci_dbg(xhci, "ignore port event for removed USB3 hcd\n");
@@ -2003,10 +2007,11 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
20032007
usb_hcd_resume_root_hub(hcd);
20042008
}
20052009

2006-
if (hcd->speed >= HCD_USB3 &&
2007-
(portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
2008-
if (port->slot_id && xhci->devs[port->slot_id])
2009-
xhci->devs[port->slot_id]->flags |= VDEV_PORT_ERROR;
2010+
if (vdev && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
2011+
if (!(portsc & PORT_RESET))
2012+
vdev->flags |= VDEV_PORT_ERROR;
2013+
} else if (vdev && portsc & PORT_RC) {
2014+
vdev->flags &= ~VDEV_PORT_ERROR;
20102015
}
20112016

20122017
if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
@@ -2064,7 +2069,7 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
20642069
* so the roothub behavior is consistent with external
20652070
* USB 3.0 hub behavior.
20662071
*/
2067-
if (port->slot_id && xhci->devs[port->slot_id])
2072+
if (vdev)
20682073
xhci_ring_device(xhci, port->slot_id);
20692074
if (bus_state->port_remote_wakeup & (1 << hcd_portnum)) {
20702075
xhci_test_and_clear_bit(xhci, port, PORT_PLC);

drivers/usb/host/xhci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,6 +3818,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
38183818
xhci_get_slot_state(xhci, virt_dev->out_ctx));
38193819
xhci_dbg(xhci, "Not freeing device rings.\n");
38203820
/* Don't treat this as an error. May change my mind later. */
3821+
virt_dev->flags = 0;
38213822
ret = 0;
38223823
goto command_cleanup;
38233824
case COMP_SUCCESS:

0 commit comments

Comments
 (0)