2018-09-05 11:42:00

by Amelie Delaunay

[permalink] [raw]
Subject: [PATCH 0/4] usb: dwc2: fix host mode external vbus supply management

This patchset fixes and improves host mode external vbus supply management,
mainly around suspend/resume use cases. It also avoid 'vbus regulator"
to be requested lots of times upon each call to dwc2_vbus_supply_init(),
especially when pm runtime is enabled.

Fabrice Gasnier (4):
usb: dwc2: get optional vbus-supply regulator once
usb: dwc2: fix a race with external vbus supply
usb: dwc2: fix call to vbus supply exit routine, call it unlocked
usb: dwc2: fix unbalanced use of external vbus-supply

drivers/usb/dwc2/hcd.c | 45 ++++++++++++++++++++++++++++++++++-----------
drivers/usb/dwc2/platform.c | 8 ++++++++
2 files changed, 42 insertions(+), 11 deletions(-)

--
2.7.4



2018-09-05 11:42:00

by Amelie Delaunay

[permalink] [raw]
Subject: [PATCH 3/4] usb: dwc2: fix call to vbus supply exit routine, call it unlocked

From: Fabrice Gasnier <[email protected]>

dwc2_vbus_supply_exit() may call regulator_disable(). It shouldn't be
called with interrupts disabled as it might sleep.
This is seen with DEBUG_ATOMIC_SLEEP=y.

Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external
vbus supply")

Signed-off-by: Fabrice Gasnier <[email protected]>
Signed-off-by: Amelie Delaunay <[email protected]>
---
drivers/usb/dwc2/hcd.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index bb72517..e8a480e 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4484,7 +4484,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
hprt0 |= HPRT0_SUSP;
hprt0 &= ~HPRT0_PWR;
dwc2_writel(hsotg, hprt0, HPRT0);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_vbus_supply_exit(hsotg);
+ spin_lock_irqsave(&hsotg->lock, flags);
}

/* Enter partial_power_down */
--
2.7.4


2018-09-05 11:42:00

by Amelie Delaunay

[permalink] [raw]
Subject: [PATCH 2/4] usb: dwc2: fix a race with external vbus supply

From: Fabrice Gasnier <[email protected]>

There's a race with root hub resume, when using external vbus supply.
Root hub gets resumed, but runtime pm autosuspend runs as external vbus
supply isn't enabled. So, host never exit from power down properly.
Initialize vbus external supply before, rater that after hub resume.

Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external
vbus supply")

Signed-off-by: Fabrice Gasnier <[email protected]>
Signed-off-by: Amelie Delaunay <[email protected]>
---
drivers/usb/dwc2/hcd.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index c205cfa..bb72517 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4387,6 +4387,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
struct usb_bus *bus = hcd_to_bus(hcd);
unsigned long flags;
+ int ret;

dev_dbg(hsotg->dev, "DWC OTG HCD START\n");

@@ -4402,6 +4403,13 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)

dwc2_hcd_reinit(hsotg);

+ /* enable external vbus supply before resuming root hub */
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ ret = dwc2_vbus_supply_init(hsotg);
+ if (ret)
+ return ret;
+ spin_lock_irqsave(&hsotg->lock, flags);
+
/* Initialize and connect root hub if one is not already attached */
if (bus->root_hub) {
dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
@@ -4411,7 +4419,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)

spin_unlock_irqrestore(&hsotg->lock, flags);

- return dwc2_vbus_supply_init(hsotg);
+ return 0;
}

