OSDN Git Service

xhci: Check for pending reset endpoint command before queueing a new one.
authorMathias Nyman <mathias.nyman@linux.intel.com>
Fri, 29 Jan 2021 13:00:43 +0000 (15:00 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 29 Jan 2021 13:16:52 +0000 (14:16 +0100)
A halted endpoint can be detected both when transfer events complete, and
in stop endpoint command completion. Both these handlers will start
clearing up the halted endpoint and queue a reset endpoint command.

It's possible to get both events for the same halted endpoint if right
after a URB cancel queues a stop endpoint command the endpoint stalls.
Use the EP_HALTED flag to prevent resetting the endpoint twice.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20210129130044.206855-27-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-ring.c

index 1440041..26f5557 100644 (file)
@@ -873,8 +873,6 @@ static void xhci_handle_halted_endpoint(struct xhci_hcd *xhci,
        if (ep->vdev->flags & VDEV_PORT_ERROR)
                return;
 
-       ep->ep_state |= EP_HALTED;
-
        /* add td to cancelled list and let reset ep handler take care of it */
        if (reset_type == EP_HARD_RESET) {
                ep->ep_state |= EP_HARD_CLEAR_TOGGLE;
@@ -884,10 +882,17 @@ static void xhci_handle_halted_endpoint(struct xhci_hcd *xhci,
                }
        }
 
+       if (ep->ep_state & EP_HALTED) {
+               xhci_dbg(xhci, "Reset ep command already pending\n");
+               return;
+       }
+
        err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type);
        if (err)
                return;
 
+       ep->ep_state |= EP_HALTED;
+
        xhci_ring_cmd_db(xhci);
 }
 
@@ -2575,7 +2580,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        case COMP_STALL_ERROR:
                xhci_dbg(xhci, "Stalled endpoint for slot %u ep %u\n", slot_id,
                         ep_index);
-               ep->ep_state |= EP_HALTED;
                status = -EPIPE;
                break;
        case COMP_SPLIT_TRANSACTION_ERROR: