aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-timer.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-11 11:23:04 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 19:56:47 -0400
commit18aafe64d75d0e27dae206cacf4171e4e485d285 (patch)
treeda5a4c0cb9bbc664c489be69956cd275ae5e0f6b /drivers/usb/host/ehci-timer.c
parent569b394f53f0abd177cc665c9b4ace89e3f4c7fb (diff)
USB: EHCI: use hrtimer for the I/O watchdog
This patch (as1586) replaces the kernel timer used by ehci-hcd as an I/O watchdog with an hrtimer event. Unlike in the current code, the watchdog event is now always enabled whenever any isochronous URBs are active. This will prevent bugs caused by the periodic schedule wrapping around with no completion interrupts; the watchdog handler is guaranteed to scan the isochronous transfers at least once during each iteration of the schedule. The extra overhead will be negligible: one timer interrupt every 100 ms. 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.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 0e28bae78d18..eb896a2c8f2e 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -76,6 +76,7 @@ static unsigned event_delays_ns[] = {
76 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ 76 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
77 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 77 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
78 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ 78 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */
79 100 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IO_WATCHDOG */
79}; 80};
80 81
81/* Enable a pending hrtimer event */ 82/* Enable a pending hrtimer event */
@@ -332,6 +333,25 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
332} 333}
333 334
334 335
336/* Enable the I/O watchdog, if appropriate */
337static void turn_on_io_watchdog(struct ehci_hcd *ehci)
338{
339 /* Not needed if the controller isn't running or it's already enabled */
340 if (ehci->rh_state != EHCI_RH_RUNNING ||
341 (ehci->enabled_hrtimer_events &
342 BIT(EHCI_HRTIMER_IO_WATCHDOG)))
343 return;
344
345 /*
346 * Isochronous transfers always need the watchdog.
347 * For other sorts we use it only if the flag is set.
348 */
349 if (ehci->isoc_count > 0 || (ehci->need_io_watchdog &&
350 ehci->async_count + ehci->intr_count > 0))
351 ehci_enable_event(ehci, EHCI_HRTIMER_IO_WATCHDOG, true);
352}
353
354
335/* 355/*
336 * Handler functions for the hrtimer event types. 356 * Handler functions for the hrtimer event types.
337 * Keep this array in the same order as the event types indexed by 357 * Keep this array in the same order as the event types indexed by
@@ -347,6 +367,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = {
347 ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ 367 ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
348 ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 368 ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
349 ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ 369 ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */
370 ehci_work, /* EHCI_HRTIMER_IO_WATCHDOG */
350}; 371};
351 372
352static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) 373static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t)