aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-11-23 18:45:28 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-24 02:04:28 -0500
commitf03c17fc9abe8582d6ad830290b3093fdf1eea61 (patch)
treeb110f763ddf4043ef1b994ea2f284d02f6039921
parentb4723ae3cc66fd067a8e661b5c05d5bd41be29b5 (diff)
[PATCH] USB: EHCI updates
This fixes some bugs in EHCI suspend/resume that joined us over the past few releases (as usbcore, PCI, pmcore, and other components evolved): - Removes suspend and resume recursion from the EHCI driver, getting rid of the USB_SUSPEND special casing. - Updates the wakeup mechanism to work again; there's a newish usbcore call it needs to use. - Provide simpler tests for "do we need to restart from scratch", to address another case where PCI Vaux was lost. (In this case it was restoring a swsusp snapshot, but there could be others.) Un-exports a symbol that was temporarily exported. A notable change from previous version is that this doesn't move the spinlock init, so there's still a resume/reinit path bug. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/usb/core/hub.c1
-rw-r--r--drivers/usb/host/ehci-hcd.c3
-rw-r--r--drivers/usb/host/ehci-hub.c7
-rw-r--r--drivers/usb/host/ehci-pci.c77
4 files changed, 46 insertions, 42 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 840727948d84..f78bd124d290 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1669,7 +1669,6 @@ int usb_suspend_device(struct usb_device *udev)
1669 return 0; 1669 return 0;
1670#endif 1670#endif
1671} 1671}
1672EXPORT_SYMBOL_GPL(usb_suspend_device);
1673 1672
1674/* 1673/*
1675 * If the USB "suspend" state is in use (rather than "global suspend"), 1674 * If the USB "suspend" state is in use (rather than "global suspend"),
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index af3c05eb86fc..f15144e96e14 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -636,9 +636,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
636 * stop that signaling. 636 * stop that signaling.
637 */ 637 */
638 ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); 638 ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
639 mod_timer (&hcd->rh_timer,
640 ehci->reset_done [i] + 1);
641 ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); 639 ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
640 usb_hcd_resume_root_hub(hcd);
642 } 641 }
643 } 642 }
644 643
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 88cb4ada686e..82caf336e9b6 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -94,6 +94,13 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
94 msleep(5); 94 msleep(5);
95 spin_lock_irq (&ehci->lock); 95 spin_lock_irq (&ehci->lock);
96 96
97 /* Ideally and we've got a real resume here, and no port's power
98 * was lost. (For PCI, that means Vaux was maintained.) But we
99 * could instead be restoring a swsusp snapshot -- so that BIOS was
100 * the last user of the controller, not reset/pm hardware keeping
101 * state we gave to it.
102 */
103
97 /* re-init operational registers in case we lost power */ 104 /* re-init operational registers in case we lost power */
98 if (readl (&ehci->regs->intr_enable) == 0) { 105 if (readl (&ehci->regs->intr_enable) == 0) {
99 /* at least some APM implementations will try to deliver 106 /* at least some APM implementations will try to deliver
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index dfd9bd0b1828..0f2be91e5e0e 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -235,10 +235,11 @@ static void ehci_pci_stop (struct usb_hcd *hcd)
235 235
236/* suspend/resume, section 4.3 */ 236/* suspend/resume, section 4.3 */
237 237
238/* These routines rely on the bus (pci, platform, etc) 238/* These routines rely on the PCI bus glue
239 * to handle powerdown and wakeup, and currently also on 239 * to handle powerdown and wakeup, and currently also on
240 * transceivers that don't need any software attention to set up 240 * transceivers that don't need any software attention to set up
241 * the right sort of wakeup. 241 * the right sort of wakeup.
242 * Also they depend on separate root hub suspend/resume.
242 */ 243 */
243 244
244static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) 245static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
@@ -246,17 +247,9 @@ static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
246 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 247 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
247 248
248 if (time_before (jiffies, ehci->next_statechange)) 249 if (time_before (jiffies, ehci->next_statechange))
249 msleep (100); 250 msleep (10);
250
251#ifdef CONFIG_USB_SUSPEND
252 (void) usb_suspend_device (hcd->self.root_hub);
253#else
254 usb_lock_device (hcd->self.root_hub);
255 (void) ehci_bus_suspend (hcd);
256 usb_unlock_device (hcd->self.root_hub);
257#endif
258 251
259 // save (PCI) FLADJ in case of Vaux power loss 252 // could save FLADJ in case of Vaux power loss
260 // ... we'd only use it to handle clock skew 253 // ... we'd only use it to handle clock skew
261 254
262 return 0; 255 return 0;
@@ -269,13 +262,18 @@ static int ehci_pci_resume (struct usb_hcd *hcd)
269 struct usb_device *root = hcd->self.root_hub; 262 struct usb_device *root = hcd->self.root_hub;
270 int retval = -EINVAL; 263 int retval = -EINVAL;
271 264
272 // maybe restore (PCI) FLADJ 265 // maybe restore FLADJ
273 266
274 if (time_before (jiffies, ehci->next_statechange)) 267 if (time_before (jiffies, ehci->next_statechange))
275 msleep (100); 268 msleep (100);
276 269
270 /* If CF is clear, we lost PCI Vaux power and need to restart. */
271 if (readl (&ehci->regs->configured_flag) != cpu_to_le32(FLAG_CF))
272 goto restart;
273
277 /* If any port is suspended (or owned by the companion), 274 /* If any port is suspended (or owned by the companion),
278 * we know we can/must resume the HC (and mustn't reset it). 275 * we know we can/must resume the HC (and mustn't reset it).
276 * We just defer that to the root hub code.
279 */ 277 */
280 for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) { 278 for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
281 u32 status; 279 u32 status;
@@ -283,42 +281,43 @@ static int ehci_pci_resume (struct usb_hcd *hcd)
283 status = readl (&ehci->regs->port_status [port]); 281 status = readl (&ehci->regs->port_status [port]);
284 if (!(status & PORT_POWER)) 282 if (!(status & PORT_POWER))
285 continue; 283 continue;
286 if (status & (PORT_SUSPEND | PORT_OWNER)) { 284 if (status & (PORT_SUSPEND | PORT_RESUME | PORT_OWNER)) {
287 down (&hcd->self.root_hub->serialize); 285 usb_hcd_resume_root_hub(hcd);
288 retval = ehci_bus_resume (hcd); 286 return 0;
289 up (&hcd->self.root_hub->serialize);
290 break;
291 } 287 }
288 }
289
290restart:
291 ehci_dbg(ehci, "lost power, restarting\n");
292 for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
293 port--;
292 if (!root->children [port]) 294 if (!root->children [port])
293 continue; 295 continue;
294 dbg_port (ehci, __FUNCTION__, port + 1, status);
295 usb_set_device_state (root->children[port], 296 usb_set_device_state (root->children[port],
296 USB_STATE_NOTATTACHED); 297 USB_STATE_NOTATTACHED);
297 } 298 }
298 299
299 /* Else reset, to cope with power loss or flush-to-storage 300 /* Else reset, to cope with power loss or flush-to-storage
300 * style "resume" having activated BIOS during reboot. 301 * style "resume" having let BIOS kick in during reboot.
301 */ 302 */
302 if (port == 0) { 303 (void) ehci_halt (ehci);
303 (void) ehci_halt (ehci); 304 (void) ehci_reset (ehci);
304 (void) ehci_reset (ehci); 305 (void) ehci_pci_reset (hcd);
305 (void) ehci_pci_reset (hcd); 306
306 307 /* emptying the schedule aborts any urbs */
307 /* emptying the schedule aborts any urbs */ 308 spin_lock_irq (&ehci->lock);
308 spin_lock_irq (&ehci->lock); 309 if (ehci->reclaim)
309 if (ehci->reclaim) 310 ehci->reclaim_ready = 1;
310 ehci->reclaim_ready = 1; 311 ehci_work (ehci, NULL);
311 ehci_work (ehci, NULL); 312 spin_unlock_irq (&ehci->lock);
312 spin_unlock_irq (&ehci->lock); 313
313 314 /* restart; khubd will disconnect devices */
314 /* restart; khubd will disconnect devices */ 315 retval = ehci_run (hcd);
315 retval = ehci_run (hcd); 316
316 317 /* here we "know" root ports should always stay powered;
317 /* here we "know" root ports should always stay powered; 318 * but some controllers may lose all power.
318 * but some controllers may lose all power. 319 */
319 */ 320 ehci_port_power (ehci, 1);
320 ehci_port_power (ehci, 1);
321 }
322 321
323 return retval; 322 return retval;
324} 323}