aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-timer.c')
-rw-r--r--drivers/usb/host/ehci-timer.c34
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 */
220static 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 */
220static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) 251static 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 */