aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hcd.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-07-27 15:05:21 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-28 17:31:13 -0400
commitc92bcfa7b4038d8ffe1f02e21269f18eb0b64144 (patch)
tree779257c92d050d3d19eb0351f73ee59bcc5fa84f /drivers/usb/host/xhci-hcd.c
parentd115b04818e57bdbc7ccde4d0660b15e33013dc8 (diff)
USB: xhci: Stall handling bug fixes.
Correct the xHCI code to handle stalls on USB endpoints. We need to move the endpoint ring's dequeue pointer past the stalled transfer, or the HW will try to restart the transfer the next time the doorbell is rung. Don't attempt to clear a halt on an endpoint if we haven't seen a stalled transfer for it. The USB core will attempt to clear a halt on all endpoints when it selects a new configuration. 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.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 057a07e876be..816c39caca1c 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1089,6 +1089,8 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
1089 unsigned int ep_index; 1089 unsigned int ep_index;
1090 unsigned long flags; 1090 unsigned long flags;
1091 int ret; 1091 int ret;
1092 struct xhci_dequeue_state deq_state;
1093 struct xhci_ring *ep_ring;
1092 1094
1093 xhci = hcd_to_xhci(hcd); 1095 xhci = hcd_to_xhci(hcd);
1094 udev = (struct usb_device *) ep->hcpriv; 1096 udev = (struct usb_device *) ep->hcpriv;
@@ -1098,11 +1100,33 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
1098 if (!ep->hcpriv) 1100 if (!ep->hcpriv)
1099 return; 1101 return;
1100 ep_index = xhci_get_endpoint_index(&ep->desc); 1102 ep_index = xhci_get_endpoint_index(&ep->desc);
1103 ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index];
1104 if (!ep_ring->stopped_td) {
1105 xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
1106 ep->desc.bEndpointAddress);
1107 return;
1108 }
1101 1109
1102 xhci_dbg(xhci, "Queueing reset endpoint command\n"); 1110 xhci_dbg(xhci, "Queueing reset endpoint command\n");
1103 spin_lock_irqsave(&xhci->lock, flags); 1111 spin_lock_irqsave(&xhci->lock, flags);
1104 ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); 1112 ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index);
1113 /*
1114 * Can't change the ring dequeue pointer until it's transitioned to the
1115 * stopped state, which is only upon a successful reset endpoint
1116 * command. Better hope that last command worked!
1117 */
1105 if (!ret) { 1118 if (!ret) {
1119 xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
1120 /* We need to move the HW's dequeue pointer past this TD,
1121 * or it will attempt to resend it on the next doorbell ring.
1122 */
1123 xhci_find_new_dequeue_state(xhci, udev->slot_id,
1124 ep_index, ep_ring->stopped_td, &deq_state);
1125 xhci_dbg(xhci, "Queueing new dequeue state\n");
1126 xhci_queue_new_dequeue_state(xhci, ep_ring,
1127 udev->slot_id,
1128 ep_index, &deq_state);
1129 kfree(ep_ring->stopped_td);
1106 xhci_ring_cmd_db(xhci); 1130 xhci_ring_cmd_db(xhci);
1107 } 1131 }
1108 spin_unlock_irqrestore(&xhci->lock, flags); 1132 spin_unlock_irqrestore(&xhci->lock, flags);