diff options
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 fb1966cf564..f74ba277c22 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"; */ #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ -#define EHCI_IAA_MSECS 10 /* arbitrary */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) /* 5-ms async qh unlink delay */ @@ -322,51 +321,6 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); /*-------------------------------------------------------------------------*/ -static void ehci_iaa_watchdog(unsigned long param) -{ - struct ehci_hcd *ehci = (struct ehci_hcd *) param; - unsigned long flags; - - spin_lock_irqsave (&ehci->lock, flags); - - /* Lost IAA irqs wedge things badly; seen first with a vt8235. - * So we need this watchdog, but must protect it against both - * (a) SMP races against real IAA firing and retriggering, and - * (b) clean HC shutdown, when IAA watchdog was pending. - */ - if (ehci->async_unlink - && !timer_pending(&ehci->iaa_watchdog) - && ehci->rh_state == EHCI_RH_RUNNING) { - u32 cmd, status; - - /* If we get here, IAA is *REALLY* late. It's barely - * conceivable that the system is so busy that CMD_IAAD - * is still legitimately set, so let's be sure it's - * clear before we read STS_IAA. (The HC should clear - * CMD_IAAD when it sets STS_IAA.) - */ - cmd = ehci_readl(ehci, &ehci->regs->command); - - /* If IAA is set here it either legitimately triggered - * before we cleared IAAD above (but _way_ late, so we'll - * still count it as lost) ... or a silicon erratum: - * - VIA seems to set IAA without triggering the IRQ; - * - IAAD potentially cleared without setting IAA. - */ - status = ehci_readl(ehci, &ehci->regs->status); - if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { - COUNT (ehci->stats.lost_iaa); - ehci_writel(ehci, STS_IAA, &ehci->regs->status); - } - - ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", - status, cmd); - end_unlink_async(ehci); - } - - spin_unlock_irqrestore(&ehci->lock, flags); -} - static void ehci_watchdog(unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; @@ -418,7 +372,6 @@ static void ehci_shutdown(struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci(hcd); del_timer_sync(&ehci->watchdog); - del_timer_sync(&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); ehci->rh_state = EHCI_RH_STOPPING; @@ -491,7 +444,6 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); - del_timer_sync(&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); ehci->enabled_hrtimer_events = 0; @@ -547,10 +499,6 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; - init_timer(&ehci->iaa_watchdog); - ehci->iaa_watchdog.function = ehci_iaa_watchdog; - ehci->iaa_watchdog.data = (unsigned long) ehci; - hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ehci->hrtimer.function = ehci_hrtimer_func; ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; @@ -830,6 +778,20 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { + + /* Turn off the IAA watchdog */ + ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_IAA_WATCHDOG); + + /* + * Mild optimization: Allow another IAAD to reset the + * hrtimer, if one occurs before the next expiration. + * In theory we could always cancel the hrtimer, but + * tests show that about half the time it will be reset + * for some other event anyway. + */ + if (ehci->next_hrtimer_event == EHCI_HRTIMER_IAA_WATCHDOG) + ++ehci->next_hrtimer_event; + /* guard against (alleged) silicon errata */ if (cmd & CMD_IAAD) ehci_dbg(ehci, "IAA with IAAD still set?\n"); |