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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
9525dcb30f
commit
a455212d19
@@ -1030,12 +1030,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct ehci_qh *qh;
|
||||
int eptype = usb_endpoint_type(&ep->desc);
|
||||
int epnum = usb_endpoint_num(&ep->desc);
|
||||
int is_out = usb_endpoint_dir_out(&ep->desc);
|
||||
unsigned long flags;
|
||||
|
||||
if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
|
||||
return;
|
||||
|
||||
rescan:
|
||||
spin_lock_irq(&ehci->lock);
|
||||
spin_lock_irqsave(&ehci->lock, flags);
|
||||
qh = ep->hcpriv;
|
||||
|
||||
/* 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)
|
||||
* the toggle bit in the QH.
|
||||
*/
|
||||
if (qh) {
|
||||
usb_settoggle(qh->dev, epnum, is_out, 0);
|
||||
if (!list_empty(&qh->qtd_list)) {
|
||||
WARN_ONCE(1, "clear_halt for a busy endpoint\n");
|
||||
} else if (qh->qh_state == QH_STATE_IDLE) {
|
||||
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
|
||||
} else {
|
||||
/* It's not safe to write into the overlay area
|
||||
* while the QH is active. Unlink it first and
|
||||
* wait for the unlink to complete.
|
||||
} else if (qh->qh_state == QH_STATE_LINKED) {
|
||||
|
||||
/* The toggle value in the QH can't be updated
|
||||
* while the QH is active. Unlink it now;
|
||||
* re-linking will call qh_refresh().
|
||||
*/
|
||||
if (qh->qh_state == QH_STATE_LINKED) {
|
||||
if (eptype == USB_ENDPOINT_XFER_BULK) {
|
||||
unlink_async(ehci, qh);
|
||||
} else {
|
||||
intr_deschedule(ehci, qh);
|
||||
(void) qh_schedule(ehci, qh);
|
||||
}
|
||||
if (eptype == USB_ENDPOINT_XFER_BULK) {
|
||||
unlink_async(ehci, qh);
|
||||
} else {
|
||||
intr_deschedule(ehci, qh);
|
||||
(void) qh_schedule(ehci, qh);
|
||||
}
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
schedule_timeout_uninterruptible(1);
|
||||
goto rescan;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&ehci->lock);
|
||||
spin_unlock_irqrestore(&ehci->lock, flags);
|
||||
}
|
||||
|
||||
static int ehci_get_frame (struct usb_hcd *hcd)
|
||||
|
Reference in New Issue
Block a user