aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hcd.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-06-11 14:56:22 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-12 18:16:36 -0400
commita455212d19d312f6a99b3a4a86fb79fb91dd76c7 (patch)
treecfd1cf74b6e51623813be2ec65e42f3756598252 /drivers/usb/host/ehci-hcd.c
parent9525dcb30f5f412748f58a0537002ea47cfe55de (diff)
USB: EHCI: update toggle state for linked QHs
This is an update to the "usb-ehci-update-toggle-state-for-linked-qhs" patch. Since an HCD's endpoint_reset method can be called in interrupt context, it mustn't assume that interrupts are enabled or that it can sleep. So we revert to the original way of refreshing QHs' toggle bits. Now the endpoint_reset method merely clears the toggle flag in the device structure (as was done before) and starts an async QH unlink. When the QH is linked again, after the unlink finishes and an URB is queued, the qh_refresh() routine will update the QH's toggle bit. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: David <david@unsolicited.net> CC: David Brownell <david-b@pacbell.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r--drivers/usb/host/ehci-hcd.c35
1 files changed, 16 insertions, 19 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 2b72473544d3..99c75603ec87 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1030,12 +1030,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
1030 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 1030 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
1031 struct ehci_qh *qh; 1031 struct ehci_qh *qh;
1032 int eptype = usb_endpoint_type(&ep->desc); 1032 int eptype = usb_endpoint_type(&ep->desc);
1033 int epnum = usb_endpoint_num(&ep->desc);
1034 int is_out = usb_endpoint_dir_out(&ep->desc);
1035 unsigned long flags;
1033 1036
1034 if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) 1037 if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
1035 return; 1038 return;
1036 1039
1037 rescan: 1040 spin_lock_irqsave(&ehci->lock, flags);
1038 spin_lock_irq(&ehci->lock);
1039 qh = ep->hcpriv; 1041 qh = ep->hcpriv;
1040 1042
1041 /* For Bulk and Interrupt endpoints we maintain the toggle state 1043 /* For Bulk and Interrupt endpoints we maintain the toggle state
@@ -1044,29 +1046,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
1044 * the toggle bit in the QH. 1046 * the toggle bit in the QH.
1045 */ 1047 */
1046 if (qh) { 1048 if (qh) {
1049 usb_settoggle(qh->dev, epnum, is_out, 0);
1047 if (!list_empty(&qh->qtd_list)) { 1050 if (!list_empty(&qh->qtd_list)) {
1048 WARN_ONCE(1, "clear_halt for a busy endpoint\n"); 1051 WARN_ONCE(1, "clear_halt for a busy endpoint\n");
1049 } else if (qh->qh_state == QH_STATE_IDLE) { 1052 } else if (qh->qh_state == QH_STATE_LINKED) {
1050 qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); 1053
1051 } else { 1054 /* The toggle value in the QH can't be updated
1052 /* It's not safe to write into the overlay area 1055 * while the QH is active. Unlink it now;
1053 * while the QH is active. Unlink it first and 1056 * re-linking will call qh_refresh().
1054 * wait for the unlink to complete.
1055 */ 1057 */
1056 if (qh->qh_state == QH_STATE_LINKED) { 1058 if (eptype == USB_ENDPOINT_XFER_BULK) {
1057 if (eptype == USB_ENDPOINT_XFER_BULK) { 1059 unlink_async(ehci, qh);
1058 unlink_async(ehci, qh); 1060 } else {
1059 } else { 1061 intr_deschedule(ehci, qh);
1060 intr_deschedule(ehci, qh); 1062 (void) qh_schedule(ehci, qh);
1061 (void) qh_schedule(ehci, qh);
1062 }
1063 } 1063 }
1064 spin_unlock_irq(&ehci->lock);
1065 schedule_timeout_uninterruptible(1);
1066 goto rescan;
1067 } 1064 }
1068 } 1065 }
1069 spin_unlock_irq(&ehci->lock); 1066 spin_unlock_irqrestore(&ehci->lock, flags);
1070} 1067}
1071 1068
1072static int ehci_get_frame (struct usb_hcd *hcd) 1069static int ehci_get_frame (struct usb_hcd *hcd)