Update to 2.6.32.39 Mainline
/drivers/usb/host/ehci-q.c
blob:f51345f6619fea5dfd9a6fca478abc9b36cafdb6 -> blob:c0d4b39a118089ad1b259864e2081fcc003f109e
--- drivers/usb/host/ehci-q.c
+++ drivers/usb/host/ehci-q.c
@@ -315,6 +315,7 @@ qh_completions (struct ehci_hcd *ehci, s
int stopped;
unsigned count = 0;
u8 state;
+ const __le32 halt = HALT_BIT(ehci);
struct ehci_qh_hw *hw = qh->hw;
if (unlikely (list_empty (&qh->qtd_list)))
@@ -421,6 +422,7 @@ qh_completions (struct ehci_hcd *ehci, s
&& !(qtd->hw_alt_next
& EHCI_LIST_END(ehci))) {
stopped = 1;
+ goto halt;
}
/* stop scanning when we reach qtds the hc is using */
@@ -454,6 +456,16 @@ qh_completions (struct ehci_hcd *ehci, s
*/
ehci_clear_tt_buffer(ehci, qh, urb, token);
}
+
+ /* force halt for unlinked or blocked qh, so we'll
+ * patch the qh later and so that completions can't
+ * activate it while we "know" it's stopped.
+ */
+ if ((halt & hw->hw_token) == 0) {
+halt:
+ hw->hw_token |= halt;
+ wmb ();
+ }
}
/* unless we already know the urb's status, collect qtd status
@@ -1224,27 +1236,24 @@ static void start_unlink_async (struct e
static void scan_async (struct ehci_hcd *ehci)
{
- bool stopped;
struct ehci_qh *qh;
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
rescan:
- stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
qh = ehci->async->qh_next.qh;
if (likely (qh != NULL)) {
do {
/* clean any finished work for this qh */
- if (!list_empty(&qh->qtd_list) && (stopped ||
- qh->stamp != ehci->stamp)) {
+ if (!list_empty (&qh->qtd_list)
+ && qh->stamp != ehci->stamp) {
int temp;
/* unlinks could happen here; completion
* reporting drops the lock. rescan using
* the latest schedule, but don't rescan
- * qhs we already finished (no looping)
- * unless the controller is stopped.
+ * qhs we already finished (no looping).
*/
qh = qh_get (qh);
qh->stamp = ehci->stamp;
@@ -1265,9 +1274,9 @@ rescan:
*/
if (list_empty(&qh->qtd_list)
&& qh->qh_state == QH_STATE_LINKED) {
- if (!ehci->reclaim && (stopped ||
- ((ehci->stamp - qh->stamp) & 0x1fff)
- >= EHCI_SHRINK_FRAMES * 8))
+ if (!ehci->reclaim
+ && ((ehci->stamp - qh->stamp) & 0x1fff)
+ >= (EHCI_SHRINK_FRAMES * 8))
start_unlink_async(ehci, qh);
else
action = TIMER_ASYNC_SHRINK;