aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/xhci-hcd.c4
-rw-r--r--drivers/usb/host/xhci-ring.c14
-rw-r--r--drivers/usb/host/xhci.h4
3 files changed, 12 insertions, 10 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 932f9993848..3a30db6d6ab 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -817,12 +817,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
xhci_debug_ring(xhci, ep_ring);
td = (struct xhci_td *) urb->hcpriv;
- ep->cancels_pending++;
list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
/* Queue a stop endpoint command, but only if this is
* the first cancellation to be handled.
*/
- if (ep->cancels_pending == 1) {
+ if (!(ep->ep_state & EP_HALT_PENDING)) {
+ ep->ep_state |= EP_HALT_PENDING;
xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index);
xhci_ring_cmd_db(xhci);
}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 821b7b4709d..184e8b6f30b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -306,7 +306,7 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci,
/* Don't ring the doorbell for this endpoint if there are pending
* cancellations because the we don't want to interrupt processing.
*/
- if (!ep->cancels_pending && !(ep_state & SET_DEQ_PENDING)
+ if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING)
&& !(ep_state & EP_HALTED)) {
field = xhci_readl(xhci, db_addr) & DB_MASK;
xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr);
@@ -507,8 +507,11 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
ep = &xhci->devs[slot_id]->eps[ep_index];
ep_ring = ep->ring;
- if (list_empty(&ep->cancelled_td_list))
+ if (list_empty(&ep->cancelled_td_list)) {
+ ep->ep_state &= ~EP_HALT_PENDING;
+ ring_ep_doorbell(xhci, slot_id, ep_index);
return;
+ }
/* Fix up the ep ring first, so HW stops executing cancelled TDs.
* We have the xHCI lock, so nothing can modify this list until we drop
@@ -535,9 +538,9 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
* the cancelled TD list for URB completion later.
*/
list_del(&cur_td->td_list);
- ep->cancels_pending--;
}
last_unlinked_td = cur_td;
+ ep->ep_state &= ~EP_HALT_PENDING;
/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
@@ -1249,10 +1252,9 @@ td_cleanup:
}
list_del(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */
- if (!list_empty(&td->cancelled_td_list)) {
+ if (!list_empty(&td->cancelled_td_list))
list_del(&td->cancelled_td_list);
- ep->cancels_pending--;
- }
+
/* 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
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 4b254b6fa24..b173fd96dce 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -652,10 +652,10 @@ struct xhci_virt_ep {
struct xhci_ring *new_ring;
unsigned int ep_state;
#define SET_DEQ_PENDING (1 << 0)
-#define EP_HALTED (1 << 1)
+#define EP_HALTED (1 << 1) /* For stall handling */
+#define EP_HALT_PENDING (1 << 2) /* For URB cancellation */
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
- unsigned int cancels_pending;
/* The TRB that was last reported in a stopped endpoint ring */
union xhci_trb *stopped_trb;
struct xhci_td *stopped_td;