On 2013/3/23 1:35, Alan Stern wrote:> Tianyu: > > Did you ever test the port power-off mechanism with system suspend? > Right now it doesn't seem like it would work, because it relies on > runtime PM to turn off the port power, and runtime PM doesn't operate > normally during a system suspend. > > Alan Stern > Hi Alan: You are right. Current the port power-off can't work during system suspend. I have already worked on a patch of adding usb port system pm support. But there is a still problem that how to control power off mechanism from kernel side. Before, we have a solution for runtime pm that increase/decrease port dev's usage count. http://marc.info/?l=linux-usb&m=135772122031446&w=2 But now, we have another user, System pm. So I think we should find a solution to cover these two cases. Maybe add a new pm qos request for NO_POWER_OFF flag? I'd like to see your opinion. I have a patch that can work and it still needs to add some condition checks in the usb_port_system_suspend(). Dev's system wakeup disable and persist enable. >From c3abd373707910672d6fd2e96da78879b3e22417 Mon Sep 17 00:00:00 2001 From: Lan Tianyu <tianyu.lan@xxxxxxxxx> Date: Tue, 26 Feb 2013 11:12:09 +0800 Subject: [PATCH] usb: Add usb port system pm support 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 without pm qos NO_POWER_OFF flag setting. During system pm, usb port should be powered off after dev being suspended and powered on before dev being resumed. Usb ports and devs enable async suspend. In order to keeping the order, call device_pm_wait_for_dev() in the usb_port_system_suspend() and usb_port_resume(). Usb_port_system_suspend() ignores EAGAIN from usb_port_runtime_suspend(). EAGAIN is caused by pm qos NO_POWER_OFF setting. This is not an error for usb port system pm. --- drivers/usb/core/hub.c | 4 ++++ drivers/usb/core/port.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 53c1555..8868f15 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3162,6 +3162,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..e5c6ec5 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -84,6 +84,9 @@ static int usb_port_runtime_resume(struct device *dev) if (!hub) return -EINVAL; + if (port_dev->power_is_on) + return 0; + usb_autopm_get_interface(intf); set_bit(port1, hub->busy_bits); @@ -127,6 +130,9 @@ static int usb_port_runtime_suspend(struct device *dev) == PM_QOS_FLAGS_ALL) return -EAGAIN; + if (!port_dev->power_is_on) + return 0; + usb_autopm_get_interface(intf); set_bit(port1, hub->busy_bits); retval = usb_hub_set_port_power(hdev, port1, false); @@ -136,9 +142,34 @@ 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->child) + 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) +{ + 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.10.4 -- Best Regards Tianyu Lan linux kernel enabling team -- 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