There are two locations where we advance the enqueue pointer through a
chain of link trbs, in inc_enq() and prepare_ring().  Factor that into a
common advance_enq().  Also, in preparation for per-ring operations
factor out the differences between the event-rings, chain-quirk-rings
and normal endpoint rings into event_ring_inc_enq() and
common_inc_enq().

Unfortunately this isn't a net win in the diffstat, but it does
eliminate the liability of failing to update one of the instances
especially in preparation for overhauling TD-fragment handling for
xhci1.0+ hosts.

Signed-off-by: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/usb/host/xhci-ring.c |  164 ++++++++++++++++++++++--------------------
 1 files changed, 86 insertions(+), 78 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index bee5c18b0509..d8c9a8211ace 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -171,9 +171,39 @@ static void inc_deq(struct xhci_ring *ring)
 }
 
 /*
- * See Cycle bit rules. SW is the consumer for the event ring only.
- * Don't make a ring full of link TRBs.  That would be dumb and this would 
loop.
- *
+ * Don't make a ring full of link TRBs.  That would be dumb and this
+ * would loop.
+ */
+static void advance_enq(struct xhci_ring *ring, u32 chain, bool do_carry_chain)
+{
+       union xhci_trb *next = ring->enqueue;
+
+       /*
+        * Update the enqueue pointer further if we're now pointing to a
+        * link TRB
+        */
+       while (last_trb(ring, ring->enq_seg, next)) {
+               if (do_carry_chain) {
+                       next->link.control &= cpu_to_le32(~TRB_CHAIN);
+                       next->link.control |= cpu_to_le32(chain);
+               } else {
+                       next->link.control |= cpu_to_le32(TRB_CHAIN);
+               }
+
+               /* Give this link TRB to the hardware */
+               wmb();
+               next->link.control ^= cpu_to_le32(TRB_CYCLE);
+
+               /* Toggle the cycle bit after the last ring segment. */
+               if (last_trb_on_last_seg(ring, ring->enq_seg, next))
+                       ring->cycle_state ^= 1;
+               ring->enq_seg = xhci_segment_next(ring, ring->enq_seg);
+               ring->enqueue = ring->enq_seg->trbs;
+               next = ring->enqueue;
+       }
+}
+
+/*
  * If we've just enqueued a TRB that is in the middle of a TD (meaning the
  * chain bit is set), then set the chain bit in all the following link TRBs.
  * If we've enqueued the last TRB in a TD, make sure the following link TRBs
@@ -187,63 +217,68 @@ static void inc_deq(struct xhci_ring *ring)
  * @more_trbs_coming:  Will you enqueue more TRBs before calling
  *                     prepare_transfer()?
  */
