diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-07-11 11:22:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 19:56:46 -0400 |
commit | 9d9387475af261949f61a5ec465e1f762d7be08a (patch) | |
tree | 7aa6688962bde78fba655b791612e60cc1b50adf /drivers/usb/host/ehci-hcd.c | |
parent | 8c5bf7be56f1a8aecc1f802f132d53f556a9bc45 (diff) |
USB: EHCI: use hrtimer for the IAA watchdog
This patch (as1581) replaces the iaa_watchdog kernel timer used by
ehci-hcd with an hrtimer event, in keeping with the general conversion
to high-res timers.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 66 |
1 files changed, 14 insertions, 52 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index fb1966cf5649..f74ba277c22d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -93,7 +93,6 @@ static const char hcd_name [] = "ehci_hcd"; | |||
93 | */ | 93 | */ |
94 | #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ | 94 | #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ |
95 | 95 | ||
96 | #define EHCI_IAA_MSECS 10 /* arbitrary */ | ||
97 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ | 96 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ |
98 | #define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) | 97 | #define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) |
99 | /* 5-ms async qh unlink delay */ | 98 | /* 5-ms async qh unlink delay */ |
@@ -322,51 +321,6 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); | |||
322 | 321 | ||
323 | /*-------------------------------------------------------------------------*/ | 322 | /*-------------------------------------------------------------------------*/ |
324 | 323 | ||
325 | static void ehci_iaa_watchdog(unsigned long param) | ||
326 | { | ||
327 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | ||
328 | unsigned long flags; | ||
329 | |||
330 | spin_lock_irqsave (&ehci->lock, flags); | ||
331 | |||
332 | /* Lost IAA irqs wedge things badly; seen first with a vt8235. | ||
333 | * So we need this watchdog, but must protect it against both | ||
334 | * (a) SMP races against real IAA firing and retriggering, and | ||
335 | * (b) clean HC shutdown, when IAA watchdog was pending. | ||
336 | */ | ||
337 | if (ehci->async_unlink | ||
338 | && !timer_pending(&ehci->iaa_watchdog) | ||
339 | && ehci->rh_state == EHCI_RH_RUNNING) { | ||
340 | u32 cmd, status; | ||
341 | |||
342 | /* If we get here, IAA is *REALLY* late. It's barely | ||
343 | * conceivable that the system is so busy that CMD_IAAD | ||
344 | * is still legitimately set, so let's be sure it's | ||
345 | * clear before we read STS_IAA. (The HC should clear | ||
346 | * CMD_IAAD when it sets STS_IAA.) | ||
347 | */ | ||
348 | cmd = ehci_readl(ehci, &ehci->regs->command); | ||
349 | |||
350 | /* If IAA is set here it either legitimately triggered | ||
351 | * before we cleared IAAD above (but _way_ late, so we'll | ||
352 | * still count it as lost) ... or a silicon erratum: | ||
353 | * - VIA seems to set IAA without triggering the IRQ; | ||
354 | * - IAAD potentially cleared without setting IAA. | ||
355 | */ | ||
356 | status = ehci_readl(ehci, &ehci->regs->status); | ||
357 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { | ||
358 | COUNT (ehci->stats.lost_iaa); | ||
359 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); | ||
360 | } | ||
361 | |||
362 | ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", | ||
363 | status, cmd); | ||
364 | end_unlink_async(ehci); | ||
365 | } | ||
366 | |||
367 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
368 | } | ||
369 | |||
370 | static void ehci_watchdog(unsigned long param) | 324 | static void ehci_watchdog(unsigned long param) |
371 | { | 325 | { |
372 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | 326 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; |
@@ -418,7 +372,6 @@ static void ehci_shutdown(struct usb_hcd *hcd) | |||
418 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 372 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
419 | 373 | ||
420 | del_timer_sync(&ehci->watchdog); | 374 | del_timer_sync(&ehci->watchdog); |
421 | del_timer_sync(&ehci->iaa_watchdog); | ||
422 | 375 | ||
423 | spin_lock_irq(&ehci->lock); | 376 | spin_lock_irq(&ehci->lock); |
424 | ehci->rh_state = EHCI_RH_STOPPING; | 377 | ehci->rh_state = EHCI_RH_STOPPING; |
@@ -491,7 +444,6 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
491 | 444 | ||
492 | /* no more interrupts ... */ | 445 | /* no more interrupts ... */ |
493 | del_timer_sync (&ehci->watchdog); | 446 | del_timer_sync (&ehci->watchdog); |
494 | del_timer_sync(&ehci->iaa_watchdog); | ||
495 | 447 | ||
496 | spin_lock_irq(&ehci->lock); | 448 | spin_lock_irq(&ehci->lock); |
497 | ehci->enabled_hrtimer_events = 0; | 449 | ehci->enabled_hrtimer_events = 0; |
@@ -547,10 +499,6 @@ static int ehci_init(struct usb_hcd *hcd) | |||
547 | ehci->watchdog.function = ehci_watchdog; | 499 | ehci->watchdog.function = ehci_watchdog; |
548 | ehci->watchdog.data = (unsigned long) ehci; | 500 | ehci->watchdog.data = (unsigned long) ehci; |
549 | 501 | ||
550 | init_timer(&ehci->iaa_watchdog); | ||
551 | ehci->iaa_watchdog.function = ehci_iaa_watchdog; | ||
552 | ehci->iaa_watchdog.data = (unsigned long) ehci; | ||
553 | |||
554 | hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | 502 | hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
555 | ehci->hrtimer.function = ehci_hrtimer_func; | 503 | ehci->hrtimer.function = ehci_hrtimer_func; |
556 | ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; | 504 | ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; |
@@ -830,6 +778,20 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
830 | 778 | ||
831 | /* complete the unlinking of some qh [4.15.2.3] */ | 779 | /* complete the unlinking of some qh [4.15.2.3] */ |
832 | if (status & STS_IAA) { | 780 | if (status & STS_IAA) { |
781 | |||
782 | /* Turn off the IAA watchdog */ | ||
783 | ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_IAA_WATCHDOG); | ||
784 | |||
785 | /* | ||
786 | * Mild optimization: Allow another IAAD to reset the | ||
787 | * hrtimer, if one occurs before the next expiration. | ||
788 | * In theory we could always cancel the hrtimer, but | ||
789 | * tests show that about half the time it will be reset | ||
790 | * for some other event anyway. | ||
791 | */ | ||
792 | if (ehci->next_hrtimer_event == EHCI_HRTIMER_IAA_WATCHDOG) | ||
793 | ++ehci->next_hrtimer_event; | ||
794 | |||
833 | /* guard against (alleged) silicon errata */ | 795 | /* guard against (alleged) silicon errata */ |
834 | if (cmd & CMD_IAAD) | 796 | if (cmd & CMD_IAAD) |
835 | ehci_dbg(ehci, "IAA with IAAD still set?\n"); | 797 | ehci_dbg(ehci, "IAA with IAAD still set?\n"); |