[RFC PATCH 16/20] xhci: refactor prepare_transfer()

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

 



In preparation for honoring xhci-v1.0+ td-fragment handling rules break
out the subroutines of prepare_transfer().  Rather than calculating the
number of trbs required and expanding the ring, v1.0+ hosts will
dynamically resize the ring as it discovers td-fragments that end up
straddling a segment boundary.

Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
---
 drivers/usb/host/xhci-ring.c |  122 ++++++++++++++++++++++++------------------
 1 files changed, 70 insertions(+), 52 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 27d271e26445..3a9ed6543dfe 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2920,10 +2920,69 @@ static void queue_trb(struct xhci_ring *ring, bool more_trbs_coming,
  * FIXME allocate segments if the ring is full.
  */
 static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
-		u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
+		unsigned int num_trbs, gfp_t mem_flags)
 {
 	unsigned int num_trbs_needed;
 
+	while (1) {
+		if (room_on_ring(xhci, ep_ring, num_trbs))
+			break;
+
+		if (ep_ring == xhci->cmd_ring) {
+			xhci_err(xhci, "Do not support expand command ring\n");
+			return -ENOMEM;
+		}
+
+		xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
+				"ERROR no room on ep ring, try ring expansion");
+		num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
+		if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
+					mem_flags)) {
+			xhci_err(xhci, "Ring expansion failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	if (enqueue_is_link_trb(ep_ring))
+		advance_enq(ep_ring, 0, do_carry_chain(xhci, ep_ring));
+	return 0;
+}
+
+static int prepare_td(struct xhci_ring *ring, struct urb *urb,
+		unsigned int td_index)
+{
+	struct urb_priv *urb_priv;
+	struct xhci_td *td;
+
+	urb_priv = urb->hcpriv;
+	td = urb_priv->td[td_index];
+
+	INIT_LIST_HEAD(&td->td_list);
+	INIT_LIST_HEAD(&td->cancelled_td_list);
+
+	if (td_index == 0) {
+		struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+		int ret = usb_hcd_link_urb_to_ep(hcd, urb);
+
+		if (ret)
+			return ret;
+	}
+
+	td->urb = urb;
+	/* Add this TD to the tail of the endpoint ring's TD list */
+	list_add_tail(&td->td_list, &ring->td_list);
+	td->start_seg = ring->enq.seg;
+	td->first_trb = xhci_ring_enqueue(ring);
+	urb_priv->td[td_index] = td;
+
+	return 0;
+}
+
+static int check_ep_submit_state(struct xhci_hcd *xhci,
+		struct xhci_ep_ctx *ep_ctx)
+{
+	u32 ep_state = le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK;
+
 	/* Make sure the endpoint has been added to xHC schedule */
 	switch (ep_state) {
 	case EP_STATE_DISABLED:
@@ -2951,28 +3010,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
 		 */
 		return -EINVAL;
 	}
-
-	while (1) {
-		if (room_on_ring(xhci, ep_ring, num_trbs))
-			break;
-
-		if (ep_ring == xhci->cmd_ring) {
-			xhci_err(xhci, "Do not support expand command ring\n");
-			return -ENOMEM;
-		}
-
-		xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
-				"ERROR no room on ep ring, try ring expansion");
-		num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
-		if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
-					mem_flags)) {
-			xhci_err(xhci, "Ring expansion failed\n");
-			return -ENOMEM;
-		}
-	}
-
-	if (enqueue_is_link_trb(ep_ring))
-		advance_enq(ep_ring, 0, do_carry_chain(xhci, ep_ring));
 	return 0;
 }
 
@@ -2986,8 +3023,6 @@ static int prepare_transfer(struct xhci_hcd *xhci,
 		gfp_t mem_flags)
 {
 	int ret;
-	struct urb_priv *urb_priv;
-	struct xhci_td	*td;
 	struct xhci_ring *ep_ring;
 	struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
 
@@ -2998,33 +3033,15 @@ static int prepare_transfer(struct xhci_hcd *xhci,
 		return -EINVAL;
 	}
 
-	ret = prepare_ring(xhci, ep_ring,
-			   le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, mem_flags);
+	ret = check_ep_submit_state(xhci, ep_ctx);
 	if (ret)
 		return ret;
 
-	urb_priv = urb->hcpriv;
-	td = urb_priv->td[td_index];
-
-	INIT_LIST_HEAD(&td->td_list);
-	INIT_LIST_HEAD(&td->cancelled_td_list);
-
-	if (td_index == 0) {
-		ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb);
-		if (unlikely(ret))
-			return ret;
-	}
-
-	td->urb = urb;
-	/* Add this TD to the tail of the endpoint ring's TD list */
-	list_add_tail(&td->td_list, &ep_ring->td_list);
-	td->start_seg = ep_ring->enq.seg;
-	td->first_trb = xhci_ring_enqueue(ep_ring);
-
-	urb_priv->td[td_index] = td;
+	ret = prepare_ring(xhci, ep_ring, num_trbs, mem_flags);
+	if (ret)
+		return ret;
 
-	return 0;
+	return prepare_td(ep_ring, urb, td_index);
 }
 
 static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
@@ -3872,8 +3889,10 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
 	/* Check the ring to guarantee there is enough room for the whole urb.
 	 * Do not insert any td of the urb to the ring if the check failed.
 	 */
-	ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
-			   num_trbs, mem_flags);
+	ret = check_ep_submit_state(xhci, ep_ctx);
+	if (ret)
+		return ret;
+	ret = prepare_ring(xhci, ep_ring, num_trbs, mem_flags);
 	if (ret)
 		return ret;
 
@@ -3930,8 +3949,7 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
 	if (!command_must_succeed)
 		reserved_trbs++;
 
-	ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
-			reserved_trbs, GFP_ATOMIC);
+	ret = prepare_ring(xhci, xhci->cmd_ring, reserved_trbs, GFP_ATOMIC);
 	if (ret < 0) {
 		xhci_err(xhci, "ERR: No room for command on command ring\n");
 		if (command_must_succeed)

--
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