[PATCH] bug with EHCI cpufreq patch on nVidia controllers
| Newsgroups | gmane.linux.usb.devel |
|---|---|
| Message-ID | <DFEF91B22ED07447AB6AA4B237F913F9B18D92@ausx3mpc125.aus.amer.dell.com> |
This patch fixes a bug with the cpu frequency change notifier and nVidia EHCI controllers. The nVidia controllers write the transfer overlay back to the qtd when they see the "inactivate" bit set in the qh, which clears the "active" bit in qtd->hw_token. When the qh was reactivated, the "active" bit in the overlay's hw_token was turned back on, but not the one in the qtd. This caused qh_completions to think that qtd was finished even though it wasn't. This patch (against 2.6.23-rc1) fixes this bug. Signed-off-by: Stuart Hayes <[email protected]> ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ [email protected] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
ehci_cpufreq_nvidia_30july_b.patch
(application/octet-stream, 1.3 KB)
--- linux-2.6.22-rc1-mm1-orig/drivers/usb/host/ehci-sched.c 2007-07-30 06:07:11.000000000 -0500
+++ linux-2.6.22-rc1-mm1/drivers/usb/host/ehci-sched.c 2007-07-30 08:39:54.000000000 -0500
@@ -547,6 +547,19 @@ static void qh_inactivate_split_intr_qhs
wmb();
}
+static inline struct ehci_qtd *current_qtd (struct ehci_qh *qh)
+{
+ struct list_head *entry, *tmp;
+ struct ehci_qtd *qtd;
+
+ list_for_each_safe (entry, tmp, &qh->qtd_list) {
+ qtd = list_entry (entry, struct ehci_qtd, qtd_list);
+ if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current)
+ return qtd;
+ }
+ return NULL;
+}
+
static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
@@ -566,12 +579,21 @@ static void qh_reactivate_split_intr_qhs
if (safe == 0) {
not_done = 1;
} else if (safe > 0) {
+ struct ehci_qtd *qtd;
+
/* See EHCI 1.0 section 4.15.2.4. */
+ qtd = current_qtd(qh);
token = qh->hw_token;
qh->hw_token = (token | HALT_BIT) & ~ACTIVE_BIT;
wmb();
qh->hw_info1 &= ~INACTIVATE_BIT;
wmb();
+ /*
+ * nVidia controllers write overlay back to qtd
+ * when qh is inactivated, so reactivate it too.
+ */
+ if (qtd)
+ qtd->hw_token = token | qh->was_active;
qh->hw_token = (token & ~HALT_BIT) | qh->was_active;
}
}