2016-11-18 12:02:16

by Baolin Wang

[permalink] [raw]
Subject: [PATCH 1/2] usb: host: plat: Enable xhci plat runtime PM

Enable the xhci plat runtime PM for parent device to suspend/resume xhci.

Signed-off-by: Baolin Wang <[email protected]>
---
drivers/usb/host/xhci-plat.c | 37 ++++++++++++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index ed56bf9..13f86ad 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -246,6 +246,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (ret)
goto dealloc_usb2_hcd;

+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
return 0;


@@ -274,6 +277,7 @@ static int xhci_plat_remove(struct platform_device *dev)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct clk *clk = xhci->clk;

+ pm_runtime_disable(&dev->dev);
usb_remove_hcd(xhci->shared_hcd);
usb_phy_shutdown(hcd->usb_phy);

@@ -311,14 +315,37 @@ static int xhci_plat_resume(struct device *dev)

return xhci_resume(xhci, 0);
}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int xhci_plat_runtime_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ return xhci_suspend(xhci, device_may_wakeup(dev));
+}
+
+static int xhci_plat_runtime_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ return xhci_resume(xhci, 0);
+}
+
+static int xhci_plat_runtime_idle(struct device *dev)
+{
+ return 0;
+}
+#endif /* CONFIG_PM */

static const struct dev_pm_ops xhci_plat_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
+
+ SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, xhci_plat_runtime_resume,
+ xhci_plat_runtime_idle)
};
-#define DEV_PM_OPS (&xhci_plat_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM */

static const struct acpi_device_id usb_xhci_acpi_match[] = {
/* XHCI-compliant USB Controller */
@@ -332,7 +359,7 @@ static int xhci_plat_resume(struct device *dev)
.remove = xhci_plat_remove,
.driver = {
.name = "xhci-hcd",
- .pm = DEV_PM_OPS,
+ .pm = &xhci_plat_pm_ops,
.of_match_table = of_match_ptr(usb_xhci_of_match),
.acpi_match_table = ACPI_PTR(usb_xhci_acpi_match),
},
--
1.7.9.5


2016-11-18 12:02:22

by Baolin Wang

[permalink] [raw]
Subject: [PATCH 2/2] usb: dwc3: core: Support the dwc3 host suspend/resume

For some mobile devices with strict power management, we also want to suspend
the host when the slave is detached for power saving. Thus we add the host
suspend/resume functions to support this requirement.

Signed-off-by: Baolin Wang <[email protected]>
---
drivers/usb/dwc3/Kconfig | 7 ++++++
drivers/usb/dwc3/core.c | 26 ++++++++++++++++++++++-
drivers/usb/dwc3/core.h | 15 +++++++++++++
drivers/usb/dwc3/host.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index a45b4f1..47bb2f3 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -47,6 +47,13 @@ config USB_DWC3_DUAL_ROLE

endchoice

+config USB_DWC3_HOST_SUSPEND
+ bool "Choose if the DWC3 host (xhci) can be suspend/resume"
+ depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y
+ help
+ We can suspend the host when the slave is detached for power saving,
+ and resume the host when one slave is attached.
+
comment "Platform Glue Driver Support"

config USB_DWC3_OMAP
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 9a4a5e4..7ad4bc3 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1091,6 +1091,7 @@ static int dwc3_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
pm_runtime_enable(dev);
+ pm_suspend_ignore_children(dev, true);
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err1;
@@ -1215,15 +1216,27 @@ static int dwc3_remove(struct platform_device *pdev)
static int dwc3_suspend_common(struct dwc3 *dwc)
{
unsigned long flags;
+ int ret;

switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_suspend(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ break;
case USB_DR_MODE_OTG:
+ ret = dwc3_host_suspend(dwc);
+ if (ret)
+ return ret;
+
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
break;
case USB_DR_MODE_HOST:
+ ret = dwc3_host_suspend(dwc);
+ if (ret)
+ return ret;
default:
/* do nothing */
break;
@@ -1245,12 +1258,23 @@ static int dwc3_resume_common(struct dwc3 *dwc)

switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_resume(dwc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+ break;
case USB_DR_MODE_OTG:
+ ret = dwc3_host_resume(dwc);
+ if (ret)
+ return ret;
+
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
- /* FALLTHROUGH */
+ break;
case USB_DR_MODE_HOST:
+ ret = dwc3_host_resume(dwc);
+ if (ret)
+ return ret;
default:
/* do nothing */
break;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b585a30..db41908 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1226,4 +1226,19 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc)
{ }
#endif

+#if IS_ENABLED(CONFIG_USB_DWC3_HOST_SUSPEND)
+int dwc3_host_suspend(struct dwc3 *dwc);
+int dwc3_host_resume(struct dwc3 *dwc);
+#else
+static inline int dwc3_host_suspend(struct dwc3 *dwc)
+{
+ return 0;
+}
+
+static inline int dwc3_host_resume(struct dwc3 *dwc)
+{
+ return 0;
+}
+#endif
+
#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index ed82464..541d27c 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -19,6 +19,9 @@

#include "core.h"

+#define DWC3_HOST_SUSPEND_COUNT 100
+#define DWC3_HOST_SUSPEND_TIMEOUT 100
+
static int dwc3_host_get_irq(struct dwc3 *dwc)
{
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
@@ -130,3 +133,53 @@ void dwc3_host_exit(struct dwc3 *dwc)
dev_name(&dwc->xhci->dev));
platform_device_unregister(dwc->xhci);
}
+
+#ifdef CONFIG_USB_DWC3_HOST_SUSPEND
+int dwc3_host_suspend(struct dwc3 *dwc)
+{
+ struct device *xhci = &dwc->xhci->dev;
+ int ret, cnt = DWC3_HOST_SUSPEND_COUNT;
+
+ /*
+ * We need make sure the children of the xHCI device had been into
+ * suspend state, or we will suspend xHCI device failed.
+ */
+ while (!pm_children_suspended(xhci) && --cnt > 0)
+ msleep(DWC3_HOST_SUSPEND_TIMEOUT);
+
+ if (cnt <= 0) {
+ dev_err(xhci, "failed to suspend xHCI children device\n");
+ return -EBUSY;
+ }
+
+ /*
+ * If the xHCI device had been into suspend state, thus just return.
+ */
+ if (pm_runtime_suspended(xhci))
+ return 0;
+
+ /* Suspend the xHCI device synchronously. */
+ ret = pm_runtime_put_sync(xhci);
+ if (ret) {
+ dev_err(xhci, "failed to suspend xHCI device\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int dwc3_host_resume(struct dwc3 *dwc)
+{
+ struct device *xhci = &dwc->xhci->dev;
+ int ret;
+
+ /* Resume the xHCI device synchronously. */
+ ret = pm_runtime_get_sync(xhci);
+ if (ret) {
+ dev_err(xhci, "failed to resume xHCI device\n");
+ return ret;
+ }
+
+ return 0;
+}
+#endif
--
1.7.9.5

2016-11-18 13:14:47

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 2/2] usb: dwc3: core: Support the dwc3 host suspend/resume

Hi Baolin,

[auto build test ERROR on next-20161117]
[cannot apply to balbi-usb/next usb/usb-testing v4.9-rc5 v4.9-rc4 v4.9-rc3 v4.9-rc5]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Baolin-Wang/usb-host-plat-Enable-xhci-plat-runtime-PM/20161118-202029
config: i386-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

drivers/usb/dwc3/host.c: In function 'dwc3_host_suspend':
>> drivers/usb/dwc3/host.c:157:10: error: implicit declaration of function 'pm_children_suspended' [-Werror=implicit-function-declaration]
while (!pm_children_suspended(xhci) && --cnt > 0)
^~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors

vim +/pm_children_suspended +157 drivers/usb/dwc3/host.c

151 int ret, cnt = DWC3_HOST_SUSPEND_COUNT;
152
153 /*
154 * We need make sure the children of the xHCI device had been into
155 * suspend state, or we will suspend xHCI device failed.
156 */
> 157 while (!pm_children_suspended(xhci) && --cnt > 0)
158 msleep(DWC3_HOST_SUSPEND_TIMEOUT);
159
160 if (cnt <= 0) {

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.46 kB)
.config.gz (56.14 kB)
Download all attachments

2016-11-21 06:22:14

by Baolin Wang

[permalink] [raw]
Subject: Re: [PATCH 2/2] usb: dwc3: core: Support the dwc3 host suspend/resume

On 18 November 2016 at 21:14, kbuild test robot <[email protected]> wrote:
> Hi Baolin,
>
> [auto build test ERROR on next-20161117]
> [cannot apply to balbi-usb/next usb/usb-testing v4.9-rc5 v4.9-rc4 v4.9-rc3 v4.9-rc5]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Baolin-Wang/usb-host-plat-Enable-xhci-plat-runtime-PM/20161118-202029
> config: i386-allmodconfig (attached as .config)
> compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386
>
> All errors (new ones prefixed by >>):
>
> drivers/usb/dwc3/host.c: In function 'dwc3_host_suspend':
>>> drivers/usb/dwc3/host.c:157:10: error: implicit declaration of function 'pm_children_suspended' [-Werror=implicit-function-declaration]
> while (!pm_children_suspended(xhci) && --cnt > 0)
> ^~~~~~~~~~~~~~~~~~~~~
> cc1: some warnings being treated as errors
>
> vim +/pm_children_suspended +157 drivers/usb/dwc3/host.c
>
> 151 int ret, cnt = DWC3_HOST_SUSPEND_COUNT;
> 152
> 153 /*
> 154 * We need make sure the children of the xHCI device had been into
> 155 * suspend state, or we will suspend xHCI device failed.
> 156 */
> > 157 while (!pm_children_suspended(xhci) && --cnt > 0)
> 158 msleep(DWC3_HOST_SUSPEND_TIMEOUT);
> 159
> 160 if (cnt <= 0) {

I will send out new patch to fix this building error.

--
Baolin.wang
Best Regards