Patch "usb: xhci: Avoid queuing redundant Stop Endpoint commands" has been added to the 6.1-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    usb: xhci: Avoid queuing redundant Stop Endpoint commands

to the 6.1-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     usb-xhci-avoid-queuing-redundant-stop-endpoint-comma.patch
and it can be found in the queue-6.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit db66bee3322c0856cc7df385602f69ae6784d999
Author: Michal Pecio <michal.pecio@xxxxxxxxx>
Date:   Wed Nov 6 12:14:59 2024 +0200

    usb: xhci: Avoid queuing redundant Stop Endpoint commands
    
    [ Upstream commit 474538b8dd1cd9c666e56cfe8ef60fbb0fb513f4 ]
    
    Stop Endpoint command on an already stopped endpoint fails and may be
    misinterpreted as a known hardware bug by the completion handler. This
    results in an unnecessary delay with repeated retries of the command.
    
    Avoid queuing this command when endpoint state flags indicate that it's
    stopped or halted and the command will fail. If commands are pending on
    the endpoint, their completion handlers will process cancelled TDs so
    it's done. In case of waiting for external operations like clearing TT
    buffer, the endpoint is stopped and cancelled TDs can be processed now.
    
    This eliminates practically all unnecessary retries because an endpoint
    with pending URBs is maintained in Running state by the driver, unless
    aforementioned commands or other operations are pending on it. This is
    guaranteed by xhci_ring_ep_doorbell() and by the fact that it is called
    every time any of those operations completes.
    
    The only known exceptions are hardware bugs (the endpoint never starts
    at all) and Stream Protocol errors not associated with any TRB, which
    cause an endpoint reset not followed by restart. Sounds like a bug.
    
    Generally, these retries are only expected to happen when the endpoint
    fails to start for unknown/no reason, which is a worse problem itself,
    and fixing the bug eliminates the retries too.
    
    All cases were tested and found to work as expected. SET_DEQ_PENDING
    was produced by patching uvcvideo to unlink URBs in 100us intervals,
    which then runs into this case very often. EP_HALTED was produced by
    restarting 'cat /dev/ttyUSB0' on a serial dongle with broken cable.
    EP_CLEARING_TT by the same, with the dongle on an external hub.
    
    Fixes: fd9d55d190c0 ("xhci: retry Stop Endpoint on buggy NEC controllers")
    CC: stable@xxxxxxxxxxxxxxx
    Signed-off-by: Michal Pecio <michal.pecio@xxxxxxxxx>
    Signed-off-by: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20241106101459.775897-34-mathias.nyman@xxxxxxxxxxxxxxx
    Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e5b2a3b551e3..2503022a3123 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1052,6 +1052,19 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
 	return 0;
 }
 
+/*
+ * Erase queued TDs from transfer ring(s) and give back those the xHC didn't
+ * stop on. If necessary, queue commands to move the xHC off cancelled TDs it
+ * stopped on. Those will be given back later when the commands complete.
+ *
+ * Call under xhci->lock on a stopped endpoint.
+ */
+void xhci_process_cancelled_tds(struct xhci_virt_ep *ep)
+{
+	xhci_invalidate_cancelled_tds(ep);
+	xhci_giveback_invalidated_tds(ep);
+}
+
 /*
  * Returns the TD the endpoint ring halted on.
  * Only call for non-running rings without streams.
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ae14c7ade9bc..e726c5edee03 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1903,10 +1903,21 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 		}
 	}
 
-	/* Queue a stop endpoint command, but only if this is
-	 * the first cancellation to be handled.
-	 */
-	if (!(ep->ep_state & EP_STOP_CMD_PENDING)) {
+	/* These completion handlers will sort out cancelled TDs for us */
+	if (ep->ep_state & (EP_STOP_CMD_PENDING | EP_HALTED | SET_DEQ_PENDING)) {
+		xhci_dbg(xhci, "Not queuing Stop Endpoint on slot %d ep %d in state 0x%x\n",
+				urb->dev->slot_id, ep_index, ep->ep_state);
+		goto done;
+	}
+
+	/* In this case no commands are pending but the endpoint is stopped */
+	if (ep->ep_state & EP_CLEARING_TT) {
+		/* and cancelled TDs can be given back right away */
+		xhci_dbg(xhci, "Invalidating TDs instantly on slot %d ep %d in state 0x%x\n",
+				urb->dev->slot_id, ep_index, ep->ep_state);
+		xhci_process_cancelled_tds(ep);
+	} else {
+		/* Otherwise, queue a new Stop Endpoint command */
 		command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
 		if (!command) {
 			ret = -ENOMEM;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index a75b8122538d..1a641f281c00 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1952,6 +1952,7 @@ void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
 void xhci_cleanup_command_queue(struct xhci_hcd *xhci);
 void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring);
 unsigned int count_trbs(u64 addr, u64 len);
+void xhci_process_cancelled_tds(struct xhci_virt_ep *ep);
 
 /* xHCI roothub code */
 void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port,




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux