diff options
author | David Brownell <david-b@pacbell.net> | 2005-03-29 07:43:56 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-03-29 07:43:56 -0800 |
commit | 5ae36c9152fa204845b48491e8bd86bf1ed23858 (patch) | |
tree | 51636b819265f2d0fe5a76174866c6ebcf6fbcce | |
parent | 2d615d2bda151f93bb626695be41663e38954828 (diff) | |
download | history-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.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ohci.h | 8 |
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, ®s->donehead), next, size); + + /* broken fminterval means traffic won't flow! */ + ohci_dbg (controller, "fminterval %08x\n", + ohci_readl (controller, ®s->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); } |