[patch 2.6.23-rc3 2/4] EHCI issues with cpufreq on VIA

David Brownell <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
From: Stuart Hayes <[email protected]>

This patch fixes lockups caused by the cpu frequency change notifier
interacting with silicon bugs in VIA EHCI controllers.  VIA EHCI does
not correctly implement the "inactivate" bit used by the cpu frequency
change handler.  Old EHCI 0.95 versions ignore this bit completely.
At least VT6212 (discrete) and VT8237 (southbridge) EHCI 1.00 versions
seem to respond to this bit incorrectly by starting a split transaction
and then marking the transaction inactive without finishing it.

This patch will automatically disable the EHCI cpu frequency change
notifier when a VIA controller is detected, and adds a parameter to
allow it to be disabled manually in case other problems are found.

Signed-off-by: Stuart Hayes <[email protected]>
Signed-off-by: David Brownell <[email protected]>
---
This patch resolves a regression, and should merge for 2.6.23-final.

 drivers/usb/host/ehci-hcd.c |   22 +++++++++++++++++-----
 drivers/usb/host/ehci-pci.c |   15 ++++++++++++++-
 drivers/usb/host/ehci.h     |    5 +++--
 3 files changed, 34 insertions(+), 8 deletions(-)

--- g26.orig/drivers/usb/host/ehci.h	2007-07-12 17:50:02.000000000 -0700
+++ g26/drivers/usb/host/ehci.h	2007-08-17 22:45:12.000000000 -0700
@@ -75,13 +75,14 @@ struct ehci_hcd {			/* one per controlle
 	struct notifier_block	cpufreq_transition;
 	int			cpufreq_changing;
 	struct list_head	split_intr_qhs;
+	unsigned		cpufreq_handler_disable:1;
 #endif
 
 	/* async schedule support */
-	struct ehci_qh		*async;
-	struct ehci_qh		*reclaim;
 	unsigned		reclaim_ready : 1;
 	unsigned		scanning : 1;
+	struct ehci_qh		*async;
+	struct ehci_qh		*reclaim;
 
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
--- g26.orig/drivers/usb/host/ehci-hcd.c	2007-07-12 17:50:02.000000000 -0700
+++ g26/drivers/usb/host/ehci-hcd.c	2007-08-17 22:45:28.000000000 -0700
@@ -129,6 +129,11 @@ static int ignore_oc = 0;
 module_param (ignore_oc, bool, S_IRUGO);
 MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
 
+/* allow user to disable cpufreq notifier; it can break with bad HW */
+static int cpufreq_ignore;
+module_param(cpufreq_ignore, bool, S_IRUGO);
+MODULE_PARM_DESC(cpufreq_ignore, "ignore cpufreq transitions");
+
 #define	INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
 
 /*-------------------------------------------------------------------------*/
@@ -461,8 +466,9 @@ static void ehci_stop (struct usb_hcd *h
 	spin_unlock_irq(&ehci->lock);
 
 #ifdef CONFIG_CPU_FREQ
-	cpufreq_unregister_notifier(&ehci->cpufreq_transition,
-				    CPUFREQ_TRANSITION_NOTIFIER);
+	if (!ehci->cpufreq_handler_disable)
+		cpufreq_unregister_notifier(&ehci->cpufreq_transition,
+					    CPUFREQ_TRANSITION_NOTIFIER);
 #endif
 	/* let companion controllers work when we aren't */
 	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
@@ -576,9 +582,15 @@ static int ehci_init(struct usb_hcd *hcd
 	 * isn't needed unless there are so many low/full speed devices
 	 * that the controller's can't cache it all.
 	 */
-	ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
-	cpufreq_register_notifier(&ehci->cpufreq_transition,
-				  CPUFREQ_TRANSITION_NOTIFIER);
+	if (cpufreq_ignore)
+		ehci->cpufreq_handler_disable = 1;
+
+	if (!ehci->cpufreq_handler_disable) {
+		ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
+		cpufreq_register_notifier(&ehci->cpufreq_transition,
+					  CPUFREQ_TRANSITION_NOTIFIER);
+	} else
+		ehci_info(ehci, "ignoring cpu frequency transitions\n");
 #endif
 	return 0;
 }
--- g26.orig/drivers/usb/host/ehci-pci.c	2007-08-17 22:29:47.000000000 -0700
+++ g26/drivers/usb/host/ehci-pci.c	2007-08-17 22:39:27.000000000 -0700
@@ -112,6 +112,19 @@ static int ehci_pci_setup(struct usb_hcd
 			break;
 		}
 		break;
+#ifdef CONFIG_CPU_FREQ
+	case PCI_VENDOR_ID_VIA:
+		/* VIA controllers do not support the "inactivate" bit
+		 * correctly... their EHCI 0.95 parts ignore it, and their
+		 * EHCI 1.00 parts (at least the VT6212 controller and
+		 * VT8237 bridge) start a split transaction but don't finish
+		 * it when the "inactivate" bit is set.
+		 * Right now, the cpufreq handler uses this bit, so disable
+		 * this for VIA controllers.
+		 */
+		ehci->cpufreq_handler_disable = 1;
+		ehci_warn(ehci, "VIA bugs; ignoring cpufreq transitions\n");
+#endif
 	}
 
 	/* cache this readonly data; minimize chip reads */
@@ -390,5 +403,5 @@ static struct pci_driver ehci_pci_driver
 	.suspend =	usb_hcd_pci_suspend,
 	.resume =	usb_hcd_pci_resume,
 #endif
-	.shutdown = 	usb_hcd_pci_shutdown,
+	.shutdown =	usb_hcd_pci_shutdown,
 };

-------------------------------------------------------------------------
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.