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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
d115b04818
commit
c92bcfa7b4
@ -1089,6 +1089,8 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
|
||||
unsigned int ep_index;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
struct xhci_dequeue_state deq_state;
|
||||
struct xhci_ring *ep_ring;
|
||||
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
udev = (struct usb_device *) ep->hcpriv;
|
||||
@ -1098,11 +1100,33 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
|
||||
if (!ep->hcpriv)
|
||||
return;
|
||||
ep_index = xhci_get_endpoint_index(&ep->desc);
|
||||
ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index];
|
||||
if (!ep_ring->stopped_td) {
|
||||
xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
|
||||
ep->desc.bEndpointAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Queueing reset endpoint command\n");
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index);
|
||||
/*
|
||||
* Can't change the ring dequeue pointer until it's transitioned to the
|
||||
* stopped state, which is only upon a successful reset endpoint
|
||||
* command. Better hope that last command worked!
|
||||
*/
|
||||
if (!ret) {
|
||||
xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
|
||||
/* We need to move the HW's dequeue pointer past this TD,
|
||||
* or it will attempt to resend it on the next doorbell ring.
|
||||
*/
|
||||
xhci_find_new_dequeue_state(xhci, udev->slot_id,
|
||||
ep_index, ep_ring->stopped_td, &deq_state);
|
||||
xhci_dbg(xhci, "Queueing new dequeue state\n");
|
||||
xhci_queue_new_dequeue_state(xhci, ep_ring,
|
||||
udev->slot_id,
|
||||
ep_index, &deq_state);
|
||||
kfree(ep_ring->stopped_td);
|
||||
xhci_ring_cmd_db(xhci);
|
||||
}
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
Reference in New Issue
Block a user