/*
--
2.7.4


2018-09-05 11:42:07

by Amelie Delaunay

[permalink] [raw]
Subject: [PATCH 4/4] usb: dwc2: fix unbalanced use of external vbus-supply

From: Fabrice Gasnier <[email protected]>

When using external vbus supply regulator, it should be enabled
synchronously with PWR bit in HPRT register. This also fixes
unbalanced use of this optional regulator (This can be reproduced
easily when unbinding the driver).

Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external
vbus supply")

Signed-off-by: Fabrice Gasnier <[email protected]>
Signed-off-by: Amelie Delaunay <[email protected]>
---
drivers/usb/dwc2/hcd.c | 33 ++++++++++++++++++++++++++-------
1 file changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index e8a480e..8efbb45 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3558,6 +3558,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
u32 port_status;
u32 speed;
u32 pcgctl;
+ u32 pwr;

switch (typereq) {
case ClearHubFeature:
@@ -3606,8 +3607,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_POWER\n");
hprt0 = dwc2_read_hprt0(hsotg);
+ pwr = hprt0 & HPRT0_PWR;
hprt0 &= ~HPRT0_PWR;
dwc2_writel(hsotg, hprt0, HPRT0);
+ if (pwr)
+ dwc2_vbus_supply_exit(hsotg);
break;

case USB_PORT_FEAT_INDICATOR:
@@ -3817,8 +3821,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_POWER\n");
hprt0 = dwc2_read_hprt0(hsotg);
+ pwr = hprt0 & HPRT0_PWR;
hprt0 |= HPRT0_PWR;
dwc2_writel(hsotg, hprt0, HPRT0);
+ if (!pwr)
+ dwc2_vbus_supply_init(hsotg);
break;

case USB_PORT_FEAT_RESET:
@@ -3835,6 +3842,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dwc2_writel(hsotg, 0, PCGCTL);

hprt0 = dwc2_read_hprt0(hsotg);
+ pwr = hprt0 & HPRT0_PWR;
/* Clear suspend bit if resetting from suspend state */
hprt0 &= ~HPRT0_SUSP;

@@ -3848,6 +3856,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
dev_dbg(hsotg->dev,
"In host mode, hprt0=%08x\n", hprt0);
dwc2_writel(hsotg, hprt0, HPRT0);
+ if (!pwr)
+ dwc2_vbus_supply_init(hsotg);
}

/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
@@ -4387,6 +4397,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
struct usb_bus *bus = hcd_to_bus(hcd);
unsigned long flags;
+ u32 hprt0;
int ret;

dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
@@ -4403,12 +4414,16 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)

dwc2_hcd_reinit(hsotg);

- /* enable external vbus supply before resuming root hub */
- spin_unlock_irqrestore(&hsotg->lock, flags);
- ret = dwc2_vbus_supply_init(hsotg);
- if (ret)
- return ret;
- spin_lock_irqsave(&hsotg->lock, flags);
+ hprt0 = dwc2_read_hprt0(hsotg);
+ /* Has vbus power been turned on in dwc2_core_host_init ? */
+ if (hprt0 & HPRT0_PWR) {
+ /* Enable external vbus supply before resuming root hub */
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ ret = dwc2_vbus_supply_init(hsotg);
+ if (ret)
+ return ret;
+ spin_lock_irqsave(&hsotg->lock, flags);
+ }

/* Initialize and connect root hub if one is not already attached */
if (bus->root_hub) {
@@ -4430,6 +4445,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
unsigned long flags;
+ u32 hprt0;

/* Turn off all host-specific interrupts */
dwc2_disable_host_interrupts(hsotg);
@@ -4438,6 +4454,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
synchronize_irq(hcd->irq);

spin_lock_irqsave(&hsotg->lock, flags);
+ hprt0 = dwc2_read_hprt0(hsotg);
/* Ensure hcd is disconnected */
dwc2_hcd_disconnect(hsotg, true);
dwc2_hcd_stop(hsotg);
@@ -4446,7 +4463,9 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
spin_unlock_irqrestore(&hsotg->lock, flags);

- dwc2_vbus_supply_exit(hsotg);
+ /* keep balanced supply init/exit by checking HPRT0_PWR */
+ if (hprt0 & HPRT0_PWR)
+ dwc2_vbus_supply_exit(hsotg);

usleep_range(1000, 3000);
}
--
2.7.4


2018-09-05 11:42:27

by Amelie Delaunay

[permalink] [raw]
Subject: [PATCH 1/4] usb: dwc2: get optional vbus-supply regulator once

From: Fabrice Gasnier <[email protected]>

Move devm_regulator_get_optional() call to probe routine. This avoids
'vbus-supply' regulator to be requested lots of times, upon each call
to dwc2_vbus_supply_init(), e.g. like with runtime pm.

Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external
vbus supply")

Signed-off-by: Fabrice Gasnier <[email protected]>
Signed-off-by: Amelie Delaunay <[email protected]>
---
drivers/usb/dwc2/hcd.c | 12 +++---------
drivers/usb/dwc2/platform.c | 8 ++++++++
2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 2bd6e6b..c205cfa 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -358,16 +358,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)

static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
{
- int ret;
-
- hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
- if (IS_ERR(hsotg->vbus_supply)) {
- ret = PTR_ERR(hsotg->vbus_supply);
- hsotg->vbus_supply = NULL;
- return ret == -ENODEV ? 0 : ret;
- }
+ if (hsotg->vbus_supply)
+ return regulator_enable(hsotg->vbus_supply);

- return regulator_enable(hsotg->vbus_supply);
+ return 0;
}

static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 9a53a58..957e342 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -434,6 +434,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
return retval;

+ hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
+ if (IS_ERR(hsotg->vbus_supply)) {
+ retval = PTR_ERR(hsotg->vbus_supply);
+ hsotg->vbus_supply = NULL;
+ if (retval != -ENODEV)
+ return retval;
+ }
+
retval = dwc2_lowlevel_hw_enable(hsotg);
if (retval)
return retval;
--
2.7.4


2018-09-10 10:20:09

by Artur Petrosyan

[permalink] [raw]
Subject: Re: [PATCH 0/4] usb: dwc2: fix host mode external vbus supply management

Hi,

On 9/5/2018 15:41, Amelie Delaunay wrote:
> This patchset fixes and improves host mode external vbus supply management,
> mainly around suspend/resume use cases. It also avoid 'vbus regulator"
> to be requested lots of times upon each call to dwc2_vbus_supply_init(),
> especially when pm runtime is enabled.
>
> Fabrice Gasnier (4):
> usb: dwc2: get optional vbus-supply regulator once
> usb: dwc2: fix a race with external vbus supply
> usb: dwc2: fix call to vbus supply exit routine, call it unlocked
> usb: dwc2: fix unbalanced use of external vbus-supply
>
> drivers/usb/dwc2/hcd.c | 45 ++++++++++++++++++++++++++++++++++-----------
> drivers/usb/dwc2/platform.c | 8 ++++++++
> 2 files changed, 42 insertions(+), 11 deletions(-)
>
Tested-by: Artur Petrosyan <[email protected]>

The patchset has been tested on Synopsys HAPS-DX platform.

Thanks,
Artur

2018-09-13 06:24:00

by Minas Harutyunyan

[permalink] [raw]
Subject: Re: [PATCH 0/4] usb: dwc2: fix host mode external vbus supply management

On 9/5/2018 3:40 PM, Amelie Delaunay wrote:
> This patchset fixes and improves host mode external vbus supply management,
> mainly around suspend/resume use cases. It also avoid 'vbus regulator"
> to be requested lots of times upon each call to dwc2_vbus_supply_init(),
> especially when pm runtime is enabled.
>
> Fabrice Gasnier (4):
> usb: dwc2: get optional vbus-supply regulator once
> usb: dwc2: fix a race with external vbus supply
> usb: dwc2: fix call to vbus supply exit routine, call it unlocked
> usb: dwc2: fix unbalanced use of external vbus-supply
>
> drivers/usb/dwc2/hcd.c | 45 ++++++++++++++++++++++++++++++++++-----------
> drivers/usb/dwc2/platform.c | 8 ++++++++
> 2 files changed, 42 insertions(+), 11 deletions(-)
>
Tested-by: Artur Petrosyan <[email protected]>
Acked-by: Minas Harutyunyan <[email protected]>