Commit 66282fd9 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: usb hcd-pci suspend/resume updates

This patch has some updates to the hcd pci power management glue:

  - removes now-obsolete comments (driver model now exists)

  - better state transitions:
      * suspending "dead" controllers needn't oops
      * multi-resume case (pm bug) simplified
      * multi-suspend case likewise (not always a bug)
      * should handle transitions other than D0->D3{hot,cold}

  - prepares for usb remote wake up support, which will be
    wanting the driver model suspend/resume code to be ready.
parent e7dbd617
...@@ -257,33 +257,6 @@ EXPORT_SYMBOL (usb_hcd_pci_remove); ...@@ -257,33 +257,6 @@ EXPORT_SYMBOL (usb_hcd_pci_remove);
#ifdef CONFIG_PM #ifdef CONFIG_PM
/*
* Some "sleep" power levels imply updating struct usb_driver
* to include a callback asking hcds to do their bit by checking
* if all the drivers can suspend. Gets involved with remote wakeup.
*
* If there are pending urbs, then HCs will need to access memory,
* causing extra power drain. New sleep()/wakeup() PM calls might
* be needed, beyond PCI suspend()/resume(). The root hub timer
* still be accessing memory though ...
*
* FIXME: USB should have some power budgeting support working with
* all kinds of hubs.
*
* FIXME: This assumes only D0->D3 suspend and D3->D0 resume.
* D1 and D2 states should do something, yes?
*
* FIXME: Should provide generic enable_wake(), calling pci_enable_wake()
* for all supported states, so that USB remote wakeup can work for any
* devices that support it (and are connected via powered hubs).
*
* FIXME: resume doesn't seem to work right any more...
*/
// 2.4 kernels have issued concurrent resumes (w/APM)
// we defend against that error; PCI doesn't yet.
/** /**
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
* @dev: USB Host Controller being suspended * @dev: USB Host Controller being suspended
...@@ -294,20 +267,29 @@ EXPORT_SYMBOL (usb_hcd_pci_remove); ...@@ -294,20 +267,29 @@ EXPORT_SYMBOL (usb_hcd_pci_remove);
int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
{ {
struct usb_hcd *hcd; struct usb_hcd *hcd;
int retval; int retval = 0;
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
dev_info (hcd->controller, "suspend to state %d\n", state); switch (hcd->state) {
case USB_STATE_HALT:
dev_dbg (hcd->controller, "halted; hcd not suspended\n");
break;
case USB_STATE_SUSPENDED:
dev_dbg (hcd->controller, "suspend D%d --> D%d\n",
dev->current_state, state);
break;
default:
dev_dbg (hcd->controller, "suspend to state %d\n", state);
pci_save_state (dev, hcd->pci_state); /* remote wakeup needs hub->suspend() cooperation */
// pci_enable_wake (dev, 3, 1);
// FIXME for all connected devices, leaf-to-root: pci_save_state (dev, hcd->pci_state);
// driver->suspend()
// proposed "new 2.5 driver model" will automate that
/* driver may want to disable DMA etc */ /* driver may want to disable DMA etc */
retval = hcd->driver->suspend (hcd, state); retval = hcd->driver->suspend (hcd, state);
hcd->state = USB_STATE_SUSPENDED; hcd->state = USB_STATE_SUSPENDED;
}
pci_set_power_state (dev, state); pci_set_power_state (dev, state);
return retval; return retval;
...@@ -326,39 +308,24 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -326,39 +308,24 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
int retval; int retval;
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
dev_info (hcd->controller, "resume\n");
/* guard against multiple resumes (APM bug?) */
atomic_inc (&hcd->resume_count);
if (atomic_read (&hcd->resume_count) != 1) {
dev_err (hcd->controller, "concurrent PCI resumes\n");
retval = 0;
goto done;
}
retval = -EBUSY;
if (hcd->state != USB_STATE_SUSPENDED) { if (hcd->state != USB_STATE_SUSPENDED) {
dev_dbg (hcd->controller, "can't resume, not suspended!\n"); dev_dbg (hcd->controller, "can't resume, not suspended!\n");
goto done; return -EL3HLT;
} }
hcd->state = USB_STATE_RESUMING; hcd->state = USB_STATE_RESUMING;
pci_set_power_state (dev, 0); pci_set_power_state (dev, 0);
pci_restore_state (dev, hcd->pci_state); pci_restore_state (dev, hcd->pci_state);
/* remote wakeup needs hub->suspend() cooperation */
// pci_enable_wake (dev, 3, 0);
retval = hcd->driver->resume (hcd); retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) { if (!HCD_IS_RUNNING (hcd->state)) {
dev_dbg (hcd->controller, "resume fail, retval %d\n", retval); dev_dbg (hcd->controller, "resume fail, retval %d\n", retval);
usb_hc_died (hcd); usb_hc_died (hcd);
// FIXME: recover, reset etc.
} else {
// FIXME for all connected devices, root-to-leaf:
// driver->resume ();
// proposed "new 2.5 driver model" will automate that
} }
done:
atomic_dec (&hcd->resume_count);
return retval; return retval;
} }
EXPORT_SYMBOL (usb_hcd_pci_resume); EXPORT_SYMBOL (usb_hcd_pci_resume);
......
...@@ -82,7 +82,6 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -82,7 +82,6 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
int region; /* pci region for regs */ int region; /* pci region for regs */
u32 pci_state [16]; /* for PM state save */ u32 pci_state [16]; /* for PM state save */
atomic_t resume_count; /* multiple resumes issue */
#endif #endif
#define HCD_BUFFER_POOLS 4 #define HCD_BUFFER_POOLS 4
...@@ -220,11 +219,8 @@ extern int usb_hcd_pci_probe (struct pci_dev *dev, ...@@ -220,11 +219,8 @@ extern int usb_hcd_pci_probe (struct pci_dev *dev,
extern void usb_hcd_pci_remove (struct pci_dev *dev); extern void usb_hcd_pci_remove (struct pci_dev *dev);
#ifdef CONFIG_PM #ifdef CONFIG_PM
// FIXME: see Documentation/power/pci.txt (2.4.6 and later?)
// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state);
extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state); extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
extern int usb_hcd_pci_resume (struct pci_dev *dev); extern int usb_hcd_pci_resume (struct pci_dev *dev);
// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg);
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment