ChangeSet 1.1123.18.15, 2003/08/13 14:39:09-07:00, david-b@pacbell.net [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. drivers/usb/core/hcd-pci.c | 83 +++++++++++++-------------------------------- drivers/usb/core/hcd.h | 4 -- 2 files changed, 25 insertions(+), 62 deletions(-) diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Fri Aug 15 10:45:38 2003 +++ b/drivers/usb/core/hcd-pci.c Fri Aug 15 10:45:38 2003 @@ -257,33 +257,6 @@ #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 * @dev: USB Host Controller being suspended @@ -294,20 +267,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) { struct usb_hcd *hcd; - int retval; + int retval = 0; hcd = pci_get_drvdata(dev); - dev_info (hcd->controller, "suspend to state %d\n", state); - - pci_save_state (dev, hcd->pci_state); - - // FIXME for all connected devices, leaf-to-root: - // driver->suspend() - // proposed "new 2.5 driver model" will automate that - - /* driver may want to disable DMA etc */ - retval = hcd->driver->suspend (hcd, state); - hcd->state = USB_STATE_SUSPENDED; + 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); + + /* remote wakeup needs hub->suspend() cooperation */ + // pci_enable_wake (dev, 3, 1); + + pci_save_state (dev, hcd->pci_state); + + /* driver may want to disable DMA etc */ + retval = hcd->driver->suspend (hcd, state); + hcd->state = USB_STATE_SUSPENDED; + } pci_set_power_state (dev, state); return retval; @@ -326,39 +308,24 @@ int retval; 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) { dev_dbg (hcd->controller, "can't resume, not suspended!\n"); - goto done; + return -EL3HLT; } hcd->state = USB_STATE_RESUMING; pci_set_power_state (dev, 0); pci_restore_state (dev, hcd->pci_state); + /* remote wakeup needs hub->suspend() cooperation */ + // pci_enable_wake (dev, 3, 0); + retval = hcd->driver->resume (hcd); if (!HCD_IS_RUNNING (hcd->state)) { dev_dbg (hcd->controller, "resume fail, retval %d\n", retval); 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; } EXPORT_SYMBOL (usb_hcd_pci_resume); diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Fri Aug 15 10:45:38 2003 +++ b/drivers/usb/core/hcd.h Fri Aug 15 10:45:38 2003 @@ -82,7 +82,6 @@ #ifdef CONFIG_PCI int region; /* pci region for regs */ u32 pci_state [16]; /* for PM state save */ - atomic_t resume_count; /* multiple resumes issue */ #endif #define HCD_BUFFER_POOLS 4 @@ -220,11 +219,8 @@ extern void usb_hcd_pci_remove (struct pci_dev *dev); #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_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_PCI */