Commit 991182b9 authored by Mathias Nyman's avatar Mathias Nyman Committed by Zefan Li

USB: xhci: Reset a halted endpoint immediately when we encounter a stall.

commit 8e71a322 upstream.

If a device is halted and reuturns a STALL, then the halted endpoint
needs to be cleared both on the host and device side. The host
side halt is cleared by issueing a xhci reset endpoint command. The device side
is cleared with a ClearFeature(ENDPOINT_HALT) request, which should
be issued by the device driver if a URB reruen -EPIPE.

Previously we cleared the host side halt after the device side was cleared.
To make sure the host side halt is cleared in time we want to issue the
reset endpoint command immedialtely when a STALL status is encountered.

Otherwise we end up not following the specs and not returning -EPIPE
several times in a row when trying to transfer data to a halted endpoint.

Fixes: bcef3fd5 (USB: xhci: Handle errors that cause endpoint halts.)
Tested-by: default avatarFelipe Balbi <balbi@ti.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
[lizf: Backported to 3.4: adjust context]
Signed-off-by: default avatarZefan Li <lizefan@huawei.com>
parent a3d7be95
......@@ -1915,23 +1915,12 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
ep->stopped_trb = event_trb;
return 0;
} else {
if (trb_comp_code == COMP_STALL) {
/* The transfer is completed from the driver's
* perspective, but we need to issue a set dequeue
* command for this stalled endpoint to move the dequeue
* pointer past the TD. We can't do that here because
* the halt condition must be cleared first. Let the
* USB class driver clear the stall later.
*/
ep->stopped_td = td;
ep->stopped_trb = event_trb;
ep->stopped_stream = ep_ring->stream_id;
} else if (xhci_requires_manual_halt_cleanup(xhci,
ep_ctx, trb_comp_code)) {
/* Other types of errors halt the endpoint, but the
* class driver doesn't call usb_reset_endpoint() unless
* the error is -EPIPE. Clear the halted status in the
* xHCI hardware manually.
if (trb_comp_code == COMP_STALL ||
xhci_requires_manual_halt_cleanup(xhci, ep_ctx,
trb_comp_code)) {
/* Issue a reset endpoint command to clear the host side * halt, followed by a set dequeue command to move the
* dequeue pointer past the TD.
* The class driver clears the device side halt later.
*/
xhci_cleanup_halted_endpoint(xhci,
slot_id, ep_index, ep_ring->stream_id,
......@@ -2051,9 +2040,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
else
td->urb->actual_length = 0;
xhci_cleanup_halted_endpoint(xhci,
slot_id, ep_index, 0, td, event_trb);
return finish_td(xhci, td, event_trb, event, ep, status, true);
return finish_td(xhci, td, event_trb, event, ep, status, false);
}
/*
* Did we transfer any data, despite the errors that might have
......@@ -2605,17 +2592,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (ret) {
urb = td->urb;
urb_priv = urb->hcpriv;
/* Leave the TD around for the reset endpoint function
* to use(but only if it's not a control endpoint,
* since we already queued the Set TR dequeue pointer
* command for stalled control endpoints).
*/
if (usb_endpoint_xfer_control(&urb->ep->desc) ||
(trb_comp_code != COMP_STALL &&
trb_comp_code != COMP_BABBLE))
xhci_urb_free_priv(xhci, urb_priv);
else
kfree(urb_priv);
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
if ((urb->actual_length != urb->transfer_buffer_length &&
......
......@@ -2851,61 +2851,31 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
}
}
/* Deal with stalled endpoints. The core should have sent the control message
* to clear the halt condition. However, we need to make the xHCI hardware
* reset its sequence number, since a device will expect a sequence number of
* zero after the halt condition is cleared.
/* Called when clearing halted device. The core should have sent the control
* message to clear the device halt condition. The host side of the halt should
* already be cleared with a reset endpoint command issued when the STALL tx
* event was received.
*
* Context: in_interrupt
*/
void xhci_endpoint_reset(struct usb_hcd *hcd,
struct usb_host_endpoint *ep)
{
struct xhci_hcd *xhci;
struct usb_device *udev;
unsigned int ep_index;
unsigned long flags;
int ret;
struct xhci_virt_ep *virt_ep;
xhci = hcd_to_xhci(hcd);
udev = (struct usb_device *) ep->hcpriv;
/* Called with a root hub endpoint (or an endpoint that wasn't added
* with xhci_add_endpoint()
*/
if (!ep->hcpriv)
return;
ep_index = xhci_get_endpoint_index(&ep->desc);
virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index];
if (!virt_ep->stopped_td) {
xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
ep->desc.bEndpointAddress);
return;
}
if (usb_endpoint_xfer_control(&ep->desc)) {
xhci_dbg(xhci, "Control endpoint stall already handled.\n");
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_cleanup_stalled_ring(xhci, udev, ep_index);
kfree(virt_ep->stopped_td);
xhci_ring_cmd_db(xhci);
}
virt_ep->stopped_td = NULL;
virt_ep->stopped_trb = NULL;
virt_ep->stopped_stream = 0;
spin_unlock_irqrestore(&xhci->lock, flags);
if (ret)
xhci_warn(xhci, "FIXME allocate a new ring segment\n");
* We might need to implement the config ep cmd in xhci 4.8.1 note:
* The Reset Endpoint Command may only be issued to endpoints in the
* Halted state. If software wishes reset the Data Toggle or Sequence
* Number of an endpoint that isn't in the Halted state, then software
* may issue a Configure Endpoint Command with the Drop and Add bits set
* for the target endpoint. that is in the Stopped state.
*/
/* For now just print debug to follow the situation */
xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n",
ep->desc.bEndpointAddress);
}
static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment