Merge remote-tracking branch 'stable/linux-5.10.y' into rpi-5.10.y
[platform/kernel/linux-rpi.git] / drivers / usb / host / xhci-ring.c
index 76389c0..545387a 100644 (file)
@@ -87,15 +87,16 @@ static bool trb_is_link(union xhci_trb *trb)
        return TRB_TYPE_LINK_LE32(trb->link.control);
 }
 
-static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb)
+static bool last_trb_on_seg(struct xhci_segment *seg,
+                           unsigned int trbs_per_seg, union xhci_trb *trb)
 {
-       return trb == &seg->trbs[TRBS_PER_SEGMENT - 1];
+       return trb == &seg->trbs[trbs_per_seg - 1];
 }
 
 static bool last_trb_on_ring(struct xhci_ring *ring,
                        struct xhci_segment *seg, union xhci_trb *trb)
 {
-       return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg);
+       return last_trb_on_seg(seg, ring->trbs_per_seg, trb) && (seg->next == ring->first_seg);
 }
 
 static bool link_trb_toggles_cycle(union xhci_trb *trb)
@@ -157,7 +158,8 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
        /* event ring doesn't have link trbs, check for last trb */
        if (ring->type == TYPE_EVENT) {
-               if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
+               if (!last_trb_on_seg(ring->deq_seg, ring->trbs_per_seg,
+                                    ring->dequeue)) {
                        ring->dequeue++;
                        goto out;
                }
@@ -265,6 +267,12 @@ static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
                return 0;
 
        if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
+               /*
+                * If the ring has a single segment the dequeue segment
+                * never changes, so don't use it as measure of free space.
+                */
+               if (ring->num_segs == 1)
+                       return ring->num_trbs_free >= num_trbs;
                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;
@@ -666,6 +674,16 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
 
        } while (!cycle_found || !td_last_trb_found);
 
+       /*
+        * Quirk: the xHC does not correctly parse link TRBs if the HW Dequeue
+        * pointer is set to one. Advance to the next TRB (and next segment).
+        */
+       if (xhci->quirks & XHCI_AVOID_DQ_ON_LINK && trb_is_link(new_deq)) {
+               if (link_trb_toggles_cycle(new_deq))
+                       state->new_cycle_state ^= 0x1;
+               next_trb(xhci, ep_ring, &new_seg, &new_deq);
+       }
+
        state->new_deq_seg = new_seg;
        state->new_deq_ptr = new_deq;
 
@@ -2966,7 +2984,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
         * that clears the EHB.
         */
        while (xhci_handle_event(xhci) > 0) {
-               if (event_loop++ < TRBS_PER_SEGMENT / 2)
+               if (event_loop++ < xhci->event_ring->trbs_per_seg / 2)
                        continue;
                xhci_update_erst_dequeue(xhci, event_ring_deq);
                event_loop = 0;
@@ -4258,9 +4276,9 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
        }
        ep = &xhci->devs[slot_id]->eps[ep_index];
        if ((ep->ep_state & SET_DEQ_PENDING)) {
-               xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n");
-               xhci_warn(xhci, "A Set TR Deq Ptr command is pending.\n");
-               return;
+               xhci_warn(xhci, "WARN A Set TR Deq Ptr command is pending for slot %u ep %u\n",
+                         slot_id, ep_index);
+               ep->ep_state &= ~SET_DEQ_PENDING;
        }
 
        /* This function gets called from contexts where it cannot sleep */