OHCI: final fix for NVIDIA problems (I hope)

Problems with NVIDIA's OHCI host controllers persist.  After looking
carefully through the spec, I finally realized that when a controller
is reset it then automatically goes into a SUSPEND state in which it
is completely quiescent (no DMA and no IRQs) and from which it will
not awaken until the system puts it into the OPERATIONAL state.

Therefore there's no need to worry about controllers being in the
RESET state for extended periods, or remaining in the OPERATIONAL
state during system shutdown.  The proper action for device
initialization is to put the controller into the RESET state (if it's
not there already) and then to issue a software reset.  Similarly, the
proper action for device shutdown is simply to do a software reset.

This patch (as1499) implements such an approach.  It simplifies
initialization and shutdown, and allows the NVIDIA shutdown-quirk code
to be removed.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested-by: Andre "Osku" Schmidt <andre.osku.schmidt@googlemail.com>
Tested-by: Arno Augustin <Arno.Augustin@web.de>
Cc: stable <stable@vger.kernel.org> [after tested in 3.2 for a while]
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 34efd47..b263919 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -389,17 +389,14 @@
 	struct ohci_hcd *ohci;
 
 	ohci = hcd_to_ohci (hcd);
-	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-	ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
+	ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable);
 
-	/* If the SHUTDOWN quirk is set, don't put the controller in RESET */
-	ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ?
-			OHCI_CTRL_RWC | OHCI_CTRL_HCFS :
-			OHCI_CTRL_RWC);
-	ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
+	/* Software reset, after which the controller goes into SUSPEND */
+	ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus);
+	ohci_readl(ohci, &ohci->regs->cmdstatus);	/* flush the writes */
+	udelay(10);
 
-	/* flush the writes */
-	(void) ohci_readl (ohci, &ohci->regs->control);
+	ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval);
 }
 
 static int check_ed(struct ohci_hcd *ohci, struct ed *ed)