You forgot to Cc the linux-usb mailing list. On Mon, Mar 25, 2013 at 04:21:42PM +0800, Lan Tianyu wrote: > This patch is to add usb port system pm support. Add > usb port's system suspend/resume callbacks and call > usb_port_runtime_resume/suspend() to power off these > ports whose pm qos NO_POWER_OFF flag is not set, system > wakeup is disabled and persist is enalbed. > > During system pm, usb port should be powered off after > dev being suspended and powered on before dev being > resumed. Decause usb ports and devs enable async suspend, > call device_pm_wait_for_dev() in the usb_port_system_suspend() > and usb_port_resume() to keeping the order. > > Usb_port_system_suspend() ignores EAGAIN from usb_port_runtime_suspend(). > Because EAGAIN is caused by pm qos NO_POWER_OFF setting. This is > not an error for usb port system pm. > > If usb port was already powered off by runtime pm with > port_dev->power_is_on being false, usb_port_system_suspend() > returns directly. > > If usb port was not powered off during system suspend with > port_dev->power_is_on being true, usb_port_system_resume() > returns directly. > > Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx> > --- > drivers/usb/core/hub.c | 4 ++++ > drivers/usb/core/port.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 52 insertions(+) > > diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c > index 5480352..09948b6 100644 > --- a/drivers/usb/core/hub.c > +++ b/drivers/usb/core/hub.c > @@ -3146,6 +3146,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) > int status; > u16 portchange, portstatus; > > + /* Wait for usb port system resume finishing */ > + if (!PMSG_IS_AUTO(msg)) > + device_pm_wait_for_dev(&udev->dev, &port_dev->dev); > + > if (port_dev->did_runtime_put) { > status = pm_runtime_get_sync(&port_dev->dev); > port_dev->did_runtime_put = false; > diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c > index 797f9d5..553cab3 100644 > --- a/drivers/usb/core/port.c > +++ b/drivers/usb/core/port.c > @@ -136,9 +136,57 @@ static int usb_port_runtime_suspend(struct device *dev) > usb_autopm_put_interface(intf); > return retval; > } > +#else > +static int usb_port_runtime_suspend(struct device *dev) { return 0; } > +static int usb_port_runtime_resume(struct device *dev) { return 0; } > #endif > > +static int usb_port_system_suspend(struct device *dev) > +{ > + struct usb_port *port_dev = to_usb_port(dev); > + int retval; > + > + if (!port_dev->power_is_on) > + return 0; > + > + if (port_dev->child) { > + struct usb_device *udev = port_dev->child; > + > + /* > + * usb port can't be powered off when dev's system > + * wakeup is enabled or persist is disabled. > + */ > + if (device_may_wakeup(&udev->dev) > + || !udev->persist_enabled) > + return 0; > + > + /* > + * usb port should be powered off after usb dev > + * being suspended. > + */ > + device_pm_wait_for_dev(dev, &port_dev->child->dev); > + } > + > + retval = usb_port_runtime_suspend(dev); > + if (retval < 0 && retval != -EAGAIN) > + return retval; > + > + return 0; > +} > + > +static int usb_port_system_resume(struct device *dev) > +{ > + struct usb_port *port_dev = to_usb_port(dev); > + > + if (port_dev->power_is_on) > + return 0; > + > + return usb_port_runtime_resume(dev); > +} > + > static const struct dev_pm_ops usb_port_pm_ops = { > + .suspend = usb_port_system_suspend, > + .resume = usb_port_system_resume, > #ifdef CONFIG_USB_SUSPEND > .runtime_suspend = usb_port_runtime_suspend, > .runtime_resume = usb_port_runtime_resume, > -- > 1.7.9.5 > -- 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