]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/usb/host/xhci-ring.c
xhci: Find out where an endpoint or stream stopped from its context.
[mirror_ubuntu-bionic-kernel.git] / drivers / usb / host / xhci-ring.c
index 03f63f50afb6213d58b498f559021db28f8a4d5a..8e73dad0a73301f5b33cc104d4d84c523d09063f 100644 (file)
@@ -691,7 +691,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
        struct xhci_td *last_unlinked_td;
        struct xhci_ep_ctx *ep_ctx;
        struct xhci_virt_device *vdev;
-
+       u64 hw_deq;
        struct xhci_dequeue_state deq_state;
 
        if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) {
@@ -715,7 +715,6 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
 
        if (list_empty(&ep->cancelled_td_list)) {
                xhci_stop_watchdog_timer_in_irq(xhci, ep);
-               ep->stopped_td = NULL;
                ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
                return;
        }
@@ -753,12 +752,19 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
                 * If we stopped on the TD we need to cancel, then we have to
                 * move the xHC endpoint ring dequeue pointer past this TD.
                 */
-               if (cur_td == ep->stopped_td)
+               hw_deq = xhci_get_hw_deq(xhci, vdev, ep_index,
+                                        cur_td->urb->stream_id);
+               hw_deq &= ~0xf;
+
+               if (trb_in_td(xhci, cur_td->start_seg, cur_td->first_trb,
+                             cur_td->last_trb, hw_deq, false)) {
                        xhci_find_new_dequeue_state(xhci, slot_id, ep_index,
-                                       cur_td->urb->stream_id,
-                                       cur_td, &deq_state);
-               else
+                                                   cur_td->urb->stream_id,
+                                                   cur_td, &deq_state);
+               } else {
                        td_to_noop(xhci, ep_ring, cur_td, false);
+               }
+
 remove_finished_td:
                /*
                 * The event handler won't see a completion for this TD anymore,
@@ -780,8 +786,6 @@ remove_finished_td:
                ring_doorbell_for_active_rings(xhci, slot_id, ep_index);
        }
 
-       ep->stopped_td = NULL;
-
        /*
         * Drop the lock and complete the URBs in the cancelled TD list.
         * New TDs to be cancelled might be added to the end of the list before
@@ -1935,7 +1939,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
                 * stopped TDs.  A stopped TD may be restarted, so don't update
                 * the ring dequeue pointer or take this TD off any lists yet.
                 */
-               ep->stopped_td = td;
                return 0;
        }
        if (trb_comp_code == COMP_STALL_ERROR ||