ChangeSet 1.1760.26.5, 2004/06/24 10:21:05-07:00, david-b@pacbell.net

[PATCH] USB: EHCI IRQ tweaks

Various tweaks to EHCI IRQ handling, these may affact some systems.

 - Delays enabling IRQs until the root hub is more fully set up, so
   any "resume detect" IRQs can be handled properly.  (Craig Nadler)

 - Power down ports on driver shutdown.  (Craig Nadler)

 - Remove some duplicate irq-sharing logic that somehow crept in; check
   only once, and return IRQ_NONE to detect IRQ storms better (db)

 - Minor comment fix re integrated TTs.  (db)

From:          Craig Nadler <craig.nadler@arc.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>


 drivers/usb/host/ehci-hcd.c |   29 ++++++++++++++++++-----------
 1 files changed, 18 insertions(+), 11 deletions(-)


diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	2004-06-29 16:26:32 -07:00
+++ b/drivers/usb/host/ehci-hcd.c	2004-06-29 16:26:32 -07:00
@@ -425,7 +425,6 @@
 		ehci_mem_cleanup (ehci);
 		return retval;
 	}
-	writel (INTR_MASK, &ehci->regs->intr_enable);
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
 #ifdef	CONFIG_PCI
@@ -531,7 +530,8 @@
 	/*
 	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
 	 * are explicitly handed to companion controller(s), so no TT is
-	 * involved with the root hub.
+	 * involved with the root hub.  (Except where one is integrated,
+	 * and there's no companion controller unless maybe for USB OTG.)
 	 */
 	ehci->reboot_notifier.notifier_call = ehci_reboot;
 	register_reboot_notifier (&ehci->reboot_notifier);
@@ -563,6 +563,8 @@
 		goto done2;
 	}
 
+	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+
 	create_debug_files (ehci);
 
 	return 0;
@@ -573,6 +575,7 @@
 static void ehci_stop (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u8			rh_ports, port;
 
 	ehci_dbg (ehci, "stop\n");
 
@@ -584,7 +587,16 @@
 		return;
 	}
 	del_timer_sync (&ehci->watchdog);
+
+	/* Turn off port power on all root hub ports. */
+	rh_ports = HCS_N_PORTS (ehci->hcs_params);
+	for (port = 1; port <= rh_ports; port++) {
+		ehci_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER,
+			port, NULL, 0);
+	}
+
 	ehci_reset (ehci);
+	writel (0, &ehci->regs->intr_enable);
 
 	/* let companion controllers work when we aren't */
 	writel (0, &ehci->regs->configured_flag);
@@ -704,12 +716,6 @@
 
 	status = readl (&ehci->regs->status);
 
-	/* shared irq */
-	if (status == 0) {
-		spin_unlock (&ehci->lock);
-		return IRQ_NONE;
-	}
-
 	/* e.g. cardbus physical eject */
 	if (status == ~(u32) 0) {
 		ehci_dbg (ehci, "device removed\n");
@@ -717,8 +723,10 @@
 	}
 
 	status &= INTR_MASK;
-	if (!status)			/* irq sharing? */
-		goto done;
+	if (!status) {			/* irq sharing? */
+		spin_unlock(&ehci->lock);
+		return IRQ_NONE;
+	}
 
 	/* clear (just) interrupts */
 	writel (status, &ehci->regs->status);
@@ -789,7 +797,6 @@
 
 	if (bh)
 		ehci_work (ehci, regs);
-done:
 	spin_unlock (&ehci->lock);
 	return IRQ_HANDLED;
 }
