diff -purN --exclude='*cmd' --exclude=tags linux-2.6.20orig/drivers/usb/host/ehci.h linux-2.6.20/drivers/usb/host/ehci.h
--- linux-2.6.20orig/drivers/usb/host/ehci.h	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/drivers/usb/host/ehci.h	2007-03-07 05:25:46.000000000 -0600
@@ -55,6 +55,12 @@ struct ehci_hcd {			/* one per controlle
 	__u32			hcs_params;	/* cached register copy */
 	spinlock_t		lock;
 
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	cpufreq_transition;
+	int			cpufreq_changing;
+	struct list_head	split_intr_qhs;
+#endif
+
 	/* async schedule support */
 	struct ehci_qh		*async;
 	struct ehci_qh		*reclaim;
@@ -390,6 +396,7 @@ struct ehci_qh {
 	__le32			hw_next;	 /* see EHCI 3.6.1 */
 	__le32			hw_info1;        /* see EHCI 3.6.2 */
 #define	QH_HEAD		0x00008000
+#define	QH_INACTIVATE	0x00000080
 	__le32			hw_info2;        /* see EHCI 3.6.2 */
 #define	QH_SMASK	0x000000ff
 #define	QH_CMASK	0x0000ff00
@@ -432,6 +439,10 @@ struct ehci_qh {
 	unsigned short		start;		/* where polling starts */
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 	struct usb_device	*dev;		/* access to TT */
+#ifdef CONFIG_CPU_FREQ
+	struct list_head	split_intr_qhs; /* list of split qhs */
+	__le32			was_active;	/* active bit before "i" set */
+#endif
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
diff -purN --exclude='*cmd' --exclude=tags linux-2.6.20orig/drivers/usb/host/ehci-hcd.c linux-2.6.20/drivers/usb/host/ehci-hcd.c
--- linux-2.6.20orig/drivers/usb/host/ehci-hcd.c	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/drivers/usb/host/ehci-hcd.c	2007-03-07 05:36:45.000000000 -0600
@@ -268,6 +268,51 @@ static void ehci_work(struct ehci_hcd *e
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_CPU_FREQ
+
+#include <linux/cpufreq.h>
+
+static void ehci_cpufreq_pause (struct ehci_hcd *ehci)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&ehci->lock, flags);
+	if (!ehci->cpufreq_changing++)
+		qh_inactivate_split_intr_qhs(ehci);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_cpufreq_unpause (struct ehci_hcd *ehci)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&ehci->lock, flags);
+	if (!--ehci->cpufreq_changing)
+		qh_reactivate_split_intr_qhs(ehci);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static int ehci_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+				 void *data)
+{
+	struct ehci_hcd *ehci = container_of(nb, struct ehci_hcd,
+					     cpufreq_transition);
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		ehci_cpufreq_pause(ehci);
+		break;
+	case CPUFREQ_POSTCHANGE:
+		ehci_cpufreq_unpause(ehci);
+		break;
+	}
+	return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 static void ehci_watchdog (unsigned long param)
 {
 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
@@ -308,6 +353,12 @@ ehci_shutdown (struct usb_hcd *hcd)
 	ehci = hcd_to_ehci (hcd);
 	(void) ehci_halt (ehci);
 
+#ifdef CONFIG_CPU_FREQ
+	if (ehci->i_thresh < 8) {
+		cpufreq_unregister_notifier(&ehci->cpufreq_transition,
+					    CPUFREQ_TRANSITION_NOTIFIER);
+	}
+#endif
 	/* make BIOS/etc use companion controller during reboot */
 	writel (0, &ehci->regs->configured_flag);
 }
@@ -485,6 +536,22 @@ static int ehci_init(struct usb_hcd *hcd
 	}
 	ehci->command = temp;
 
+#ifdef CONFIG_CPU_FREQ
+	INIT_LIST_HEAD (&ehci->split_intr_qhs);
+	if (ehci->i_thresh < 8) {
+		/*
+		 * If the EHCI controller caches enough uframes, this
+		 * isn't needed.  If there's a controller with an i_thresh
+		 * of 6-7, the QH inactivate/reactivate code may need
+		 * modification to work with QHs for full/low speed
+		 * devices behind a hub that have a period of 1.
+		 */
+		ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
+		cpufreq_register_notifier(&ehci->cpufreq_transition,
+					  CPUFREQ_TRANSITION_NOTIFIER);
+	}
+#endif
+
 	return 0;
 }
 