-static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
-                       bool more_trbs_coming)
+static void common_inc_enq(struct xhci_ring *ring, bool more_trbs_coming,
+               bool do_carry_chain)
 {
-       u32 chain;
-       union xhci_trb *next;
-
-       chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
-       /* If this is not event ring, there is one less usable TRB */
-       if (ring->type != TYPE_EVENT &&
-                       !last_trb(ring, ring->enq_seg, ring->enqueue))
-               ring->num_trbs_free--;
-       next = ++(ring->enqueue);
+       u32 chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
 
+       ring->num_trbs_free--;
+       (ring->enqueue)++;
        ring->enq_updates++;
-       /* Update the dequeue pointer further if that was a link TRB or we're at
-        * the end of an event ring segment (which doesn't have link TRBS)
+
+       /*
+        * If the caller doesn't plan on enqueueing more TDs before
+        * ringing the doorbell, then we don't want to give the link TRB
+        * to the hardware just yet.  We'll give the link TRB back in
+        * prepare_ring() just before we enqueue the TD at the top of
+        * the ring.
         */
-       while (last_trb(ring, ring->enq_seg, next)) {
-               if (ring->type != TYPE_EVENT) {
-                       /*
-                        * If the caller doesn't plan on enqueueing more
-                        * TDs before ringing the doorbell, then we
-                        * don't want to give the link TRB to the
-                        * hardware just yet.  We'll give the link TRB
-                        * back in prepare_ring() just before we enqueue
-                        * the TD at the top of the ring.
-                        */
-                       if (!chain && !more_trbs_coming)
-                               break;
+       if (!chain && !more_trbs_coming)
+               return;
+       advance_enq(ring, chain, do_carry_chain);
+}
 
-                       /* If we're not dealing with 0.95 hardware or
-                        * isoc rings on AMD 0.96 host,
-                        * carry over the chain bit of the previous TRB
-                        * (which may mean the chain bit is cleared).
-                        */
-                       if (!(ring->type == TYPE_ISOC &&
-                                       (xhci->quirks & XHCI_AMD_0x96_HOST))
-                                               && !xhci_link_trb_quirk(xhci)) {
-                               next->link.control &=
-                                       cpu_to_le32(~TRB_CHAIN);
-                               next->link.control |=
-                                       cpu_to_le32(chain);
-                       }
-                       /* Give this link TRB to the hardware */
-                       wmb();
-                       next->link.control ^= cpu_to_le32(TRB_CYCLE);
+/*
+ * See Cycle bit rules. SW is the consumer for the event ring only.
+ */
+static void event_inc_enq(struct xhci_ring *ring)
+{
+       union xhci_trb *next;
 
-                       /* Toggle the cycle bit after the last ring segment. */
-                       if (last_trb_on_last_seg(ring, ring->enq_seg, next))
-                               ring->cycle_state ^= 1;
-               }
+       next = ++(ring->enqueue);
+       ring->enq_updates++;
+
+       /*
+        * Fix up the enqueue pointer if we're at the end of an event
+        * ring segment (which doesn't have link TRBS)
+        */
+       if (last_trb(ring, ring->enq_seg, next)) {
                ring->enq_seg = xhci_segment_next(ring, ring->enq_seg);
                ring->enqueue = ring->enq_seg->trbs;
-               next = ring->enqueue;
        }
 }
 
+static bool do_carry_chain(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+       /*
+        * With 0.95 hardware or isoc rings on AMD 0.96 host, don't
+        * carry over the chain bit of the previous TRB (which may mean
+        * the chain bit is cleared).
+        */
+       return !(xhci_link_trb_quirk(xhci) || (ring->type == TYPE_ISOC
+                       && (xhci->quirks & XHCI_AMD_0x96_HOST)));
+}
+
+static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
+                       bool more_trbs_coming)
+{
+       if (ring->type == TYPE_EVENT)
+               event_inc_enq(ring);
+       else
+               common_inc_enq(ring, more_trbs_coming,
+                               do_carry_chain(xhci, ring));
+}
+
 /*
  * Check to see if there's room to enqueue num_trbs on the ring and make sure
  * enqueue pointer will not advance into dequeue segment. See rules above.
@@ -2849,35 +2884,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct 
xhci_ring *ep_ring,
                }
        }
 
-       if (enqueue_is_link_trb(ep_ring)) {
-               struct xhci_ring *ring = ep_ring;
-               union xhci_trb *next;
-
-               next = ring->enqueue;
-
-               while (last_trb(ring, ring->enq_seg, next)) {
-                       /* If we're not dealing with 0.95 hardware or isoc rings
-                        * on AMD 0.96 host, clear the chain bit.
-                        */
-                       if (!xhci_link_trb_quirk(xhci) &&
-                                       !(ring->type == TYPE_ISOC &&
-                                        (xhci->quirks & XHCI_AMD_0x96_HOST)))
-                               next->link.control &= cpu_to_le32(~TRB_CHAIN);
-                       else
-                               next->link.control |= cpu_to_le32(TRB_CHAIN);
-
-                       wmb();
-                       next->link.control ^= cpu_to_le32(TRB_CYCLE);
-
-                       /* Toggle the cycle bit after the last ring segment. */
-                       if (last_trb_on_last_seg(ring, ring->enq_seg, next))
-                               ring->cycle_state ^= 1;
-                       ring->enq_seg = xhci_segment_next(ring, ring->enq_seg);
-                       ring->enqueue = ring->enq_seg->trbs;
-                       next = ring->enqueue;
-               }
-       }
-
+       if (enqueue_is_link_trb(ep_ring))
+               advance_enq(ep_ring, 0, do_carry_chain(xhci, ep_ring));
        return 0;
 }
 

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