xhci: Stop unnecessary tracking of free trbs in a ring
[platform/kernel/linux-rpi.git] / drivers / usb / host / xhci-ring.c
index 1ad12d5..646ff12 100644 (file)
@@ -174,12 +174,10 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 
        /* All other rings have link trbs */
        if (!trb_is_link(ring->dequeue)) {
-               if (last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
+               if (last_trb_on_seg(ring->deq_seg, ring->dequeue))
                        xhci_warn(xhci, "Missing link TRB at end of segment\n");
-               } else {
+               else
                        ring->dequeue++;
-                       ring->num_trbs_free++;
-               }
        }
 
        while (trb_is_link(ring->dequeue)) {
@@ -221,9 +219,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
        unsigned int link_trb_count = 0;
 
        chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
-       /* If this is not event ring, there is one less usable TRB */
-       if (!trb_is_link(ring->enqueue))
-               ring->num_trbs_free--;
 
        if (last_trb_on_seg(ring->enq_seg, ring->enqueue)) {
                xhci_err(xhci, "Tried to move enqueue past ring segment\n");
@@ -277,24 +272,83 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
 }
 
 /*
+ * Return number of free normal TRBs from enqueue to dequeue pointer on ring.
+ * Not counting an assumed link TRB at end of each TRBS_PER_SEGMENT sized segment.
+ * Only for transfer and command rings where driver is the producer, not for
+ * event rings.
+ */
+static unsigned int xhci_num_trbs_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+       struct xhci_segment *enq_seg = ring->enq_seg;
+       union xhci_trb *enq = ring->enqueue;
+       union xhci_trb *last_on_seg;
+       unsigned int free = 0;
+       int i = 0;
+
+       /* Ring might be empty even if enq != deq if enq is left on a link trb */
+       if (trb_is_link(enq)) {
+               enq_seg = enq_seg->next;
+               enq = enq_seg->trbs;
+       }
+
+       /* Empty ring, common case, don't walk the segments */
+       if (enq == ring->dequeue)
+               return ring->num_segs * (TRBS_PER_SEGMENT - 1);
+
+       do {
+               if (ring->deq_seg == enq_seg && ring->dequeue >= enq)
+                       return free + (ring->dequeue - enq);
+               last_on_seg = &enq_seg->trbs[TRBS_PER_SEGMENT - 1];
+               free += last_on_seg - enq;
+               enq_seg = enq_seg->next;
+               enq = enq_seg->trbs;
+       } while (i++ <= ring->num_segs);
+
+       return free;
+}
+
+/*
  * 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.
+ * return number of new segments needed to ensure this.
  */
-static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
-               unsigned int num_trbs)
+
+static unsigned int xhci_ring_expansion_needed(struct xhci_hcd *xhci, struct xhci_ring *ring,
+                                              unsigned int num_trbs)
 {
-       int num_trbs_in_deq_seg;
+       struct xhci_segment *seg;
+       int trbs_past_seg;
+       int enq_used;
+       int new_segs;
+
+       enq_used = ring->enqueue - ring->enq_seg->trbs;
+
+       /* how many trbs will be queued past the enqueue segment? */
+       trbs_past_seg = enq_used + num_trbs - (TRBS_PER_SEGMENT - 1);
 
-       if (ring->num_trbs_free < num_trbs)
+       if (trbs_past_seg <= 0)
                return 0;
 
-       if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
-               num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs;
-               if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg)
-                       return 0;
+       /* Empty ring special case, enqueue stuck on link trb while dequeue advanced */
+       if (trb_is_link(ring->enqueue) && ring->enq_seg->next->trbs == ring->dequeue)
+               return 0;
+
+       new_segs = 1 + (trbs_past_seg / (TRBS_PER_SEGMENT - 1));
+       seg = ring->enq_seg;
+
+       while (new_segs > 0) {
+               seg = seg->next;
+               if (seg == ring->deq_seg) {
+                       xhci_dbg(xhci, "Ring expansion by %d segments needed\n",
+                                new_segs);
+                       xhci_dbg(xhci, "Adding %d trbs moves enq %d trbs into deq seg\n",
+                                num_trbs, trbs_past_seg % TRBS_PER_SEGMENT);
+                       return new_segs;
+               }
+               new_segs--;
        }
 
-       return 1;
+       return 0;
 }
 
 /* Ring the host controller doorbell after placing a command on the ring */
@@ -1248,10 +1302,7 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
                unsigned int ep_index)
 {
        union xhci_trb *dequeue_temp;
-       int num_trbs_free_temp;
-       bool revert = false;
 
-       num_trbs_free_temp = ep_ring->num_trbs_free;
        dequeue_temp = ep_ring->dequeue;
 
        /* If we get two back-to-back stalls, and the first stalled transfer
@@ -1267,7 +1318,6 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
 
        while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
                /* We have more usable TRBs */
-               ep_ring->num_trbs_free++;
                ep_ring->dequeue++;
                if (trb_is_link(ep_ring->dequeue)) {
                        if (ep_ring->dequeue ==
@@ -1277,15 +1327,10 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
                        ep_ring->dequeue = ep_ring->deq_seg->trbs;
                }
                if (ep_ring->dequeue == dequeue_temp) {
-                       revert = true;
+                       xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
                        break;
                }
        }
-
-       if (revert) {
-               xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
-               ep_ring->num_trbs_free = num_trbs_free_temp;
-       }
 }
 
 /*
@@ -2211,7 +2256,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
        /* Update ring dequeue pointer */
        ep_ring->dequeue = td->last_trb;
        ep_ring->deq_seg = td->last_trb_seg;
-       ep_ring->num_trbs_free += td->num_trbs - 1;
        inc_deq(xhci, ep_ring);
 
        return xhci_td_cleanup(xhci, td, ep_ring, td->status);
@@ -2433,7 +2477,6 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
        /* Update ring dequeue pointer */
        ep->ring->dequeue = td->last_trb;
        ep->ring->deq_seg = td->last_trb_seg;
-       ep->ring->num_trbs_free += td->num_trbs - 1;
        inc_deq(xhci, ep->ring);
 
        return xhci_td_cleanup(xhci, td, ep->ring, status);
@@ -3138,13 +3181,13 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
 
 /*
  * Does various checks on the endpoint ring, and makes it ready to queue num_trbs.
- * FIXME allocate segments if the ring is full.
+ * expand ring if it start to be 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_needed;
        unsigned int link_trb_count = 0;
+       unsigned int new_segs = 0;
 
        /* Make sure the endpoint has been added to xHC schedule */
        switch (ep_state) {
@@ -3175,20 +3218,17 @@ 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;
-               }
+       if (ep_ring != xhci->cmd_ring) {
+               new_segs = xhci_ring_expansion_needed(xhci, ep_ring, num_trbs);
+       } else if (xhci_num_trbs_free(xhci, ep_ring) <= num_trbs) {
+               xhci_err(xhci, "Do not support expand command ring\n");
+               return -ENOMEM;
+       }
 
+       if (new_segs) {
                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)) {
+               if (xhci_ring_expansion(xhci, ep_ring, new_segs, mem_flags)) {
                        xhci_err(xhci, "Ring expansion failed\n");
                        return -ENOMEM;
                }
@@ -4158,7 +4198,6 @@ cleanup:
        ep_ring->enqueue = urb_priv->td[0].first_trb;
        ep_ring->enq_seg = urb_priv->td[0].start_seg;
        ep_ring->cycle_state = start_cycle;
-       ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp;
        usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
        return ret;
 }
@@ -4240,7 +4279,6 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
        }
 
 skip_start_over:
-       ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
 
        return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index);
 }