summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYe Li <ye.li@nxp.com>2018-01-04 09:17:57 -0600
committerYe Li <ye.li@nxp.com>2018-01-08 08:15:36 -0600
commit650c2bcc5d35ea6566041854049b091eb79d94ac (patch)
treed0175c85f9a08c11bb800ad12b7e9dda1434446f
parentbc823433658f2446f71643cdef91cc875eb56229 (diff)
MLK-17348 xhci: Reset endpoint when endpoint is halted
When testing a poor USB disk "Transcend JetFlash XPGMC7W5 ", sometime we will get TRB TX error during getting string descriptors, then the usb process aborts due to the context state changed to halted. Actually when the endpoint context state is halted, we can send reset endpoint command to put it to stopped state, then set TR dequeue pointer for following doorbell ring to re-run it. This patch adds this error recovery mechanism. Signed-off-by: Ye Li <ye.li@nxp.com> (cherry picked from commit 6a2418e2b0554045ae1e8096b22fa64da5de4d8a)
-rw-r--r--drivers/usb/host/xhci-ring.c41
1 files changed, 37 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 2675a8f649..fb93ea265b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -467,6 +467,29 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
BUG();
}
+static void reset_ep(struct usb_device *udev, int ep_index)
+{
+ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+ struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
+ union xhci_trb *event;
+
+ xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_RESET_EP);
+
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+ != udev->slot_id || GET_COMP_CODE(le32_to_cpu(
+ event->event_cmd.status)) != COMP_SUCCESS);
+ xhci_acknowledge_event(ctrl);
+
+ xhci_queue_command(ctrl, (void *)((uintptr_t)ring->enqueue |
+ ring->cycle_state), udev->slot_id, ep_index, TRB_SET_DEQ);
+ event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
+ BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
+ != udev->slot_id || GET_COMP_CODE(le32_to_cpu(
+ event->event_cmd.status)) != COMP_SUCCESS);
+ xhci_acknowledge_event(ctrl);
+}
+
/*
* Stops transfer processing for an endpoint and throws away all unprocessed
* TRBs by setting the xHC's dequeue pointer to our enqueue pointer. The next
@@ -554,6 +577,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
int start_cycle;
u32 field = 0;
u32 length_field = 0;
+ u32 ep_state;
struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
int slot_id = udev->slot_id;
int ep_index;
@@ -611,11 +635,15 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
* prepare_trasfer() as there in 'Linux' since we are not
* maintaining multiple TDs/transfer at the same time.
*/
- ret = prepare_ring(ctrl, ring,
- le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK);
+ ep_state = le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK;
+ ret = prepare_ring(ctrl, ring, ep_state);
if (ret < 0)
return ret;
+ /* For halted EP, reset it to stopped state and set TR Dequeue Pointer */
+ if (ep_state == EP_STATE_HALTED)
+ reset_ep(udev, ep_index);
+
/*
* Don't give the first TRB to the hardware (by toggling the cycle bit)
* until we've finished creating all the other TRBs. The ring's cycle
@@ -746,6 +774,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
int num_trbs;
u32 field;
u32 length_field;
+ u32 ep_state;
u64 buf_64 = 0;
struct xhci_generic_trb *start_trb;
struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
@@ -797,12 +826,16 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
* prepare_trasfer() as there in 'Linux' since we are not
* maintaining multiple TDs/transfer at the same time.
*/
- ret = prepare_ring(ctrl, ep_ring,
- le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK);
+ ep_state = le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK;
+ ret = prepare_ring(ctrl, ep_ring, ep_state);
if (ret < 0)
return ret;
+ /* For halted EP, reset it to stopped state and set TR Dequeue Pointer */
+ if (ep_state == EP_STATE_HALTED)
+ reset_ep(udev, ep_index);
+
/*
* Don't give the first TRB to the hardware (by toggling the cycle bit)
* until we've finished creating all the other TRBs. The ring's cycle