diff options
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 47 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/ehci-timer.c | 21 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 13 |
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 */ |
99 | static int log2_irq_thresh = 0; // 0 to 6 | 97 | static int log2_irq_thresh = 0; // 0 to 6 |
100 | module_param (log2_irq_thresh, int, S_IRUGO); | 98 | module_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 | ||
128 | static void | ||
129 | timer_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 | ||
310 | static 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 | */ |
395 | static void ehci_work (struct ehci_hcd *ehci) | 359 | static 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 | ||
975 | static void disable_async(struct ehci_hcd *ehci) | 976 | static 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 | ||
494 | static void disable_periodic(struct ehci_hcd *ehci) | 495 | static 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 */ | ||
337 | static 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 | ||
352 | static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) | 373 | static 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 | ||
238 | enum ehci_timer_action { | ||
239 | TIMER_IO_WATCHDOG, | ||
240 | }; | ||
241 | |||
242 | static inline void | ||
243 | timer_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> |