[RFC] xhci: Let completion handlers run before rings are restarted.

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

 



Hans, can you please test this patch?

>8---------------------------------------------------------------------8<

Hans reported an issue with the USBDEVFS_URB_BULK_CONTINUATION flag that
is used by libusb and devio (usbfs).  This causes his usb redirection
code, and large bulk transfers, to not work under an xHCI host
controller.

It's explained in the kerneldoc for for usb_unlink_urb() that the host
controller driver is expected to allow URB completion handlers to run on
an error before restarting the endpoint ring:

 * Host Controller Drivers (HCDs) place all the URBs for a particular
 * endpoint in a queue.  Normally the queue advances as the controller
 * hardware processes each request.  But when an URB terminates with an
 * error its queue generally stops (see below), at least until that URB's
 * completion routine returns.  It is guaranteed that a stopped queue
 * will not restart until all its unlinked URBs have been fully retired,
 * with their completion routines run, even if that's not until some time
 * after the original completion handler returns.  The same behavior and
 * guarantee apply when an URB terminates because it was unlinked.
 *
 * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
 * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
 * and -EREMOTEIO.  Control endpoint queues behave the same way except
 * that they are not guaranteed to stop for -EREMOTEIO errors.  Queues
 * for isochronous endpoints are treated differently, because they must
 * advance at fixed rates.  Such queues do not stop when an URB
 * encounters an error or is unlinked.  An unlinked isochronous URB may
 * leave a gap in the stream of packets; it is undefined whether such
 * gaps can be filled in.
 *
 * Note that early termination of an URB because a short packet was
 * received will generate a -EREMOTEIO error if and only if the
 * URB_SHORT_NOT_OK flag is set.  By setting this flag, USB device
 * drivers can build deep queues for large or complex bulk transfers
 * and clean them up reliably after any sort of aborted transfer by
 * unlinking all pending URBs at the first fault.
 *
 * When a control URB terminates with an error other than -EREMOTEIO, it
 * is quite likely that the status stage of the transfer will not take
 * place.

This patch changes the xHCI ring handling code to allow the URB
completion handler to run before ringing the doorbell on an endpoint
ring.  This means adding a new flag to prevent the doorbell ring
(EP_STAY_HALTED), to avoid a race condition with the URB completion
handler and a completing Set TR Dequeue Pointer command (which will
restart the ring).  The new flag temporarily stops the ring until the
URB completion function has a chance to cancel any pending URBs.  That
will set a different cancellation pending flag, which will also halt the
endpoint ring.

Make sure to set the new EP_STAY_HALTED flag before calling
xhci_cleanup_halted_endpoint().  That function will queue a Set TR
Dequeue command, which will ring the doorbell and restart the ring after
it completes.  We need to make sure that the URB completion handlers
have a chance to run before the ring is restarted.

This patch should be backported to kernels as old as 2.6.36, because
that was the first kernel where the xHCI ring code refactoring was
introduced.  It will be too hard to port this to the unrefactored code.

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
Cc: Hans de Goede <hdegoede@xxxxxxxxxx>
Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
---
 drivers/usb/host/xhci-ring.c |   31 +++++++++++++++++++++++++++++--
 drivers/usb/host/xhci.h      |    5 +++++
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 23b4aef..890aadf 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -295,7 +295,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
 	 * FIXME - check all the stream rings for pending cancellations.
 	 */
 	if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) ||
-	    (ep_state & EP_HALTED))
+	    (ep_state & EP_HALTED) || (ep_state & EP_STAY_HALTED))
 		return;
 	xhci_writel(xhci, DB_VALUE(ep_index, stream_id), db_addr);
 	/* The CPU has better things to do at this point than wait for a
@@ -1594,12 +1594,20 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
 			 * pointer past the TD.  We can't do that here because
 			 * the halt condition must be cleared first.  Let the
 			 * USB class driver clear the stall later.
+			 *
+			 * The endpoint will remain halted until the stall is
+			 * cleared, so completion handlers will run before the
+			 * ring is restarted.
 			 */
 			ep->stopped_td = td;
 			ep->stopped_trb = event_trb;
 			ep->stopped_stream = ep_ring->stream_id;
 		} else if (xhci_requires_manual_halt_cleanup(xhci,
 					ep_ctx, trb_comp_code)) {
+			/* Let the URB completion handlers run before restarting
+			 * the endpoint ring.
+			 */
+			ep->ep_state |= EP_STAY_HALTED;
 			/* Other types of errors halt the endpoint, but the
 			 * class driver doesn't call usb_reset_endpoint() unless
 			 * the error is -EPIPE.  Clear the halted status in the
@@ -1658,6 +1666,14 @@ td_cleanup:
 		}
 	}
 
+	/* If we've only kept the ring halted in order for the completion
+	 * handlers to run (and not because the ring is halted by a STALL), then
+	 * restart the ring.
+	 */
+	if (ep->ep_state & EP_STAY_HALTED) {
+		ep->ep_state &= ~EP_STAY_HALTED;
+		xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0);
+	}
 	return ret;
 }
 
@@ -1674,6 +1690,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
 	int ep_index;
 	struct xhci_ep_ctx *ep_ctx;
 	u32 trb_comp_code;
+	int ret;
 
 	slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
 	xdev = xhci->devs[slot_id];
@@ -1723,9 +1740,19 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
 		else
 			td->urb->actual_length = 0;
 
+		/* Let the URB completion handlers run before restarting the
+		 * endpoint ring.  finish_td() won't set the EP_STAY_HALTED flag
+		 * for COMP_STALL.  We have to set it ourselves before we call
+		 * xhci_cleanup_halted_endpoint(), since that will queue a Set
+		 * TR Dequeue command, which may restart the ring on completion.
+		 */
+		ep->ep_state |= EP_STAY_HALTED;
 		xhci_cleanup_halted_endpoint(xhci,
 			slot_id, ep_index, 0, td, event_trb);
-		return finish_td(xhci, td, event_trb, event, ep, status, true);
+		ret = finish_td(xhci, td, event_trb, event, ep, status, true);
+		ep->ep_state &= ~EP_STAY_HALTED;
+		xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0);
+		return ret;
 	}
 	/*
 	 * Did we transfer any data, despite the errors that might have
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 55c0785..95907ee 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -835,6 +835,11 @@ struct xhci_virt_ep {
 #define EP_HAS_STREAMS		(1 << 4)
 /* Transitioning the endpoint to not using streams, don't enqueue URBs */
 #define EP_GETTING_NO_STREAMS	(1 << 5)
+/* Stop endpoint ring temporarily until completion handlers have a chance to
+ * cancel any outstanding URBs.  URB cancellation will set the EP_HALT_PENDING
+ * flag, which will stop the endpoint ring until all cancellations are complete.
+ */
+#define EP_STAY_HALTED		(1 << 6)
 	/* ----  Related to URB cancellation ---- */
 	struct list_head	cancelled_td_list;
 	/* The TRB that was last reported in a stopped endpoint ring */
-- 
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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux