diff options
Diffstat (limited to 'drivers/usb/host/ehci-timer.c')
-rw-r--r-- | drivers/usb/host/ehci-timer.c | 61 |
1 files changed, 29 insertions, 32 deletions
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index c3fa1305f830..e7363332887e 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c | |||
@@ -113,8 +113,8 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci) | |||
113 | 113 | ||
114 | if (want != actual) { | 114 | if (want != actual) { |
115 | 115 | ||
116 | /* Poll again later, but give up after about 20 ms */ | 116 | /* Poll again later, but give up after about 2-4 ms */ |
117 | if (ehci->ASS_poll_count++ < 20) { | 117 | if (ehci->ASS_poll_count++ < 2) { |
118 | ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); | 118 | ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); |
119 | return; | 119 | return; |
120 | } | 120 | } |
@@ -159,8 +159,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci) | |||
159 | 159 | ||
160 | if (want != actual) { | 160 | if (want != actual) { |
161 | 161 | ||
162 | /* Poll again later, but give up after about 20 ms */ | 162 | /* Poll again later, but give up after about 2-4 ms */ |
163 | if (ehci->PSS_poll_count++ < 20) { | 163 | if (ehci->PSS_poll_count++ < 2) { |
164 | ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); | 164 | ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); |
165 | return; | 165 | return; |
166 | } | 166 | } |
@@ -295,8 +295,7 @@ static void end_free_itds(struct ehci_hcd *ehci) | |||
295 | /* Handle lost (or very late) IAA interrupts */ | 295 | /* Handle lost (or very late) IAA interrupts */ |
296 | static void ehci_iaa_watchdog(struct ehci_hcd *ehci) | 296 | static void ehci_iaa_watchdog(struct ehci_hcd *ehci) |
297 | { | 297 | { |
298 | if (ehci->rh_state != EHCI_RH_RUNNING) | 298 | u32 cmd, status; |
299 | return; | ||
300 | 299 | ||
301 | /* | 300 | /* |
302 | * Lost IAA irqs wedge things badly; seen first with a vt8235. | 301 | * Lost IAA irqs wedge things badly; seen first with a vt8235. |
@@ -304,34 +303,32 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci) | |||
304 | * (a) SMP races against real IAA firing and retriggering, and | 303 | * (a) SMP races against real IAA firing and retriggering, and |
305 | * (b) clean HC shutdown, when IAA watchdog was pending. | 304 | * (b) clean HC shutdown, when IAA watchdog was pending. |
306 | */ | 305 | */ |
307 | if (1) { | 306 | if (ehci->rh_state != EHCI_RH_RUNNING) |
308 | u32 cmd, status; | 307 | return; |
309 | |||
310 | /* If we get here, IAA is *REALLY* late. It's barely | ||
311 | * conceivable that the system is so busy that CMD_IAAD | ||
312 | * is still legitimately set, so let's be sure it's | ||
313 | * clear before we read STS_IAA. (The HC should clear | ||
314 | * CMD_IAAD when it sets STS_IAA.) | ||
315 | */ | ||
316 | cmd = ehci_readl(ehci, &ehci->regs->command); | ||
317 | |||
318 | /* | ||
319 | * If IAA is set here it either legitimately triggered | ||
320 | * after the watchdog timer expired (_way_ late, so we'll | ||
321 | * still count it as lost) ... or a silicon erratum: | ||
322 | * - VIA seems to set IAA without triggering the IRQ; | ||
323 | * - IAAD potentially cleared without setting IAA. | ||
324 | */ | ||
325 | status = ehci_readl(ehci, &ehci->regs->status); | ||
326 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { | ||
327 | COUNT(ehci->stats.lost_iaa); | ||
328 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); | ||
329 | } | ||
330 | 308 | ||
331 | ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", | 309 | /* If we get here, IAA is *REALLY* late. It's barely |
332 | status, cmd); | 310 | * conceivable that the system is so busy that CMD_IAAD |
333 | end_unlink_async(ehci); | 311 | * is still legitimately set, so let's be sure it's |
312 | * clear before we read STS_IAA. (The HC should clear | ||
313 | * CMD_IAAD when it sets STS_IAA.) | ||
314 | */ | ||
315 | cmd = ehci_readl(ehci, &ehci->regs->command); | ||
316 | |||
317 | /* | ||
318 | * If IAA is set here it either legitimately triggered | ||
319 | * after the watchdog timer expired (_way_ late, so we'll | ||
320 | * still count it as lost) ... or a silicon erratum: | ||
321 | * - VIA seems to set IAA without triggering the IRQ; | ||
322 | * - IAAD potentially cleared without setting IAA. | ||
323 | */ | ||
324 | status = ehci_readl(ehci, &ehci->regs->status); | ||
325 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { | ||
326 | COUNT(ehci->stats.lost_iaa); | ||
327 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); | ||
334 | } | 328 | } |
329 | |||
330 | ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); | ||
331 | end_unlink_async(ehci); | ||
335 | } | 332 | } |
336 | 333 | ||
337 | 334 | ||