diff options
Diffstat (limited to 'drivers/usb/host/ehci-timer.c')
-rw-r--r-- | drivers/usb/host/ehci-timer.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 11e5b32f73e9..424ac5d83714 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 | 5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */ | ||
75 | 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */ | 76 | 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */ |
76 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ | 77 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ |
77 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ | 78 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ |
@@ -215,6 +216,36 @@ static void ehci_handle_controller_death(struct ehci_hcd *ehci) | |||
215 | /* Not in process context, so don't try to reset the controller */ | 216 | /* Not in process context, so don't try to reset the controller */ |
216 | } | 217 | } |
217 | 218 | ||
219 | /* start to unlink interrupt QHs */ | ||
220 | static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci) | ||
221 | { | ||
222 | bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); | ||
223 | |||
224 | /* | ||
225 | * Process all the QHs on the intr_unlink list that were added | ||
226 | * before the current unlink cycle began. The list is in | ||
227 | * temporal order, so stop when we reach the first entry in the | ||
228 | * current cycle. But if the root hub isn't running then | ||
229 | * process all the QHs on the list. | ||
230 | */ | ||
231 | while (!list_empty(&ehci->intr_unlink_wait)) { | ||
232 | struct ehci_qh *qh; | ||
233 | |||
234 | qh = list_first_entry(&ehci->intr_unlink_wait, | ||
235 | struct ehci_qh, unlink_node); | ||
236 | if (!stopped && (qh->unlink_cycle == | ||
237 | ehci->intr_unlink_wait_cycle)) | ||
238 | break; | ||
239 | list_del_init(&qh->unlink_node); | ||
240 | start_unlink_intr(ehci, qh); | ||
241 | } | ||
242 | |||
243 | /* Handle remaining entries later */ | ||
244 | if (!list_empty(&ehci->intr_unlink_wait)) { | ||
245 | ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true); | ||
246 | ++ehci->intr_unlink_wait_cycle; | ||
247 | } | ||
248 | } | ||
218 | 249 | ||
219 | /* Handle unlinked interrupt QHs once they are gone from the hardware */ | 250 | /* Handle unlinked interrupt QHs once they are gone from the hardware */ |
220 | static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) | 251 | static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) |
@@ -236,7 +267,7 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) | |||
236 | unlink_node); | 267 | unlink_node); |
237 | if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) | 268 | if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) |
238 | break; | 269 | break; |
239 | list_del(&qh->unlink_node); | 270 | list_del_init(&qh->unlink_node); |
240 | end_unlink_intr(ehci, qh); | 271 | end_unlink_intr(ehci, qh); |
241 | } | 272 | } |
242 | 273 | ||
@@ -363,6 +394,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { | |||
363 | ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ | 394 | ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ |
364 | ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ | 395 | ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ |
365 | end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ | 396 | end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ |
397 | ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */ | ||
366 | unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */ | 398 | unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */ |
367 | ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ | 399 | ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ |
368 | ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ | 400 | ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ |