|
@@ -1170,7 +1170,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|
|
struct ehci_qh *prev;
|
|
|
|
|
|
/* Add to the end of the list of QHs waiting for the next IAAD */
|
|
|
- qh->qh_state = QH_STATE_UNLINK;
|
|
|
+ qh->qh_state = QH_STATE_UNLINK_WAIT;
|
|
|
if (ehci->async_unlink)
|
|
|
ehci->async_unlink_last->unlink_next = qh;
|
|
|
else
|
|
@@ -1213,9 +1213,19 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
|
|
|
|
|
|
/* Do only the first waiting QH (nVidia bug?) */
|
|
|
qh = ehci->async_unlink;
|
|
|
- ehci->async_iaa = qh;
|
|
|
- ehci->async_unlink = qh->unlink_next;
|
|
|
- qh->unlink_next = NULL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Intel (?) bug: The HC can write back the overlay region
|
|
|
+ * even after the IAA interrupt occurs. In self-defense,
|
|
|
+ * always go through two IAA cycles for each QH.
|
|
|
+ */
|
|
|
+ if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
|
|
|
+ qh->qh_state = QH_STATE_UNLINK;
|
|
|
+ } else {
|
|
|
+ ehci->async_iaa = qh;
|
|
|
+ ehci->async_unlink = qh->unlink_next;
|
|
|
+ qh->unlink_next = NULL;
|
|
|
+ }
|
|
|
|
|
|
/* Make sure the unlinks are all visible to the hardware */
|
|
|
wmb();
|