aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
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
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')
-rw-r--r--drivers/usb/host/ehci-hcd.c47
-rw-r--r--drivers/usb/host/ehci-hub.c5
-rw-r--r--drivers/usb/host/ehci-q.c1
-rw-r--r--drivers/usb/host/ehci-sched.c3
-rw-r--r--drivers/usb/host/ehci-timer.c21
-rw-r--r--drivers/usb/host/ehci.h13
6 files changed, 25 insertions, 65 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c13dad8a8503..9f26080889f5 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -93,8 +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_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
97
98/* Initial IRQ latency: faster than hw default */ 96/* Initial IRQ latency: faster than hw default */
99static int log2_irq_thresh = 0; // 0 to 6 97static int log2_irq_thresh = 0; // 0 to 6
100module_param (log2_irq_thresh, int, S_IRUGO); 98module_param (log2_irq_thresh, int, S_IRUGO);
@@ -125,25 +123,6 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
125 123
126/*-------------------------------------------------------------------------*/ 124/*-------------------------------------------------------------------------*/
127 125
128static void
129timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
130{
131 if (!test_and_set_bit(action, &ehci->actions)) {
132 unsigned long t;
133
134 switch (action) {
135 case TIMER_IO_WATCHDOG:
136 if (!ehci->need_io_watchdog)
137 return;
138 t = EHCI_IO_JIFFIES;
139 break;
140 }
141 mod_timer(&ehci->watchdog, t + jiffies);
142 }
143}
144
145/*-------------------------------------------------------------------------*/
146
147/* 126/*
148 * handshake - spin reading hc until handshake completes or fails 127 * handshake - spin reading hc until handshake completes or fails
149 * @ptr: address of hc register to be read 128 * @ptr: address of hc register to be read
@@ -307,19 +286,6 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);
307 286
308/*-------------------------------------------------------------------------*/ 287/*-------------------------------------------------------------------------*/
309 288
310static void ehci_watchdog(unsigned long param)
311{
312 struct ehci_hcd *ehci = (struct ehci_hcd *) param;
313 unsigned long flags;
314
315 spin_lock_irqsave(&ehci->lock, flags);
316
317 /* ehci could run by timer, without IRQs ... */
318 ehci_work (ehci);
319
320 spin_unlock_irqrestore (&ehci->lock, flags);
321}
322
323/* On some systems, leaving remote wakeup enabled prevents system shutdown. 289/* On some systems, leaving remote wakeup enabled prevents system shutdown.
324 * The firmware seems to think that powering off is a wakeup event! 290 * The firmware seems to think that powering off is a wakeup event!
325 * This routine turns off remote wakeup and everything else, on all ports. 291 * This routine turns off remote wakeup and everything else, on all ports.
@@ -357,8 +323,6 @@ static void ehci_shutdown(struct usb_hcd *hcd)
357{ 323{
358 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 324 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
359 325
360 del_timer_sync(&ehci->watchdog);
361
362 spin_lock_irq(&ehci->lock); 326 spin_lock_irq(&ehci->lock);
363 ehci->rh_state = EHCI_RH_STOPPING; 327 ehci->rh_state = EHCI_RH_STOPPING;
364 ehci_silence_controller(ehci); 328 ehci_silence_controller(ehci);
@@ -394,8 +358,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
394 */ 358 */
395static void ehci_work (struct ehci_hcd *ehci) 359static void ehci_work (struct ehci_hcd *ehci)
396{ 360{
397 timer_action_done (ehci, TIMER_IO_WATCHDOG);
398
399 /* another CPU may drop ehci->lock during a schedule scan while 361 /* another CPU may drop ehci->lock during a schedule scan while
400 * it reports urb completions. this flag guards against bogus 362 * it reports urb completions. this flag guards against bogus
401 * attempts at re-entrant schedule scanning. 363 * attempts at re-entrant schedule scanning.
@@ -422,10 +384,7 @@ static void ehci_work (struct ehci_hcd *ehci)
422 * misplace IRQs, and should let us run completely without IRQs. 384 * misplace IRQs, and should let us run completely without IRQs.
423 * such lossage has been observed on both VT6202 and VT8235. 385 * such lossage has been observed on both VT6202 and VT8235.
424 */ 386 */
425 if (ehci->rh_state == EHCI_RH_RUNNING && 387 turn_on_io_watchdog(ehci);
426 (ehci->async->qh_next.ptr != NULL ||
427 ehci->periodic_count != 0))
428 timer_action (ehci, TIMER_IO_WATCHDOG);
429} 388}
430 389
431/* 390/*
@@ -438,7 +397,6 @@ static void ehci_stop (struct usb_hcd *hcd)
438 ehci_dbg (ehci, "stop\n"); 397 ehci_dbg (ehci, "stop\n");
439 398
440 /* no more interrupts ... */ 399 /* no more interrupts ... */
441 del_timer_sync (&ehci->watchdog);
442 400
443 spin_lock_irq(&ehci->lock); 401 spin_lock_irq(&ehci->lock);
444 ehci->enabled_hrtimer_events = 0; 402 ehci->enabled_hrtimer_events = 0;
@@ -490,9 +448,6 @@ static int ehci_init(struct usb_hcd *hcd)
490 * keep io watchdog by default, those good HCDs could turn off it later 448 * keep io watchdog by default, those good HCDs could turn off it later
491 */ 449 */
492 ehci->need_io_watchdog = 1; 450 ehci->need_io_watchdog = 1;
493 init_timer(&ehci->watchdog);
494 ehci->watchdog.function = ehci_watchdog;
495 ehci->watchdog.data = (unsigned long) ehci;
496 451
497 hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 452 hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
498 ehci->hrtimer.function = ehci_hrtimer_func; 453 ehci->hrtimer.function = ehci_hrtimer_func;
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 5d84562e2716..05490d387fd2 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -208,7 +208,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
208 208
209 if (time_before (jiffies, ehci->next_statechange)) 209 if (time_before (jiffies, ehci->next_statechange))
210 msleep(5); 210 msleep(5);
211 del_timer_sync(&ehci->watchdog);
212 211
213 spin_lock_irq (&ehci->lock); 212 spin_lock_irq (&ehci->lock);
214 213
@@ -316,10 +315,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
316 ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; 315 ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT;
317 spin_unlock_irq (&ehci->lock); 316 spin_unlock_irq (&ehci->lock);
318 317
319 /* ehci_work() may have re-enabled the watchdog timer, which we do not
320 * want, and so we must delete any pending watchdog timer events.
321 */
322 del_timer_sync(&ehci->watchdog);
323 hrtimer_cancel(&ehci->hrtimer); 318 hrtimer_cancel(&ehci->hrtimer);
324 return 0; 319 return 0;
325} 320}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index c9c7f7b3b7db..9bc39ca460c8 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -970,6 +970,7 @@ static void enable_async(struct ehci_hcd *ehci)
970 970
971 /* Don't start the schedule until ASS is 0 */ 971 /* Don't start the schedule until ASS is 0 */
972 ehci_poll_ASS(ehci); 972 ehci_poll_ASS(ehci);
973 turn_on_io_watchdog(ehci);
973} 974}
974 975
975static void disable_async(struct ehci_hcd *ehci) 976static void disable_async(struct ehci_hcd *ehci)
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 263b542985c0..26ce8fef0e5b 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -489,6 +489,7 @@ static void enable_periodic(struct ehci_hcd *ehci)
489 489
490 /* Don't start the schedule until PSS is 0 */ 490 /* Don't start the schedule until PSS is 0 */
491 ehci_poll_PSS(ehci); 491 ehci_poll_PSS(ehci);
492 turn_on_io_watchdog(ehci);
492} 493}
493 494
494static void disable_periodic(struct ehci_hcd *ehci) 495static void disable_periodic(struct ehci_hcd *ehci)
@@ -1649,7 +1650,6 @@ static void itd_link_urb(
1649 iso_sched_free (stream, iso_sched); 1650 iso_sched_free (stream, iso_sched);
1650 urb->hcpriv = NULL; 1651 urb->hcpriv = NULL;
1651 1652
1652 timer_action (ehci, TIMER_IO_WATCHDOG);
1653 ++ehci->isoc_count; 1653 ++ehci->isoc_count;
1654 enable_periodic(ehci); 1654 enable_periodic(ehci);
1655} 1655}
@@ -2052,7 +2052,6 @@ static void sitd_link_urb(
2052 iso_sched_free (stream, sched); 2052 iso_sched_free (stream, sched);
2053 urb->hcpriv = NULL; 2053 urb->hcpriv = NULL;
2054 2054
2055 timer_action (ehci, TIMER_IO_WATCHDOG);
2056 ++ehci->isoc_count; 2055 ++ehci->isoc_count;
2057 enable_periodic(ehci); 2056 enable_periodic(ehci);
2058} 2057}
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)
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 08637183aad0..254f414bd0bd 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -88,6 +88,7 @@ enum ehci_hrtimer_event {
88 EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ 88 EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
89 EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ 89 EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
90 EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ 90 EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
91 EHCI_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
91 EHCI_HRTIMER_NUM_EVENTS /* Must come last */ 92 EHCI_HRTIMER_NUM_EVENTS /* Must come last */
92}; 93};
93#define EHCI_HRTIMER_NO_EVENT 99 94#define EHCI_HRTIMER_NO_EVENT 99
@@ -177,8 +178,6 @@ struct ehci_hcd { /* one per controller */
177 struct dma_pool *itd_pool; /* itd per iso urb */ 178 struct dma_pool *itd_pool; /* itd per iso urb */
178 struct dma_pool *sitd_pool; /* sitd per split iso urb */ 179 struct dma_pool *sitd_pool; /* sitd per split iso urb */
179 180
180 struct timer_list watchdog;
181 unsigned long actions;
182 unsigned random_frame; 181 unsigned random_frame;
183 unsigned long next_statechange; 182 unsigned long next_statechange;
184 ktime_t last_periodic_enable; 183 ktime_t last_periodic_enable;
@@ -235,16 +234,6 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
235 return container_of ((void *) ehci, struct usb_hcd, hcd_priv); 234 return container_of ((void *) ehci, struct usb_hcd, hcd_priv);
236} 235}
237 236
238enum ehci_timer_action {
239 TIMER_IO_WATCHDOG,
240};
241
242static inline void
243timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
244{
245 clear_bit (action, &ehci->actions);
246}
247
248/*-------------------------------------------------------------------------*/ 237/*-------------------------------------------------------------------------*/
249 238
250#include <linux/usb/ehci_def.h> 239#include <linux/usb/ehci_def.h>