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.willi...@intel.com>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to