diff -purN --exclude='*cmd' --exclude=tags linux-2.6.20orig/drivers/usb/host/ehci-mem.c linux-2.6.20/drivers/usb/host/ehci-mem.c
--- linux-2.6.20orig/drivers/usb/host/ehci-mem.c	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/drivers/usb/host/ehci-mem.c	2007-03-02 05:32:52.000000000 -0600
@@ -94,6 +94,9 @@ static struct ehci_qh *ehci_qh_alloc (st
 	qh->qh_dma = dma;
 	// INIT_LIST_HEAD (&qh->qh_list);
 	INIT_LIST_HEAD (&qh->qtd_list);
+#ifdef CONFIG_CPU_FREQ
+	INIT_LIST_HEAD (&qh->split_intr_qhs);
+#endif
 
 	/* dummy td enables safe urb queuing */
 	qh->dummy = ehci_qtd_alloc (ehci, flags);
diff -purN --exclude='*cmd' --exclude=tags linux-2.6.20orig/drivers/usb/host/ehci-q.c linux-2.6.20/drivers/usb/host/ehci-q.c
--- linux-2.6.20orig/drivers/usb/host/ehci-q.c	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/drivers/usb/host/ehci-q.c	2007-03-07 05:59:33.000000000 -0600
@@ -311,6 +311,10 @@ qh_completions (struct ehci_hcd *ehci, s
 		struct urb	*urb;
 		u32		token = 0;
 
+		/* ignore QHs that are currently inactive */
+		if (qh->hw_info1 & __constant_cpu_to_le32 (QH_INACTIVATE))
+			break;
+
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		urb = qtd->urb;
 
diff -purN --exclude='*cmd' --exclude=tags linux-2.6.20orig/drivers/usb/host/ehci-sched.c linux-2.6.20/drivers/usb/host/ehci-sched.c
--- linux-2.6.20orig/drivers/usb/host/ehci-sched.c	2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20/drivers/usb/host/ehci-sched.c	2007-03-07 05:25:15.000000000 -0600
@@ -473,6 +473,103 @@ static int disable_periodic (struct ehci
 }
 
 /*-------------------------------------------------------------------------*/
+#ifdef CONFIG_CPU_FREQ
+
+/* ignore/inactivate bit in QH hw_info1 */
+#define INACTIVATE_BIT __constant_cpu_to_le32 (QH_INACTIVATE)
+
+#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
+#define ACTIVE_BIT __constant_cpu_to_le32(QTD_STS_ACTIVE)
+#define STATUS_BIT __constant_cpu_to_le32(QTD_STS_STS)
+
+static int safe_to_inactivate (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	/*
+	 * Some HCs (Broadcom/ServerWorks HT1000) will stop in the
+	 * middle of a split transaction when you set the "I" bit.
+	 */
+	int now; /* current (frame * 8) + uframe */
+	int prev_start, next_start; /* uframes from/to split start */
+	int start_uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK);
+
+	now = readl (&ehci->regs->frame_index) % (ehci->periodic_size << 3);
+
+	next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now) %
+		     (qh->period << 3);
+	prev_start = (qh->period << 3) - next_start;
+
+	if ((qh->period << 3) <= (ehci->i_thresh + 2)) {
+		/* Can't handle qh->period = 1 with ehci->i_thresh >= 6,
+		 * because we'd never have a uframe during which we know
+		 * we could inactivate the QH without it completing after
+		 * we set the "I" bit.
+		 */
+		return -EINVAL;
+	}
+
+	/*
+	 * Make sure the split transaction hasn't already started.  We'll see
+	 * QTD_STS_STS set if the split transaction was started (but not
+	 * done) if we wait until the 2nd frame after the split should have
+	 * started.
+	 * Also, to avoid setting "I" after the start split happens, don't
+	 * set the "I" bit in a uframe that might already be cached in the
+	 * controller when we set it (using ehci->i_thresh).
+	 *
+	 * It's easier to set the "i" bit when the transaction isn't active
+	 * than trying to figure out if it completed after we set the "i" bit!
+	 */
+	if ((next_start > ehci->i_thresh) && (prev_start > 1))
+		/* safe to set "i" bit if split isn't in progress */
+		return (qh->hw_token & STATUS_BIT) ? 0 : 1;
+	else
+		return 0;
+}
+
+static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci)
+{
+	struct ehci_qh	*qh;
+	int not_done, safe;
+
+	/* Set inactivate bit for all the split interrupt QHs. */
+	do {
+		not_done = 0;
+		list_for_each_entry (qh, &ehci->split_intr_qhs,
+				     split_intr_qhs) {
+			if (qh->hw_info1 & INACTIVATE_BIT) /* already off */
+				continue;
+
+			safe = safe_to_inactivate (ehci, qh);
+			if (safe < 0) {
+				continue;
+			} else if (safe > 0) {
+				qh->was_active = qh->hw_token & ACTIVE_BIT; 
+				qh->hw_info1 |= INACTIVATE_BIT;
+			} else
+				not_done = 1;
+		}
+	} while (not_done);
+	wmb();
+}
+
+static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
+{
+	struct ehci_qh	*qh;
+	u32		token;
+
+	list_for_each_entry (qh, &ehci->split_intr_qhs, split_intr_qhs) {
+		if (qh->hw_info1 & INACTIVATE_BIT) {
+			/* See EHCI 1.0 section 4.15.2.4 for description. */
+			token = qh->hw_token;
+			qh->hw_token = (token | HALT_BIT) & ~ACTIVE_BIT;
+			wmb();
+			qh->hw_info1 &= ~INACTIVATE_BIT;
+			wmb();
+			qh->hw_token = (token & ~HALT_BIT) | qh->was_active;
+		}
+	}
+}
+#endif
 
 /* periodic schedule slots have iso tds (normal or split) first, then a
  * sparse tree for active interrupt transfers.
@@ -490,6 +587,16 @@ static int qh_link_periodic (struct ehci
 		period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
 		qh, qh->start, qh->usecs, qh->c_usecs);
 
+#ifdef CONFIG_CPU_FREQ
+	/*
+	 * If low/full speed interrupt QHs are inactive (because of
+	 * cpufreq changing processor speeds), start QH with I flag set--
+	 * it will automatically be cleared when cpufreq is done.
+	 */
+	if (ehci->cpufreq_changing)
+		qh->hw_info1 |= __constant_cpu_to_le32 (QH_INACTIVATE);
+#endif
+
 	/* high bandwidth, or otherwise every microframe */
 	if (period == 0)
 		period = 1;
@@ -538,6 +645,12 @@ static int qh_link_periodic (struct ehci
 		? ((qh->usecs + qh->c_usecs) / qh->period)
 		: (qh->usecs * 8);
 
+#ifdef CONFIG_CPU_FREQ
+	/* add qh to list of low/full speed interrupt QHs, if applicable */
+	if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
+		list_add (&qh->split_intr_qhs, &ehci->split_intr_qhs);
+	}
+#endif
 	/* maybe enable periodic schedule processing */
 	if (!ehci->periodic_sched++)
 		return enable_periodic (ehci);
@@ -557,6 +670,13 @@ static void qh_unlink_periodic (struct e
 	// THEN
 	//   qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
 
+#ifdef CONFIG_CPU_FREQ
+	/* remove qh from list of low/full speed interrupt QHs */
+	if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
+		list_del_init (&qh->split_intr_qhs);
+	}
+#endif
+
 	/* high bandwidth, or otherwise part of every microframe */
 	if ((period = qh->period) == 0)
 		period = 1;
