aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-timer.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-11 11:22:44 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 19:56:46 -0400
commit9d9387475af261949f61a5ec465e1f762d7be08a (patch)
tree7aa6688962bde78fba655b791612e60cc1b50adf /drivers/usb/host/ehci-timer.c
parent8c5bf7be56f1a8aecc1f802f132d53f556a9bc45 (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-timer.c')
-rw-r--r--drivers/usb/host/ehci-timer.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 8feb60ff4228..aab042064226 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = {
72 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 72 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
73 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 73 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
74 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ 74 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
75 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
75 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 76 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
76 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ 77 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */
77}; 78};
@@ -291,6 +292,49 @@ static void end_free_itds(struct ehci_hcd *ehci)
291} 292}
292 293
293 294
295/* Handle lost (or very late) IAA interrupts */
296static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
297{
298 if (ehci->rh_state != EHCI_RH_RUNNING)
299 return;
300
301 /*
302 * Lost IAA irqs wedge things badly; seen first with a vt8235.
303 * So we need this watchdog, but must protect it against both
304 * (a) SMP races against real IAA firing and retriggering, and
305 * (b) clean HC shutdown, when IAA watchdog was pending.
306 */
307 if (ehci->async_unlink) {
308 u32 cmd, status;
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
331 ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
332 status, cmd);
333 end_unlink_async(ehci);
334 }
335}
336
337
294/* 338/*
295 * Handler functions for the hrtimer event types. 339 * Handler functions for the hrtimer event types.
296 * Keep this array in the same order as the event types indexed by 340 * Keep this array in the same order as the event types indexed by
@@ -302,6 +346,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = {
302 ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ 346 ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
303 ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ 347 ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
304 end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ 348 end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
349 ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
305 ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 350 ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
306 ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ 351 ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */
307}; 352};