|
@@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = {
|
|
|
1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
|
|
|
1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
|
|
|
2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
|
|
|
+ 5 * NSEC_PER_MSEC, /* EHCI_HRTIMER_START_UNLINK_INTR */
|
|
|
6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */
|
|
|
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */
|
|
|
10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
|
|
@@ -215,6 +216,36 @@ static void ehci_handle_controller_death(struct ehci_hcd *ehci)
|
|
|
/* Not in process context, so don't try to reset the controller */
|
|
|
}
|
|
|
|
|
|
+/* start to unlink interrupt QHs */
|
|
|
+static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci)
|
|
|
+{
|
|
|
+ bool stopped = (ehci->rh_state < EHCI_RH_RUNNING);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Process all the QHs on the intr_unlink list that were added
|
|
|
+ * before the current unlink cycle began. The list is in
|
|
|
+ * temporal order, so stop when we reach the first entry in the
|
|
|
+ * current cycle. But if the root hub isn't running then
|
|
|
+ * process all the QHs on the list.
|
|
|
+ */
|
|
|
+ while (!list_empty(&ehci->intr_unlink_wait)) {
|
|
|
+ struct ehci_qh *qh;
|
|
|
+
|
|
|
+ qh = list_first_entry(&ehci->intr_unlink_wait,
|
|
|
+ struct ehci_qh, unlink_node);
|
|
|
+ if (!stopped && (qh->unlink_cycle ==
|
|
|
+ ehci->intr_unlink_wait_cycle))
|
|
|
+ break;
|
|
|
+ list_del_init(&qh->unlink_node);
|
|
|
+ start_unlink_intr(ehci, qh);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Handle remaining entries later */
|
|
|
+ if (!list_empty(&ehci->intr_unlink_wait)) {
|
|
|
+ ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
|
|
|
+ ++ehci->intr_unlink_wait_cycle;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
/* Handle unlinked interrupt QHs once they are gone from the hardware */
|
|
|
static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
|
|
@@ -236,7 +267,7 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
|
|
|
unlink_node);
|
|
|
if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
|
|
|
break;
|
|
|
- list_del(&qh->unlink_node);
|
|
|
+ list_del_init(&qh->unlink_node);
|
|
|
end_unlink_intr(ehci, qh);
|
|
|
}
|
|
|
|
|
@@ -363,6 +394,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = {
|
|
|
ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
|
|
|
ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
|
|
|
end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
|
|
|
+ ehci_handle_start_intr_unlinks, /* EHCI_HRTIMER_START_UNLINK_INTR */
|
|
|
unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */
|
|
|
ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */
|
|
|
ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
|