aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hcd.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-04-29 22:02:31 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:49 -0400
commitae636747146ea97efa18e04576acd3416e2514f5 (patch)
tree22e392df7126974c0ac4dc2fe516dc9e16a49873 /drivers/usb/host/xhci-hcd.c
parent8a96c052283e68fe91a6c657c175b39bfed80bed (diff)
USB: xhci: URB cancellation support.
Add URB cancellation support to the xHCI host controller driver. This currently supports cancellation for endpoints that do not have streams enabled. An URB is represented by a number of Transaction Request Buffers (TRBs), that are chained together to make one (or more) Transaction Descriptors (TDs) on an endpoint ring. The ring is comprised of contiguous segments, linked together with Link TRBs (which may or may not be chained into a TD). To cancel an URB, we must stop the endpoint ring, make the hardware skip over the TDs in the URB (either by turning them into No-op TDs, or by moving the hardware's ring dequeue pointer past the last TRB in the last TD), and then restart the ring. There are times when we must drop the xHCI lock during this process, like when we need to complete cancelled URBs. We must ensure that additional URBs can be marked as cancelled, and that new URBs can be enqueued (since the URB completion handlers can do either). The new endpoint ring variables cancels_pending and state (which can only be modified while holding the xHCI lock) ensure that future cancellation and enqueueing do not interrupt any pending cancellation code. To facilitate cancellation, we must keep track of the starting ring segment, first TRB, and last TRB for each URB. We also need to keep track of the list of TDs that have been marked as cancelled, separate from the list of TDs that are queued for this endpoint. The new variables and cancellation list are stored in the xhci_td structure. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r--drivers/usb/host/xhci-hcd.c64
1 files changed, 61 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index e5fbdcdbf676..36e440ce88e5 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -613,12 +613,70 @@ exit:
613 return ret; 613 return ret;
614} 614}
615 615
616/* Remove from hardware lists 616/*
617 * completions normally happen asynchronously 617 * Remove the URB's TD from the endpoint ring. This may cause the HC to stop
618 * USB transfers, potentially stopping in the middle of a TRB buffer. The HC
619 * should pick up where it left off in the TD, unless a Set Transfer Ring
620 * Dequeue Pointer is issued.
621 *
622 * The TRBs that make up the buffers for the canceled URB will be "removed" from
623 * the ring. Since the ring is a contiguous structure, they can't be physically
624 * removed. Instead, there are two options:
625 *
626 * 1) If the HC is in the middle of processing the URB to be canceled, we
627 * simply move the ring's dequeue pointer past those TRBs using the Set
628 * Transfer Ring Dequeue Pointer command. This will be the common case,
629 * when drivers timeout on the last submitted URB and attempt to cancel.
630 *
631 * 2) If the HC is in the middle of a different TD, we turn the TRBs into a
632 * series of 1-TRB transfer no-op TDs. (No-ops shouldn't be chained.) The
633 * HC will need to invalidate the any TRBs it has cached after the stop
634 * endpoint command, as noted in the xHCI 0.95 errata.
635 *
636 * 3) The TD may have completed by the time the Stop Endpoint Command
637 * completes, so software needs to handle that case too.
638 *
639 * This function should protect against the TD enqueueing code ringing the
640 * doorbell while this code is waiting for a Stop Endpoint command to complete.
641 * It also needs to account for multiple cancellations on happening at the same
642 * time for the same endpoint.
643 *
644 * Note that this function can be called in any context, or so says
645 * usb_hcd_unlink_urb()
618 */ 646 */
619int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) 647int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
620{ 648{
621 return -ENOSYS; 649 unsigned long flags;
650 int ret;
651 struct xhci_hcd *xhci;
652 struct xhci_td *td;
653 unsigned int ep_index;
654 struct xhci_ring *ep_ring;
655
656 xhci = hcd_to_xhci(hcd);
657 spin_lock_irqsave(&xhci->lock, flags);
658 /* Make sure the URB hasn't completed or been unlinked already */
659 ret = usb_hcd_check_unlink_urb(hcd, urb, status);
660 if (ret || !urb->hcpriv)
661 goto done;
662
663 xhci_dbg(xhci, "Cancel URB 0x%x\n", (unsigned int) urb);
664 ep_index = xhci_get_endpoint_index(&urb->ep->desc);
665 ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index];
666 td = (struct xhci_td *) urb->hcpriv;
667
668 ep_ring->cancels_pending++;
669 list_add_tail(&td->cancelled_td_list, &ep_ring->cancelled_td_list);
670 /* Queue a stop endpoint command, but only if this is
671 * the first cancellation to be handled.
672 */
673 if (ep_ring->cancels_pending == 1) {
674 queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index);
675 ring_cmd_db(xhci);
676 }
677done:
678 spin_unlock_irqrestore(&xhci->lock, flags);
679 return ret;
622} 680}
623 681
624/* Drop an endpoint from a new bandwidth configuration for this device. 682/* Drop an endpoint from a new bandwidth configuration for this device.