On Monday 27 April 2009, Alan Stern wrote: > This patch (as1236) converts the USB PCI power management routines > over to the new PM framework. > > Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> > CC: "Rafael J. Wysocki" <rjw@xxxxxxx> Looks good, thanks for doing this Alan! Acked-by: Rafael J. Wysocki <rjw@xxxxxxx> > --- > > Index: usb-2.6/drivers/usb/core/hcd.h > =================================================================== > --- usb-2.6.orig/drivers/usb/core/hcd.h > +++ usb-2.6/drivers/usb/core/hcd.h > @@ -261,14 +261,11 @@ struct pci_device_id; > extern int usb_hcd_pci_probe(struct pci_dev *dev, > const struct pci_device_id *id); > extern void usb_hcd_pci_remove(struct pci_dev *dev); > - > -#ifdef CONFIG_PM > -extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t msg); > -extern int usb_hcd_pci_resume(struct pci_dev *dev); > -#endif /* CONFIG_PM */ > - > extern void usb_hcd_pci_shutdown(struct pci_dev *dev); > > +#ifdef CONFIG_PM_SLEEP > +extern struct dev_pm_ops usb_hcd_pci_pm_ops; > +#endif > #endif /* CONFIG_PCI */ > > /* pci-ish (pdev null is ok) buffer alloc/mapping support */ > Index: usb-2.6/drivers/usb/core/hcd-pci.c > =================================================================== > --- usb-2.6.orig/drivers/usb/core/hcd-pci.c > +++ usb-2.6/drivers/usb/core/hcd-pci.c > @@ -185,194 +185,198 @@ void usb_hcd_pci_remove(struct pci_dev * > } > EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); > > - > -#ifdef CONFIG_PM > - > /** > - * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD > - * @dev: USB Host Controller being suspended > - * @message: Power Management message describing this state transition > - * > - * Store this function in the HCD's struct pci_driver as .suspend. > + * usb_hcd_pci_shutdown - shutdown host controller > + * @dev: USB Host Controller being shutdown > */ > -int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) > +void usb_hcd_pci_shutdown(struct pci_dev *dev) > +{ > + struct usb_hcd *hcd; > + > + hcd = pci_get_drvdata(dev); > + if (!hcd) > + return; > + > + if (hcd->driver->shutdown) > + hcd->driver->shutdown(hcd); > +} > +EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); > + > +#ifdef CONFIG_PM_SLEEP > + > +static int check_root_hub_suspended(struct device *dev) > +{ > + struct pci_dev *pci_dev = to_pci_dev(dev); > + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); > + > + if (!(hcd->state == HC_STATE_SUSPENDED || > + hcd->state == HC_STATE_HALT)) { > + dev_warn(dev, "Root hub is not suspended\n"); > + return -EBUSY; > + } > + return 0; > +} > + > +static int hcd_pci_suspend(struct device *dev) > { > - struct usb_hcd *hcd = pci_get_drvdata(dev); > - int retval = 0; > - int wake, w; > - int has_pci_pm; > + struct pci_dev *pci_dev = to_pci_dev(dev); > + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); > + int retval; > > /* Root hub suspend should have stopped all downstream traffic, > * and all bus master traffic. And done so for both the interface > * and the stub usb_device (which we check here). But maybe it > * didn't; writing sysfs power/state files ignores such rules... > - * > - * We must ignore the FREEZE vs SUSPEND distinction here, because > - * otherwise the swsusp will save (and restore) garbage state. > */ > - if (!(hcd->state == HC_STATE_SUSPENDED || > - hcd->state == HC_STATE_HALT)) { > - dev_warn(&dev->dev, "Root hub is not suspended\n"); > - retval = -EBUSY; > - goto done; > - } > + retval = check_root_hub_suspended(dev); > + if (retval) > + return retval; > > /* We might already be suspended (runtime PM -- not yet written) */ > - if (dev->current_state != PCI_D0) > - goto done; > + if (pci_dev->current_state != PCI_D0) > + return retval; > > if (hcd->driver->pci_suspend) { > - retval = hcd->driver->pci_suspend(hcd, message); > + retval = hcd->driver->pci_suspend(hcd, PMSG_SUSPEND); > suspend_report_result(hcd->driver->pci_suspend, retval); > if (retval) > - goto done; > + return retval; > } > > - synchronize_irq(dev->irq); > + synchronize_irq(pci_dev->irq); > > /* Downstream ports from this root hub should already be quiesced, so > * there will be no DMA activity. Now we can shut down the upstream > - * link (except maybe for PME# resume signaling) and enter some PCI > - * low power state, if the hardware allows. > + * link (except maybe for PME# resume signaling). We'll enter a > + * low power state during suspend_noirq, if the hardware allows. > */ > - pci_disable_device(dev); > + pci_disable_device(pci_dev); > + return retval; > +} > + > +static int hcd_pci_suspend_noirq(struct device *dev) > +{ > + struct pci_dev *pci_dev = to_pci_dev(dev); > + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); > + int retval; > + > + retval = check_root_hub_suspended(dev); > + if (retval) > + return retval; > > - pci_save_state(dev); > + pci_save_state(pci_dev); > > - /* Don't fail on error to enable wakeup. We rely on pci code > - * to reject requests the hardware can't implement, rather > - * than coding the same thing. > + /* If the root hub is HALTed rather than SUSPENDed, > + * disallow remote wakeup. > */ > - wake = (hcd->state == HC_STATE_SUSPENDED && > - device_may_wakeup(&dev->dev)); > - w = pci_wake_from_d3(dev, wake); > - if (w < 0) > - wake = w; > - dev_dbg(&dev->dev, "wakeup: %d\n", wake); > - > - /* Don't change state if we don't need to */ > - if (message.event == PM_EVENT_FREEZE || > - message.event == PM_EVENT_PRETHAW) { > - dev_dbg(&dev->dev, "--> no state change\n"); > - goto done; > - } > - > - has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); > - if (!has_pci_pm) { > - dev_dbg(&dev->dev, "--> PCI D0 legacy\n"); > - } else { > + if (hcd->state == HC_STATE_HALT) > + device_set_wakeup_enable(dev, 0); > + dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev)); > > - /* NOTE: dev->current_state becomes nonzero only here, and > - * only for devices that support PCI PM. Also, exiting > - * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset > - * some device state (e.g. as part of clock reinit). > - */ > - retval = pci_set_power_state(dev, PCI_D3hot); > - suspend_report_result(pci_set_power_state, retval); > - if (retval == 0) { > - dev_dbg(&dev->dev, "--> PCI D3\n"); > - } else { > - dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n", > - retval); > - pci_restore_state(dev); > - } > + /* Possibly enable remote wakeup, > + * choose the appropriate low-power state, and go to that state. > + */ > + retval = pci_prepare_to_sleep(pci_dev); > + if (retval == -EIO) { /* Low-power not supported */ > + dev_dbg(dev, "--> PCI D0 legacy\n"); > + retval = 0; > + } else if (retval == 0) { > + dev_dbg(dev, "--> PCI %s\n", > + pci_power_name(pci_dev->current_state)); > + } else { > + suspend_report_result(pci_prepare_to_sleep, retval); > + return retval; > } > > #ifdef CONFIG_PPC_PMAC > - if (retval == 0) { > - /* Disable ASIC clocks for USB */ > - if (machine_is(powermac)) { > - struct device_node *of_node; > - > - of_node = pci_device_to_OF_node(dev); > - if (of_node) > - pmac_call_feature(PMAC_FTR_USB_ENABLE, > - of_node, 0, 0); > - } > + /* Disable ASIC clocks for USB */ > + if (machine_is(powermac)) { > + struct device_node *of_node; > + > + of_node = pci_device_to_OF_node(pci_dev); > + if (of_node) > + pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); > } > #endif > - > - done: > return retval; > } > -EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend); > > -/** > - * usb_hcd_pci_resume - power management resume of a PCI-based HCD > - * @dev: USB Host Controller being resumed > - * > - * Store this function in the HCD's struct pci_driver as .resume. > - */ > -int usb_hcd_pci_resume(struct pci_dev *dev) > +static int hcd_pci_resume_noirq(struct device *dev) > { > - struct usb_hcd *hcd; > - int retval; > + struct pci_dev *pci_dev = to_pci_dev(dev); > > #ifdef CONFIG_PPC_PMAC > /* Reenable ASIC clocks for USB */ > if (machine_is(powermac)) { > struct device_node *of_node; > > - of_node = pci_device_to_OF_node(dev); > + of_node = pci_device_to_OF_node(pci_dev); > if (of_node) > pmac_call_feature(PMAC_FTR_USB_ENABLE, > of_node, 0, 1); > } > #endif > > - pci_restore_state(dev); > + /* Go back to D0 and disable remote wakeup */ > + pci_back_from_sleep(pci_dev); > + return 0; > +} > + > +static int resume_common(struct device *dev, bool hibernated) > +{ > + struct pci_dev *pci_dev = to_pci_dev(dev); > + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); > + int retval; > > - hcd = pci_get_drvdata(dev); > if (hcd->state != HC_STATE_SUSPENDED) { > - dev_dbg(hcd->self.controller, > - "can't resume, not suspended!\n"); > + dev_dbg(dev, "can't resume, not suspended!\n"); > return 0; > } > > - pci_enable_wake(dev, PCI_D0, false); > - > - retval = pci_enable_device(dev); > + retval = pci_enable_device(pci_dev); > if (retval < 0) { > - dev_err(&dev->dev, "can't re-enable after resume, %d!\n", > - retval); > + dev_err(dev, "can't re-enable after resume, %d!\n", retval); > return retval; > } > > - pci_set_master(dev); > - > - /* yes, ignore this result too... */ > - (void) pci_wake_from_d3(dev, 0); > + pci_set_master(pci_dev); > > clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); > > if (hcd->driver->pci_resume) { > retval = hcd->driver->pci_resume(hcd); > if (retval) { > - dev_err(hcd->self.controller, > - "PCI post-resume error %d!\n", retval); > + dev_err(dev, "PCI post-resume error %d!\n", retval); > usb_hc_died(hcd); > } > } > return retval; > } > -EXPORT_SYMBOL_GPL(usb_hcd_pci_resume); > - > -#endif /* CONFIG_PM */ > > -/** > - * usb_hcd_pci_shutdown - shutdown host controller > - * @dev: USB Host Controller being shutdown > - */ > -void usb_hcd_pci_shutdown(struct pci_dev *dev) > +static int hcd_pci_resume(struct device *dev) > { > - struct usb_hcd *hcd; > - > - hcd = pci_get_drvdata(dev); > - if (!hcd) > - return; > + return resume_common(dev, false); > +} > > - if (hcd->driver->shutdown) > - hcd->driver->shutdown(hcd); > +static int hcd_pci_restore(struct device *dev) > +{ > + return resume_common(dev, true); > } > -EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); > > +struct dev_pm_ops usb_hcd_pci_pm_ops = { > + .suspend = hcd_pci_suspend, > + .suspend_noirq = hcd_pci_suspend_noirq, > + .resume_noirq = hcd_pci_resume_noirq, > + .resume = hcd_pci_resume, > + .freeze = check_root_hub_suspended, > + .freeze_noirq = check_root_hub_suspended, > + .thaw_noirq = NULL, > + .thaw = NULL, > + .poweroff = hcd_pci_suspend, > + .poweroff_noirq = hcd_pci_suspend_noirq, > + .restore_noirq = hcd_pci_resume_noirq, > + .restore = hcd_pci_restore, > +}; > +EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); > + > +#endif /* CONFIG_PM_SLEEP */ > Index: usb-2.6/drivers/usb/host/ehci-pci.c > =================================================================== > --- usb-2.6.orig/drivers/usb/host/ehci-pci.c > +++ usb-2.6/drivers/usb/host/ehci-pci.c > @@ -429,10 +429,11 @@ static struct pci_driver ehci_pci_driver > > .probe = usb_hcd_pci_probe, > .remove = usb_hcd_pci_remove, > + .shutdown = usb_hcd_pci_shutdown, > > -#ifdef CONFIG_PM > - .suspend = usb_hcd_pci_suspend, > - .resume = usb_hcd_pci_resume, > +#ifdef CONFIG_PM_SLEEP > + .driver = { > + .pm = &usb_hcd_pci_pm_ops > + }, > #endif > - .shutdown = usb_hcd_pci_shutdown, > }; > Index: usb-2.6/drivers/usb/host/ohci-pci.c > =================================================================== > --- usb-2.6.orig/drivers/usb/host/ohci-pci.c > +++ usb-2.6/drivers/usb/host/ohci-pci.c > @@ -484,12 +484,11 @@ static struct pci_driver ohci_pci_driver > > .probe = usb_hcd_pci_probe, > .remove = usb_hcd_pci_remove, > + .shutdown = usb_hcd_pci_shutdown, > > -#ifdef CONFIG_PM > - .suspend = usb_hcd_pci_suspend, > - .resume = usb_hcd_pci_resume, > +#ifdef CONFIG_PM_SLEEP > + .driver = { > + .pm = &usb_hcd_pci_pm_ops > + }, > #endif > - > - .shutdown = usb_hcd_pci_shutdown, > }; > - > Index: usb-2.6/drivers/usb/host/uhci-hcd.c > =================================================================== > --- usb-2.6.orig/drivers/usb/host/uhci-hcd.c > +++ usb-2.6/drivers/usb/host/uhci-hcd.c > @@ -940,10 +940,11 @@ static struct pci_driver uhci_pci_driver > .remove = usb_hcd_pci_remove, > .shutdown = uhci_shutdown, > > -#ifdef CONFIG_PM > - .suspend = usb_hcd_pci_suspend, > - .resume = usb_hcd_pci_resume, > -#endif /* PM */ > +#ifdef CONFIG_PM_SLEEP > + .driver = { > + .pm = &usb_hcd_pci_pm_ops > + }, > +#endif > }; > > static int __init uhci_hcd_init(void) > > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html