]> 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 74bf5c60a26075fff92cf74f6d3b2a2d4af4f0d4..8e73dad0a73301f5b33cc104d4d84c523d09063f 100644 (file)
@@ -323,7 +323,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
                if (i_cmd->status != COMP_COMMAND_ABORTED)
                        continue;
 
-               i_cmd->status = COMP_STOPPED;
+               i_cmd->status = COMP_COMMAND_RING_STOPPED;
 
                xhci_dbg(xhci, "Turn aborted command %p to no-op\n",
                         i_cmd->command_trb);
@@ -641,8 +641,8 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
        xhci_urb_free_priv(urb_priv);
        usb_hcd_unlink_urb_from_ep(hcd, urb);
        spin_unlock(&xhci->lock);
-       usb_hcd_giveback_urb(hcd, urb, status);
        trace_xhci_urb_giveback(urb);
+       usb_hcd_giveback_urb(hcd, urb, status);
        spin_lock(&xhci->lock);
 }
 
@@ -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
@@ -1380,7 +1384,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
        cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status));
 
        /* If CMD ring stopped we own the trbs between enqueue and dequeue */
-       if (cmd_comp_code == COMP_STOPPED) {
+       if (cmd_comp_code == COMP_COMMAND_RING_STOPPED) {
                complete_all(&xhci->cmd_ring_stop_completion);
                return;
        }
@@ -1436,8 +1440,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
                break;
        case TRB_CMD_NOOP:
                /* Is this an aborted command turned to NO-OP? */
-               if (cmd->status == COMP_STOPPED)
-                       cmd_comp_code = COMP_STOPPED;
+               if (cmd->status == COMP_COMMAND_RING_STOPPED)
+                       cmd_comp_code = COMP_COMMAND_RING_STOPPED;
                break;
        case TRB_RESET_EP:
                WARN_ON(slot_id != TRB_TO_SLOT_ID(
@@ -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 ||
@@ -2677,11 +2680,12 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        union xhci_trb *event_ring_deq;
        irqreturn_t ret = IRQ_NONE;
+       unsigned long flags;
        dma_addr_t deq;
        u64 temp_64;
        u32 status;
 
-       spin_lock(&xhci->lock);
+       spin_lock_irqsave(&xhci->lock, flags);
        /* Check if the xHC generated the interrupt, or the irq is shared */
        status = readl(&xhci->op_regs->status);
        if (status == ~(u32)0) {
@@ -2707,12 +2711,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
         */
        status |= STS_EINT;
        writel(status, &xhci->op_regs->status);
-       /* FIXME when MSI-X is supported and there are multiple vectors */
-       /* Clear the MSI-X event interrupt status */
 
-       if (hcd->irq) {
+       if (!hcd->msi_enabled) {
                u32 irq_pending;
-               /* Acknowledge the PCI interrupt */
                irq_pending = readl(&xhci->ir_set->irq_pending);
                irq_pending |= IMAN_IP;
                writel(irq_pending, &xhci->ir_set->irq_pending);
@@ -2757,7 +2758,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
        ret = IRQ_HANDLED;
 
 out:
-       spin_unlock(&xhci->lock);
+       spin_unlock_irqrestore(&xhci->lock, flags);
 
        return ret;
 }