diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/xhci-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 14 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 4 |
3 files changed, 12 insertions, 10 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c index 932f99938481..3a30db6d6abe 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) | |||
817 | xhci_debug_ring(xhci, ep_ring); | 817 | xhci_debug_ring(xhci, ep_ring); |
818 | td = (struct xhci_td *) urb->hcpriv; | 818 | td = (struct xhci_td *) urb->hcpriv; |
819 | 819 | ||
820 | ep->cancels_pending++; | ||
821 | list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); | 820 | list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); |
822 | /* Queue a stop endpoint command, but only if this is | 821 | /* Queue a stop endpoint command, but only if this is |
823 | * the first cancellation to be handled. | 822 | * the first cancellation to be handled. |
824 | */ | 823 | */ |
825 | if (ep->cancels_pending == 1) { | 824 | if (!(ep->ep_state & EP_HALT_PENDING)) { |
825 | ep->ep_state |= EP_HALT_PENDING; | ||
826 | xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index); | 826 | xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index); |
827 | xhci_ring_cmd_db(xhci); | 827 | xhci_ring_cmd_db(xhci); |
828 | } | 828 | } |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 821b7b4709de..184e8b6f30b2 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, | |||
306 | /* Don't ring the doorbell for this endpoint if there are pending | 306 | /* Don't ring the doorbell for this endpoint if there are pending |
307 | * cancellations because the we don't want to interrupt processing. | 307 | * cancellations because the we don't want to interrupt processing. |
308 | */ | 308 | */ |
309 | if (!ep->cancels_pending && !(ep_state & SET_DEQ_PENDING) | 309 | if (!(ep_state & EP_HALT_PENDING) && !(ep_state & SET_DEQ_PENDING) |
310 | && !(ep_state & EP_HALTED)) { | 310 | && !(ep_state & EP_HALTED)) { |
311 | field = xhci_readl(xhci, db_addr) & DB_MASK; | 311 | field = xhci_readl(xhci, db_addr) & DB_MASK; |
312 | xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); | 312 | xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); |
@@ -507,8 +507,11 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci, | |||
507 | ep = &xhci->devs[slot_id]->eps[ep_index]; | 507 | ep = &xhci->devs[slot_id]->eps[ep_index]; |
508 | ep_ring = ep->ring; | 508 | ep_ring = ep->ring; |
509 | 509 | ||
510 | if (list_empty(&ep->cancelled_td_list)) | 510 | if (list_empty(&ep->cancelled_td_list)) { |
511 | ep->ep_state &= ~EP_HALT_PENDING; | ||
512 | ring_ep_doorbell(xhci, slot_id, ep_index); | ||
511 | return; | 513 | return; |
514 | } | ||
512 | 515 | ||
513 | /* Fix up the ep ring first, so HW stops executing cancelled TDs. | 516 | /* Fix up the ep ring first, so HW stops executing cancelled TDs. |
514 | * We have the xHCI lock, so nothing can modify this list until we drop | 517 | * 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, | |||
535 | * the cancelled TD list for URB completion later. | 538 | * the cancelled TD list for URB completion later. |
536 | */ | 539 | */ |
537 | list_del(&cur_td->td_list); | 540 | list_del(&cur_td->td_list); |
538 | ep->cancels_pending--; | ||
539 | } | 541 | } |
540 | last_unlinked_td = cur_td; | 542 | last_unlinked_td = cur_td; |
543 | ep->ep_state &= ~EP_HALT_PENDING; | ||
541 | 544 | ||
542 | /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ | 545 | /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ |
543 | if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { | 546 | if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { |
@@ -1249,10 +1252,9 @@ td_cleanup: | |||
1249 | } | 1252 | } |
1250 | list_del(&td->td_list); | 1253 | list_del(&td->td_list); |
1251 | /* Was this TD slated to be cancelled but completed anyway? */ | 1254 | /* Was this TD slated to be cancelled but completed anyway? */ |
1252 | if (!list_empty(&td->cancelled_td_list)) { | 1255 | if (!list_empty(&td->cancelled_td_list)) |
1253 | list_del(&td->cancelled_td_list); | 1256 | list_del(&td->cancelled_td_list); |
1254 | ep->cancels_pending--; | 1257 | |
1255 | } | ||
1256 | /* Leave the TD around for the reset endpoint function to use | 1258 | /* Leave the TD around for the reset endpoint function to use |
1257 | * (but only if it's not a control endpoint, since we already | 1259 | * (but only if it's not a control endpoint, since we already |
1258 | * queued the Set TR dequeue pointer command for stalled | 1260 | * queued the Set TR dequeue pointer command for stalled |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 4b254b6fa245..b173fd96dceb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -652,10 +652,10 @@ struct xhci_virt_ep { | |||
652 | struct xhci_ring *new_ring; | 652 | struct xhci_ring *new_ring; |
653 | unsigned int ep_state; | 653 | unsigned int ep_state; |
654 | #define SET_DEQ_PENDING (1 << 0) | 654 | #define SET_DEQ_PENDING (1 << 0) |
655 | #define EP_HALTED (1 << 1) | 655 | #define EP_HALTED (1 << 1) /* For stall handling */ |
656 | #define EP_HALT_PENDING (1 << 2) /* For URB cancellation */ | ||
656 | /* ---- Related to URB cancellation ---- */ | 657 | /* ---- Related to URB cancellation ---- */ |
657 | struct list_head cancelled_td_list; | 658 | struct list_head cancelled_td_list; |
658 | unsigned int cancels_pending; | ||
659 | /* The TRB that was last reported in a stopped endpoint ring */ | 659 | /* The TRB that was last reported in a stopped endpoint ring */ |
660 | union xhci_trb *stopped_trb; | 660 | union xhci_trb *stopped_trb; |
661 | struct xhci_td *stopped_td; | 661 | struct xhci_td *stopped_td; |