aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-03-29 07:43:56 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2005-03-29 07:43:56 -0800
commit5ae36c9152fa204845b48491e8bd86bf1ed23858 (patch)
tree51636b819265f2d0fe5a76174866c6ebcf6fbcce
parent2d615d2bda151f93bb626695be41663e38954828 (diff)
downloadhistory-5ae36c9152fa204845b48491e8bd86bf1ed23858.tar.gz
[PATCH] USB: ohci D3 resume fix
This fixes a problem that cropped up resuming OHCI from PCI D3 on NForce2. Evidently the register controlling frame timing gets clobbered in D3, but not other registers ... a "by the book" reinit seems to solve this particular problem. (And ought to help a few startup glitches on other implementations. Linux never used that toggle bit before, and has had to struggle with glitchy init...) It also updates some diagnostics to be bit more useful, and tries to avoid a particular "wakeup while suspending" glitch that seems particular to one particular type of Australian mouse. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/ohci-dbg.c6
-rw-r--r--drivers/usb/host/ohci-hcd.c4
-rw-r--r--drivers/usb/host/ohci-hub.c5
-rw-r--r--drivers/usb/host/ohci.h8
4 files changed, 17 insertions, 6 deletions
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 6e3ad024a75ab..62f53a2138082 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -193,6 +193,10 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
maybe_print_eds (controller, "donehead",
ohci_readl (controller, &regs->donehead), next, size);
+
+ /* broken fminterval means traffic won't flow! */
+ ohci_dbg (controller, "fminterval %08x\n",
+ ohci_readl (controller, &regs->fminterval));
}
#define dbg_port_sw(hc,num,value,next,size) \
@@ -620,9 +624,11 @@ show_registers (struct class_device *class_dev, char *buf)
ohci_dbg_sw (ohci, &next, &size,
"bus %s, device %s\n"
+ "%s\n"
"%s version " DRIVER_VERSION "\n",
hcd->self.controller->bus->name,
hcd->self.controller->bus_id,
+ hcd->product_desc,
hcd_name);
if (bus->controller->power.power_state) {
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 770d855efdef3..1e27f10c1592c 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -587,7 +587,6 @@ retry:
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
}
- ohci_writel (ohci, ohci->fminterval, &ohci->regs->fminterval);
/* Tell the controller where the control and bulk lists are
* The lists are empty now. */
@@ -728,7 +727,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
if (ints & OHCI_INTR_RD) {
ohci_vdbg (ohci, "resume detect\n");
- schedule_work(&ohci->rh_resume);
+ if (hcd->state != HC_STATE_QUIESCING)
+ schedule_work(&ohci->rh_resume);
}
if (ints & OHCI_INTR_WDH) {
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index a3c2915be60df..e2fc4129dfc6e 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -169,7 +169,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
ohci_info (ohci, "wakeup\n");
break;
case OHCI_USB_OPER:
- ohci_dbg (ohci, "odd resume\n");
+ ohci_dbg (ohci, "already resumed\n");
status = 0;
break;
default: /* RESET, we lost power */
@@ -197,7 +197,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
&ohci->regs->roothub.portstatus [temp]);
}
- /* Some controllers (lucent) need extra-long delays */
+ /* Some controllers (lucent erratum) need extra-long delays */
hcd->state = HC_STATE_RESUMING;
mdelay (20 /* usb 11.5.1.10 */ + 15);
@@ -216,6 +216,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent);
ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca);
+ /* Sometimes PCI D3 suspend trashes frame timings ... */
periodic_reinit (ohci);
/* interrupts might have been disabled */
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 66fdf4f950cbd..2ba6e2b0210c9 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -599,12 +599,16 @@ static inline void disable (struct ohci_hcd *ohci)
#define FI 0x2edf /* 12000 bits per frame (-1) */
#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7))
+#define FIT (1 << 31)
#define LSTHRESH 0x628 /* lowspeed bit threshold */
-static inline void periodic_reinit (struct ohci_hcd *ohci)
+static void periodic_reinit (struct ohci_hcd *ohci)
{
- u32 fi = ohci->fminterval & 0x0ffff;
+ u32 fi = ohci->fminterval & 0x03fff;
+ u32 fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT;
+ ohci_writel (ohci, (fit ^ FIT) | ohci->fminterval,
+ &ohci->regs->fminterval);
ohci_writel (ohci, ((9 * fi) / 10) & 0x3fff,
&ohci->regs->periodicstart);
}