diff mbox series

[v15,3/6] usb: dwc3: core: Host wake up support from system suspend

Message ID 1651740973-7944-4-git-send-email-quic_kriskura@quicinc.com (mailing list archive)
State Superseded
Headers show
Series USB DWC3 host wake up support from system suspend | expand

Commit Message

Krishna Kurapati May 5, 2022, 8:56 a.m. UTC
From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>

During suspend read the status of all port and set hs phy mode
based on current speed. Use this hs phy mode to configure wakeup
interrupts in qcom glue driver.

Check wakeup-source property for dwc3 core node to set the
wakeup capability. Drop the device_init_wakeup call from
runtime suspend and resume.

Also check during suspend if any wakeup capable devices are
connected to the controller (directly or through hubs), if there
are none set a flag to indicate that the PHY is powered
down during suspend.

Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
---
 drivers/usb/dwc3/core.c | 33 ++++++++++++++++++++-------------
 drivers/usb/dwc3/core.h |  4 ++++
 drivers/usb/dwc3/host.c | 24 ++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 13 deletions(-)

Comments

Matthias Kaehlcke May 5, 2022, 10:48 p.m. UTC | #1
On Thu, May 05, 2022 at 02:26:10PM +0530, Krishna Kurapati wrote:
> From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> 
> During suspend read the status of all port and set hs phy mode
> based on current speed. Use this hs phy mode to configure wakeup
> interrupts in qcom glue driver.
> 
> Check wakeup-source property for dwc3 core node to set the
> wakeup capability. Drop the device_init_wakeup call from
> runtime suspend and resume.
> 
> Also check during suspend if any wakeup capable devices are
> connected to the controller (directly or through hubs), if there
> are none set a flag to indicate that the PHY is powered
> down during suspend.
> 
> Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
> ---
>  drivers/usb/dwc3/core.c | 33 ++++++++++++++++++++-------------
>  drivers/usb/dwc3/core.h |  4 ++++
>  drivers/usb/dwc3/host.c | 24 ++++++++++++++++++++++++
>  3 files changed, 48 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> index 950e238..cf377f5 100644
> --- a/drivers/usb/dwc3/core.c
> +++ b/drivers/usb/dwc3/core.c
> @@ -33,6 +33,7 @@
>  #include <linux/usb/gadget.h>
>  #include <linux/usb/of.h>
>  #include <linux/usb/otg.h>
> +#include <linux/usb/hcd.h>

This is not needed anymore

>  
>  #include "core.h"
>  #include "gadget.h"
> @@ -1787,6 +1788,7 @@ static int dwc3_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, dwc);
>  	dwc3_cache_hwparams(dwc);
> +	device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
>  
>  	spin_lock_init(&dwc->lock);
>  	mutex_init(&dwc->mutex);
> @@ -1936,6 +1938,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
>  {
>  	unsigned long	flags;
>  	u32 reg;
> +	struct usb_hcd  *hcd = platform_get_drvdata(dwc->xhci);

This isn't used anymore, delete it

>  
>  	switch (dwc->current_dr_role) {
>  	case DWC3_GCTL_PRTCAP_DEVICE:
> @@ -1948,10 +1951,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
>  		dwc3_core_exit(dwc);
>  		break;
>  	case DWC3_GCTL_PRTCAP_HOST:
> -		if (!PMSG_IS_AUTO(msg)) {
> -			dwc3_core_exit(dwc);
> -			break;
> -		}
> +		dwc3_check_phy_speed_mode(dwc);
>  
>  		/* Let controller to suspend HSPHY before PHY driver suspends */
>  		if (dwc->dis_u2_susphy_quirk ||
> @@ -1967,6 +1967,16 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
>  
>  		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
>  		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
> +
> +		if (!PMSG_IS_AUTO(msg)) {
> +			if (device_may_wakeup(dwc->dev) &&
> +					device_wakeup_path(dwc->dev)) {

nit: the indentation is odd, align it with device_may_wakeup()?

> +				dwc->phy_power_off = false;
> +			} else {
> +				dwc->phy_power_off = true;
> +				dwc3_core_exit(dwc);

As commented earlier, taking the controller and PHYs completely down causes a
significant power draw in some USB clients. Let's clarify what the specific
benefits are of doing dwc3_core_exit() vs. entering a low power mode.
Krishna Kurapati May 6, 2022, 5:11 a.m. UTC | #2
On 5/6/2022 4:18 AM, Matthias Kaehlcke wrote:
> On Thu, May 05, 2022 at 02:26:10PM +0530, Krishna Kurapati wrote:
>> From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
>>
>> During suspend read the status of all port and set hs phy mode
>> based on current speed. Use this hs phy mode to configure wakeup
>> interrupts in qcom glue driver.
>>
>> Check wakeup-source property for dwc3 core node to set the
>> wakeup capability. Drop the device_init_wakeup call from
>> runtime suspend and resume.
>>
>> Also check during suspend if any wakeup capable devices are
>> connected to the controller (directly or through hubs), if there
>> are none set a flag to indicate that the PHY is powered
>> down during suspend.
>>
>> Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
>> Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
>> ---
>>   drivers/usb/dwc3/core.c | 33 ++++++++++++++++++++-------------
>>   drivers/usb/dwc3/core.h |  4 ++++
>>   drivers/usb/dwc3/host.c | 24 ++++++++++++++++++++++++
>>   3 files changed, 48 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
>> index 950e238..cf377f5 100644
>> --- a/drivers/usb/dwc3/core.c
>> +++ b/drivers/usb/dwc3/core.c
>> @@ -33,6 +33,7 @@
>>   #include <linux/usb/gadget.h>
>>   #include <linux/usb/of.h>
>>   #include <linux/usb/otg.h>
>> +#include <linux/usb/hcd.h>
> This is not needed anymore
>
>>   
>>   #include "core.h"
>>   #include "gadget.h"
>> @@ -1787,6 +1788,7 @@ static int dwc3_probe(struct platform_device *pdev)
>>   
>>   	platform_set_drvdata(pdev, dwc);
>>   	dwc3_cache_hwparams(dwc);
>> +	device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
>>   
>>   	spin_lock_init(&dwc->lock);
>>   	mutex_init(&dwc->mutex);
>> @@ -1936,6 +1938,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
>>   {
>>   	unsigned long	flags;
>>   	u32 reg;
>> +	struct usb_hcd  *hcd = platform_get_drvdata(dwc->xhci);
> This isn't used anymore, delete it
My bad, Will fix this in next version.
>>   
>>   	switch (dwc->current_dr_role) {
>>   	case DWC3_GCTL_PRTCAP_DEVICE:
>> @@ -1948,10 +1951,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
>>   		dwc3_core_exit(dwc);
>>   		break;
>>   	case DWC3_GCTL_PRTCAP_HOST:
>> -		if (!PMSG_IS_AUTO(msg)) {
>> -			dwc3_core_exit(dwc);
>> -			break;
>> -		}
>> +		dwc3_check_phy_speed_mode(dwc);
>>   
>>   		/* Let controller to suspend HSPHY before PHY driver suspends */
>>   		if (dwc->dis_u2_susphy_quirk ||
>> @@ -1967,6 +1967,16 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
>>   
>>   		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
>>   		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
>> +
>> +		if (!PMSG_IS_AUTO(msg)) {
>> +			if (device_may_wakeup(dwc->dev) &&
>> +					device_wakeup_path(dwc->dev)) {
> nit: the indentation is odd, align it with device_may_wakeup()?
Sure, Will take care of it.
>> +				dwc->phy_power_off = false;
>> +			} else {
>> +				dwc->phy_power_off = true;
>> +				dwc3_core_exit(dwc);
> As commented earlier, taking the controller and PHYs completely down causes a
> significant power draw in some USB clients. Let's clarify what the specific
> benefits are of doing dwc3_core_exit() vs. entering a low power mode.
Sure, once we come to a conclusion on this, I will refresh the patches.
Pavan Kondeti May 6, 2022, 5:14 a.m. UTC | #3
On Fri, May 06, 2022 at 10:41:01AM +0530, Krishna Kurapati PSSNV wrote:
> 
> On 5/6/2022 4:18 AM, Matthias Kaehlcke wrote:
> >On Thu, May 05, 2022 at 02:26:10PM +0530, Krishna Kurapati wrote:
> >>From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> >>
> >>During suspend read the status of all port and set hs phy mode
> >>based on current speed. Use this hs phy mode to configure wakeup
> >>interrupts in qcom glue driver.
> >>
> >>Check wakeup-source property for dwc3 core node to set the
> >>wakeup capability. Drop the device_init_wakeup call from
> >>runtime suspend and resume.
> >>
> >>Also check during suspend if any wakeup capable devices are
> >>connected to the controller (directly or through hubs), if there
> >>are none set a flag to indicate that the PHY is powered
> >>down during suspend.
> >>
> >>Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> >>Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
> >>---
> >>  drivers/usb/dwc3/core.c | 33 ++++++++++++++++++++-------------
> >>  drivers/usb/dwc3/core.h |  4 ++++
> >>  drivers/usb/dwc3/host.c | 24 ++++++++++++++++++++++++
> >>  3 files changed, 48 insertions(+), 13 deletions(-)
> >>
> >>diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> >>index 950e238..cf377f5 100644
> >>--- a/drivers/usb/dwc3/core.c
> >>+++ b/drivers/usb/dwc3/core.c
> >>@@ -33,6 +33,7 @@
> >>  #include <linux/usb/gadget.h>
> >>  #include <linux/usb/of.h>
> >>  #include <linux/usb/otg.h>
> >>+#include <linux/usb/hcd.h>
> >This is not needed anymore
> >
> >>  #include "core.h"
> >>  #include "gadget.h"
> >>@@ -1787,6 +1788,7 @@ static int dwc3_probe(struct platform_device *pdev)
> >>  	platform_set_drvdata(pdev, dwc);
> >>  	dwc3_cache_hwparams(dwc);
> >>+	device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
> >>  	spin_lock_init(&dwc->lock);
> >>  	mutex_init(&dwc->mutex);
> >>@@ -1936,6 +1938,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> >>  {
> >>  	unsigned long	flags;
> >>  	u32 reg;
> >>+	struct usb_hcd  *hcd = platform_get_drvdata(dwc->xhci);
> >This isn't used anymore, delete it
> My bad, Will fix this in next version.
> >>  	switch (dwc->current_dr_role) {
> >>  	case DWC3_GCTL_PRTCAP_DEVICE:
> >>@@ -1948,10 +1951,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> >>  		dwc3_core_exit(dwc);
> >>  		break;
> >>  	case DWC3_GCTL_PRTCAP_HOST:
> >>-		if (!PMSG_IS_AUTO(msg)) {
> >>-			dwc3_core_exit(dwc);
> >>-			break;
> >>-		}
> >>+		dwc3_check_phy_speed_mode(dwc);
> >>  		/* Let controller to suspend HSPHY before PHY driver suspends */
> >>  		if (dwc->dis_u2_susphy_quirk ||
> >>@@ -1967,6 +1967,16 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> >>  		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
> >>  		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
> >>+
> >>+		if (!PMSG_IS_AUTO(msg)) {
> >>+			if (device_may_wakeup(dwc->dev) &&
> >>+					device_wakeup_path(dwc->dev)) {
> >nit: the indentation is odd, align it with device_may_wakeup()?
> Sure, Will take care of it.
> >>+				dwc->phy_power_off = false;
> >>+			} else {
> >>+				dwc->phy_power_off = true;
> >>+				dwc3_core_exit(dwc);
> >As commented earlier, taking the controller and PHYs completely down causes a
> >significant power draw in some USB clients. Let's clarify what the specific
> >benefits are of doing dwc3_core_exit() vs. entering a low power mode.
> Sure, once we come to a conclusion on this, I will refresh the patches.

I think, Matthias is asking you to clarify in the commit description. we can
even quote Matthias observations.

Thanks,
Pavan
Matthias Kaehlcke May 6, 2022, 3:51 p.m. UTC | #4
On Fri, May 06, 2022 at 10:44:48AM +0530, Pavan Kondeti wrote:
> On Fri, May 06, 2022 at 10:41:01AM +0530, Krishna Kurapati PSSNV wrote:
> > 
> > On 5/6/2022 4:18 AM, Matthias Kaehlcke wrote:
> > >On Thu, May 05, 2022 at 02:26:10PM +0530, Krishna Kurapati wrote:
> > >>From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> > >>
> > >>During suspend read the status of all port and set hs phy mode
> > >>based on current speed. Use this hs phy mode to configure wakeup
> > >>interrupts in qcom glue driver.
> > >>
> > >>Check wakeup-source property for dwc3 core node to set the
> > >>wakeup capability. Drop the device_init_wakeup call from
> > >>runtime suspend and resume.
> > >>
> > >>Also check during suspend if any wakeup capable devices are
> > >>connected to the controller (directly or through hubs), if there
> > >>are none set a flag to indicate that the PHY is powered
> > >>down during suspend.
> > >>
> > >>Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> > >>Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
> > >>---
> > >>  drivers/usb/dwc3/core.c | 33 ++++++++++++++++++++-------------
> > >>  drivers/usb/dwc3/core.h |  4 ++++
> > >>  drivers/usb/dwc3/host.c | 24 ++++++++++++++++++++++++
> > >>  3 files changed, 48 insertions(+), 13 deletions(-)
> > >>
> > >>diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> > >>index 950e238..cf377f5 100644
> > >>--- a/drivers/usb/dwc3/core.c
> > >>+++ b/drivers/usb/dwc3/core.c
> > >>@@ -33,6 +33,7 @@
> > >>  #include <linux/usb/gadget.h>
> > >>  #include <linux/usb/of.h>
> > >>  #include <linux/usb/otg.h>
> > >>+#include <linux/usb/hcd.h>
> > >This is not needed anymore
> > >
> > >>  #include "core.h"
> > >>  #include "gadget.h"
> > >>@@ -1787,6 +1788,7 @@ static int dwc3_probe(struct platform_device *pdev)
> > >>  	platform_set_drvdata(pdev, dwc);
> > >>  	dwc3_cache_hwparams(dwc);
> > >>+	device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
> > >>  	spin_lock_init(&dwc->lock);
> > >>  	mutex_init(&dwc->mutex);
> > >>@@ -1936,6 +1938,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > >>  {
> > >>  	unsigned long	flags;
> > >>  	u32 reg;
> > >>+	struct usb_hcd  *hcd = platform_get_drvdata(dwc->xhci);
> > >This isn't used anymore, delete it
> > My bad, Will fix this in next version.
> > >>  	switch (dwc->current_dr_role) {
> > >>  	case DWC3_GCTL_PRTCAP_DEVICE:
> > >>@@ -1948,10 +1951,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > >>  		dwc3_core_exit(dwc);
> > >>  		break;
> > >>  	case DWC3_GCTL_PRTCAP_HOST:
> > >>-		if (!PMSG_IS_AUTO(msg)) {
> > >>-			dwc3_core_exit(dwc);
> > >>-			break;
> > >>-		}
> > >>+		dwc3_check_phy_speed_mode(dwc);
> > >>  		/* Let controller to suspend HSPHY before PHY driver suspends */
> > >>  		if (dwc->dis_u2_susphy_quirk ||
> > >>@@ -1967,6 +1967,16 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > >>  		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
> > >>  		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
> > >>+
> > >>+		if (!PMSG_IS_AUTO(msg)) {
> > >>+			if (device_may_wakeup(dwc->dev) &&
> > >>+					device_wakeup_path(dwc->dev)) {
> > >nit: the indentation is odd, align it with device_may_wakeup()?
> > Sure, Will take care of it.
> > >>+				dwc->phy_power_off = false;
> > >>+			} else {
> > >>+				dwc->phy_power_off = true;
> > >>+				dwc3_core_exit(dwc);
> > >As commented earlier, taking the controller and PHYs completely down causes a
> > >significant power draw in some USB clients. Let's clarify what the specific
> > >benefits are of doing dwc3_core_exit() vs. entering a low power mode.
> > Sure, once we come to a conclusion on this, I will refresh the patches.
> 
> I think, Matthias is asking you to clarify in the commit description. we can
> even quote Matthias observations.

Actually I would like to have a discussion about the benefits of powering down
the controller and PHYs vs. entering a low power state. Maybe there are good
reasons for powering everything down (e.g. significant power savings), but
as we have seen there are also significant downsides, so let's make sure
we understand both.
Matthias Kaehlcke May 6, 2022, 4:51 p.m. UTC | #5
On Fri, May 06, 2022 at 08:51:22AM -0700, Matthias Kaehlcke wrote:
> On Fri, May 06, 2022 at 10:44:48AM +0530, Pavan Kondeti wrote:
> > On Fri, May 06, 2022 at 10:41:01AM +0530, Krishna Kurapati PSSNV wrote:
> > > 
> > > On 5/6/2022 4:18 AM, Matthias Kaehlcke wrote:
> > > >On Thu, May 05, 2022 at 02:26:10PM +0530, Krishna Kurapati wrote:
> > > >>From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> > > >>
> > > >>During suspend read the status of all port and set hs phy mode
> > > >>based on current speed. Use this hs phy mode to configure wakeup
> > > >>interrupts in qcom glue driver.
> > > >>
> > > >>Check wakeup-source property for dwc3 core node to set the
> > > >>wakeup capability. Drop the device_init_wakeup call from
> > > >>runtime suspend and resume.
> > > >>
> > > >>Also check during suspend if any wakeup capable devices are
> > > >>connected to the controller (directly or through hubs), if there
> > > >>are none set a flag to indicate that the PHY is powered
> > > >>down during suspend.
> > > >>
> > > >>Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
> > > >>Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
> > > >>---
> > > >>  drivers/usb/dwc3/core.c | 33 ++++++++++++++++++++-------------
> > > >>  drivers/usb/dwc3/core.h |  4 ++++
> > > >>  drivers/usb/dwc3/host.c | 24 ++++++++++++++++++++++++
> > > >>  3 files changed, 48 insertions(+), 13 deletions(-)
> > > >>
> > > >>diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
> > > >>index 950e238..cf377f5 100644
> > > >>--- a/drivers/usb/dwc3/core.c
> > > >>+++ b/drivers/usb/dwc3/core.c
> > > >>@@ -33,6 +33,7 @@
> > > >>  #include <linux/usb/gadget.h>
> > > >>  #include <linux/usb/of.h>
> > > >>  #include <linux/usb/otg.h>
> > > >>+#include <linux/usb/hcd.h>
> > > >This is not needed anymore
> > > >
> > > >>  #include "core.h"
> > > >>  #include "gadget.h"
> > > >>@@ -1787,6 +1788,7 @@ static int dwc3_probe(struct platform_device *pdev)
> > > >>  	platform_set_drvdata(pdev, dwc);
> > > >>  	dwc3_cache_hwparams(dwc);
> > > >>+	device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
> > > >>  	spin_lock_init(&dwc->lock);
> > > >>  	mutex_init(&dwc->mutex);
> > > >>@@ -1936,6 +1938,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > > >>  {
> > > >>  	unsigned long	flags;
> > > >>  	u32 reg;
> > > >>+	struct usb_hcd  *hcd = platform_get_drvdata(dwc->xhci);
> > > >This isn't used anymore, delete it
> > > My bad, Will fix this in next version.
> > > >>  	switch (dwc->current_dr_role) {
> > > >>  	case DWC3_GCTL_PRTCAP_DEVICE:
> > > >>@@ -1948,10 +1951,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > > >>  		dwc3_core_exit(dwc);
> > > >>  		break;
> > > >>  	case DWC3_GCTL_PRTCAP_HOST:
> > > >>-		if (!PMSG_IS_AUTO(msg)) {
> > > >>-			dwc3_core_exit(dwc);
> > > >>-			break;
> > > >>-		}
> > > >>+		dwc3_check_phy_speed_mode(dwc);
> > > >>  		/* Let controller to suspend HSPHY before PHY driver suspends */
> > > >>  		if (dwc->dis_u2_susphy_quirk ||
> > > >>@@ -1967,6 +1967,16 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > > >>  		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
> > > >>  		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
> > > >>+
> > > >>+		if (!PMSG_IS_AUTO(msg)) {
> > > >>+			if (device_may_wakeup(dwc->dev) &&
> > > >>+					device_wakeup_path(dwc->dev)) {
> > > >nit: the indentation is odd, align it with device_may_wakeup()?
> > > Sure, Will take care of it.
> > > >>+				dwc->phy_power_off = false;
> > > >>+			} else {
> > > >>+				dwc->phy_power_off = true;
> > > >>+				dwc3_core_exit(dwc);
> > > >As commented earlier, taking the controller and PHYs completely down causes a
> > > >significant power draw in some USB clients. Let's clarify what the specific
> > > >benefits are of doing dwc3_core_exit() vs. entering a low power mode.
> > > Sure, once we come to a conclusion on this, I will refresh the patches.
> > 
> > I think, Matthias is asking you to clarify in the commit description. we can
> > even quote Matthias observations.
> 
> Actually I would like to have a discussion about the benefits of powering down
> the controller and PHYs vs. entering a low power state. Maybe there are good
> reasons for powering everything down (e.g. significant power savings), but
> as we have seen there are also significant downsides, so let's make sure
> we understand both.

I found this, as I commented on the other thread:

  commit c4a5153e87fdf6805f63ff57556260e2554155a5
  Author: Manu Gautam <mgautam@codeaurora.org>
  Date:   Thu Jan 18 16:54:30 2018 +0530

  usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode

  Commit 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during
  host bus-suspend/resume") updated suspend/resume routines to not
  power_off and reinit PHYs/core for host mode.
  It broke platforms that rely on DWC3 core to power_off PHYs to
  enter low power state on system suspend.

  Perform dwc3_core_exit/init only during host mode system_suspend/
  resume to addresses power regression from above mentioned patch
  and also allow USB session to stay connected across
  runtime_suspend/resume in host mode. While at it also replace
  existing checks for HOST only dr_mode with current_dr_role to
  have similar core driver behavior for both Host-only and DRD+Host
  configurations.

  Fixes: 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
  Reviewed-by: Roger Quadros <rogerq@ti.com>
  Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
  Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>


So apparently powering off the core and PHYs is needed on some
platforms.

Let's move forward with the core/PHYs off for now and try to
come up with a solution (e.g. a DT property that indicates
that the core/PHYs can remain powererd) in a separate
patch/series.
Alan Stern May 6, 2022, 6:18 p.m. UTC | #6
[CC: list drastically reduced]

On Fri, May 06, 2022 at 09:51:46AM -0700, Matthias Kaehlcke wrote:
> I found this, as I commented on the other thread:
> 
>   commit c4a5153e87fdf6805f63ff57556260e2554155a5
>   Author: Manu Gautam <mgautam@codeaurora.org>
>   Date:   Thu Jan 18 16:54:30 2018 +0530
> 
>   usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode
> 
>   Commit 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during
>   host bus-suspend/resume") updated suspend/resume routines to not
>   power_off and reinit PHYs/core for host mode.
>   It broke platforms that rely on DWC3 core to power_off PHYs to
>   enter low power state on system suspend.
> 
>   Perform dwc3_core_exit/init only during host mode system_suspend/
>   resume to addresses power regression from above mentioned patch
>   and also allow USB session to stay connected across
>   runtime_suspend/resume in host mode. While at it also replace
>   existing checks for HOST only dr_mode with current_dr_role to
>   have similar core driver behavior for both Host-only and DRD+Host
>   configurations.
> 
>   Fixes: 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
>   Reviewed-by: Roger Quadros <rogerq@ti.com>
>   Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
>   Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
> 
> 
> So apparently powering off the core and PHYs is needed on some
> platforms.
> 
> Let's move forward with the core/PHYs off for now and try to
> come up with a solution (e.g. a DT property that indicates
> that the core/PHYs can remain powererd) in a separate
> patch/series.

Isn't it true that if you power off the PHY, the controller will be 
unable to detect resume requests from attached devices? Similarly, won't 
the controller will be unable to detect plug and unplug events on the 
root hub?

Doesn't this mean that if wakeup is enabled on the root hub or any of 
the devices downstream from a root-hub port, the port's PHY must remain 
powered during suspend?

Or am I totally off-base?

Alan Stern
Matthias Kaehlcke May 6, 2022, 6:46 p.m. UTC | #7
On Fri, May 06, 2022 at 02:18:06PM -0400, Alan Stern wrote:
> [CC: list drastically reduced]
> 
> On Fri, May 06, 2022 at 09:51:46AM -0700, Matthias Kaehlcke wrote:
> > I found this, as I commented on the other thread:
> > 
> >   commit c4a5153e87fdf6805f63ff57556260e2554155a5
> >   Author: Manu Gautam <mgautam@codeaurora.org>
> >   Date:   Thu Jan 18 16:54:30 2018 +0530
> > 
> >   usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode
> > 
> >   Commit 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during
> >   host bus-suspend/resume") updated suspend/resume routines to not
> >   power_off and reinit PHYs/core for host mode.
> >   It broke platforms that rely on DWC3 core to power_off PHYs to
> >   enter low power state on system suspend.
> > 
> >   Perform dwc3_core_exit/init only during host mode system_suspend/
> >   resume to addresses power regression from above mentioned patch
> >   and also allow USB session to stay connected across
> >   runtime_suspend/resume in host mode. While at it also replace
> >   existing checks for HOST only dr_mode with current_dr_role to
> >   have similar core driver behavior for both Host-only and DRD+Host
> >   configurations.
> > 
> >   Fixes: 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
> >   Reviewed-by: Roger Quadros <rogerq@ti.com>
> >   Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
> >   Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
> > 
> > 
> > So apparently powering off the core and PHYs is needed on some
> > platforms.
> > 
> > Let's move forward with the core/PHYs off for now and try to
> > come up with a solution (e.g. a DT property that indicates
> > that the core/PHYs can remain powererd) in a separate
> > patch/series.
> 
> Isn't it true that if you power off the PHY, the controller will be 
> unable to detect resume requests from attached devices? Similarly, won't 
> the controller will be unable to detect plug and unplug events on the 
> root hub?
> 
> Doesn't this mean that if wakeup is enabled on the root hub or any of 
> the devices downstream from a root-hub port, the port's PHY must remain 
> powered during suspend?

Yes.

Currently the core/PHYs are always powered off during suspend in host mode:

static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
{
	...

	switch (dwc->current_dr_role) {
	case DWC3_GCTL_PRTCAP_HOST:
		if (!PMSG_IS_AUTO(msg)) {
			dwc3_core_exit(dwc);
			break;
		}

	...
}

With that I would expect wakeup to be broken for all dwc3. I'm a bit confused
though, since dwc3-imx8mp.c seems to support wakeup and the driver landed
after the above patch ...

This series intends to change the above code to something like this:

	if (!PMSG_IS_AUTO(msg)) {
	       if (device_may_wakeup(dwc->dev) &&
	                       device_wakeup_path(dwc->dev)) {
	               dwc->phy_power_off = false;
	       } else {
	               dwc->phy_power_off = true;
	               dwc3_core_exit(dwc);
	       }
	}

i.e. the core/PHYs would only be powered down if wakeup is disabled or no
wakeup capable devices are connected. With that plug/unplug events still
wouldn't be detected.
Alan Stern May 6, 2022, 8:30 p.m. UTC | #8
On Fri, May 06, 2022 at 11:46:06AM -0700, Matthias Kaehlcke wrote:
> On Fri, May 06, 2022 at 02:18:06PM -0400, Alan Stern wrote:
> > [CC: list drastically reduced]
> > 
> > On Fri, May 06, 2022 at 09:51:46AM -0700, Matthias Kaehlcke wrote:
> > > I found this, as I commented on the other thread:
> > > 
> > >   commit c4a5153e87fdf6805f63ff57556260e2554155a5
> > >   Author: Manu Gautam <mgautam@codeaurora.org>
> > >   Date:   Thu Jan 18 16:54:30 2018 +0530
> > > 
> > >   usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode
> > > 
> > >   Commit 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during
> > >   host bus-suspend/resume") updated suspend/resume routines to not
> > >   power_off and reinit PHYs/core for host mode.
> > >   It broke platforms that rely on DWC3 core to power_off PHYs to
> > >   enter low power state on system suspend.
> > > 
> > >   Perform dwc3_core_exit/init only during host mode system_suspend/
> > >   resume to addresses power regression from above mentioned patch
> > >   and also allow USB session to stay connected across
> > >   runtime_suspend/resume in host mode. While at it also replace
> > >   existing checks for HOST only dr_mode with current_dr_role to
> > >   have similar core driver behavior for both Host-only and DRD+Host
> > >   configurations.
> > > 
> > >   Fixes: 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
> > >   Reviewed-by: Roger Quadros <rogerq@ti.com>
> > >   Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
> > >   Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
> > > 
> > > 
> > > So apparently powering off the core and PHYs is needed on some
> > > platforms.
> > > 
> > > Let's move forward with the core/PHYs off for now and try to
> > > come up with a solution (e.g. a DT property that indicates
> > > that the core/PHYs can remain powererd) in a separate
> > > patch/series.
> > 
> > Isn't it true that if you power off the PHY, the controller will be 
> > unable to detect resume requests from attached devices? Similarly, won't 
> > the controller will be unable to detect plug and unplug events on the 
> > root hub?
> > 
> > Doesn't this mean that if wakeup is enabled on the root hub or any of 
> > the devices downstream from a root-hub port, the port's PHY must remain 
> > powered during suspend?
> 
> Yes.
> 
> Currently the core/PHYs are always powered off during suspend in host mode:
> 
> static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> {
> 	...
> 
> 	switch (dwc->current_dr_role) {
> 	case DWC3_GCTL_PRTCAP_HOST:
> 		if (!PMSG_IS_AUTO(msg)) {
> 			dwc3_core_exit(dwc);
> 			break;
> 		}
> 
> 	...
> }
> 
> With that I would expect wakeup to be broken for all dwc3. I'm a bit confused
> though, since dwc3-imx8mp.c seems to support wakeup and the driver landed
> after the above patch ...
> 
> This series intends to change the above code to something like this:
> 
> 	if (!PMSG_IS_AUTO(msg)) {
> 	       if (device_may_wakeup(dwc->dev) &&
> 	                       device_wakeup_path(dwc->dev)) {
> 	               dwc->phy_power_off = false;
> 	       } else {
> 	               dwc->phy_power_off = true;
> 	               dwc3_core_exit(dwc);
> 	       }
> 	}

> i.e. the core/PHYs would only be powered down if wakeup is disabled or no
> wakeup capable devices are connected. With that plug/unplug events still
> wouldn't be detected.

Indeed.  Shouldn't the "&&" and "||"?  That is, don't you want to leave 
the core and PHY powered if wakeup is enabled for the root hub or for 
any devices beneath it?

It would be simpler to leave the core and PHY powered whenever wakeup is 
enabled for the controller itself, regardless of the status of the root 
hub and downstream devices.  Users might not like this so much if the 
default setting is to enable wakeup for the controller always.  Still, 
it's an easy solution.

Alan Stern
Pavan Kondeti May 9, 2022, 3:32 a.m. UTC | #9
On Fri, May 06, 2022 at 04:30:33PM -0400, Alan Stern wrote:
> On Fri, May 06, 2022 at 11:46:06AM -0700, Matthias Kaehlcke wrote:
> > On Fri, May 06, 2022 at 02:18:06PM -0400, Alan Stern wrote:
> > > [CC: list drastically reduced]
> > > 
> > > On Fri, May 06, 2022 at 09:51:46AM -0700, Matthias Kaehlcke wrote:
> > > > I found this, as I commented on the other thread:
> > > > 
> > > >   commit c4a5153e87fdf6805f63ff57556260e2554155a5
> > > >   Author: Manu Gautam <mgautam@codeaurora.org>
> > > >   Date:   Thu Jan 18 16:54:30 2018 +0530
> > > > 
> > > >   usb: dwc3: core: Power-off core/PHYs on system_suspend in host mode
> > > > 
> > > >   Commit 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during
> > > >   host bus-suspend/resume") updated suspend/resume routines to not
> > > >   power_off and reinit PHYs/core for host mode.
> > > >   It broke platforms that rely on DWC3 core to power_off PHYs to
> > > >   enter low power state on system suspend.
> > > > 
> > > >   Perform dwc3_core_exit/init only during host mode system_suspend/
> > > >   resume to addresses power regression from above mentioned patch
> > > >   and also allow USB session to stay connected across
> > > >   runtime_suspend/resume in host mode. While at it also replace
> > > >   existing checks for HOST only dr_mode with current_dr_role to
> > > >   have similar core driver behavior for both Host-only and DRD+Host
> > > >   configurations.
> > > > 
> > > >   Fixes: 689bf72c6e0d ("usb: dwc3: Don't reinitialize core during host bus-suspend/resume")
> > > >   Reviewed-by: Roger Quadros <rogerq@ti.com>
> > > >   Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
> > > >   Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
> > > > 
> > > > 
> > > > So apparently powering off the core and PHYs is needed on some
> > > > platforms.
> > > > 
> > > > Let's move forward with the core/PHYs off for now and try to
> > > > come up with a solution (e.g. a DT property that indicates
> > > > that the core/PHYs can remain powererd) in a separate
> > > > patch/series.
> > > 
> > > Isn't it true that if you power off the PHY, the controller will be 
> > > unable to detect resume requests from attached devices? Similarly, won't 
> > > the controller will be unable to detect plug and unplug events on the 
> > > root hub?
> > > 
> > > Doesn't this mean that if wakeup is enabled on the root hub or any of 
> > > the devices downstream from a root-hub port, the port's PHY must remain 
> > > powered during suspend?
> > 
> > Yes.
> > 
> > Currently the core/PHYs are always powered off during suspend in host mode:
> > 
> > static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > {
> > 	...
> > 
> > 	switch (dwc->current_dr_role) {
> > 	case DWC3_GCTL_PRTCAP_HOST:
> > 		if (!PMSG_IS_AUTO(msg)) {
> > 			dwc3_core_exit(dwc);
> > 			break;
> > 		}
> > 
> > 	...
> > }
> > 
> > With that I would expect wakeup to be broken for all dwc3. I'm a bit confused
> > though, since dwc3-imx8mp.c seems to support wakeup and the driver landed
> > after the above patch ...
> > 
> > This series intends to change the above code to something like this:
> > 
> > 	if (!PMSG_IS_AUTO(msg)) {
> > 	       if (device_may_wakeup(dwc->dev) &&
> > 	                       device_wakeup_path(dwc->dev)) {
> > 	               dwc->phy_power_off = false;
> > 	       } else {
> > 	               dwc->phy_power_off = true;
> > 	               dwc3_core_exit(dwc);
> > 	       }
> > 	}
> 
> > i.e. the core/PHYs would only be powered down if wakeup is disabled or no
> > wakeup capable devices are connected. With that plug/unplug events still
> > wouldn't be detected.
> 
> Indeed.  Shouldn't the "&&" and "||"?  That is, don't you want to leave 
> the core and PHY powered if wakeup is enabled for the root hub or for 
> any devices beneath it?
> 
> It would be simpler to leave the core and PHY powered whenever wakeup is 
> enabled for the controller itself, regardless of the status of the root 
> hub and downstream devices.  Users might not like this so much if the 
> default setting is to enable wakeup for the controller always.  Still, 
> it's an easy solution.
> 
At this point it is not clear if all boards that has DWC3 controller can
support wakeup capability or not. Thats why we have introduced a wakeup device
tree property based on which we advertise our wakeup capability.

device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node,
"wakeup-source"));

Hence the && condition to make sure that we support wakeup and our children
needs it.

Thanks,
Pavan
Alan Stern May 9, 2022, 2:08 p.m. UTC | #10
On Mon, May 09, 2022 at 09:02:38AM +0530, Pavan Kondeti wrote:
> On Fri, May 06, 2022 at 04:30:33PM -0400, Alan Stern wrote:
> > On Fri, May 06, 2022 at 11:46:06AM -0700, Matthias Kaehlcke wrote:
> > > Currently the core/PHYs are always powered off during suspend in host mode:
> > > 
> > > static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > > {
> > > 	...
> > > 
> > > 	switch (dwc->current_dr_role) {
> > > 	case DWC3_GCTL_PRTCAP_HOST:
> > > 		if (!PMSG_IS_AUTO(msg)) {
> > > 			dwc3_core_exit(dwc);
> > > 			break;
> > > 		}
> > > 
> > > 	...
> > > }
> > > 
> > > With that I would expect wakeup to be broken for all dwc3. I'm a bit confused
> > > though, since dwc3-imx8mp.c seems to support wakeup and the driver landed
> > > after the above patch ...
> > > 
> > > This series intends to change the above code to something like this:
> > > 
> > > 	if (!PMSG_IS_AUTO(msg)) {
> > > 	       if (device_may_wakeup(dwc->dev) &&
> > > 	                       device_wakeup_path(dwc->dev)) {
> > > 	               dwc->phy_power_off = false;
> > > 	       } else {
> > > 	               dwc->phy_power_off = true;
> > > 	               dwc3_core_exit(dwc);
> > > 	       }
> > > 	}
> > 
> > > i.e. the core/PHYs would only be powered down if wakeup is disabled or no
> > > wakeup capable devices are connected. With that plug/unplug events still
> > > wouldn't be detected.
> > 
> > Indeed.  Shouldn't the "&&" and "||"?  That is, don't you want to leave 
> > the core and PHY powered if wakeup is enabled for the root hub or for 
> > any devices beneath it?
> > 
> > It would be simpler to leave the core and PHY powered whenever wakeup is 
> > enabled for the controller itself, regardless of the status of the root 
> > hub and downstream devices.  Users might not like this so much if the 
> > default setting is to enable wakeup for the controller always.  Still, 
> > it's an easy solution.
> > 
> At this point it is not clear if all boards that has DWC3 controller can
> support wakeup capability or not. Thats why we have introduced a wakeup device
> tree property based on which we advertise our wakeup capability.
> 
> device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node,
> "wakeup-source"));
> 
> Hence the && condition to make sure that we support wakeup and our children
> needs it.

Oh, I see.  I misread the code above, thinking that dwc->dev referred to 
the root hub.  It doesn't; it refers to the controller.  Sorry for the 
mistake.

BTW, if there's any trouble with getting device_wakeup_path() to work 
the way you want, you could consider instead calling 
usb_wakeup_enabled_descendants() on the root hub.  This function returns 
a count of the number of wakeup-enabled USB devices at or below the 
device you pass to it.

Alan Stern
Pavan Kondeti May 9, 2022, 2:23 p.m. UTC | #11
On Mon, May 09, 2022 at 10:08:41AM -0400, Alan Stern wrote:
> On Mon, May 09, 2022 at 09:02:38AM +0530, Pavan Kondeti wrote:
> > On Fri, May 06, 2022 at 04:30:33PM -0400, Alan Stern wrote:
> > > On Fri, May 06, 2022 at 11:46:06AM -0700, Matthias Kaehlcke wrote:
> > > > Currently the core/PHYs are always powered off during suspend in host mode:
> > > > 
> > > > static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > > > {
> > > > 	...
> > > > 
> > > > 	switch (dwc->current_dr_role) {
> > > > 	case DWC3_GCTL_PRTCAP_HOST:
> > > > 		if (!PMSG_IS_AUTO(msg)) {
> > > > 			dwc3_core_exit(dwc);
> > > > 			break;
> > > > 		}
> > > > 
> > > > 	...
> > > > }
> > > > 
> > > > With that I would expect wakeup to be broken for all dwc3. I'm a bit confused
> > > > though, since dwc3-imx8mp.c seems to support wakeup and the driver landed
> > > > after the above patch ...
> > > > 
> > > > This series intends to change the above code to something like this:
> > > > 
> > > > 	if (!PMSG_IS_AUTO(msg)) {
> > > > 	       if (device_may_wakeup(dwc->dev) &&
> > > > 	                       device_wakeup_path(dwc->dev)) {
> > > > 	               dwc->phy_power_off = false;
> > > > 	       } else {
> > > > 	               dwc->phy_power_off = true;
> > > > 	               dwc3_core_exit(dwc);
> > > > 	       }
> > > > 	}
> > > 
> > > > i.e. the core/PHYs would only be powered down if wakeup is disabled or no
> > > > wakeup capable devices are connected. With that plug/unplug events still
> > > > wouldn't be detected.
> > > 
> > > Indeed.  Shouldn't the "&&" and "||"?  That is, don't you want to leave 
> > > the core and PHY powered if wakeup is enabled for the root hub or for 
> > > any devices beneath it?
> > > 
> > > It would be simpler to leave the core and PHY powered whenever wakeup is 
> > > enabled for the controller itself, regardless of the status of the root 
> > > hub and downstream devices.  Users might not like this so much if the 
> > > default setting is to enable wakeup for the controller always.  Still, 
> > > it's an easy solution.
> > > 
> > At this point it is not clear if all boards that has DWC3 controller can
> > support wakeup capability or not. Thats why we have introduced a wakeup device
> > tree property based on which we advertise our wakeup capability.
> > 
> > device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node,
> > "wakeup-source"));
> > 
> > Hence the && condition to make sure that we support wakeup and our children
> > needs it.
> 
> Oh, I see.  I misread the code above, thinking that dwc->dev referred to 
> the root hub.  It doesn't; it refers to the controller.  Sorry for the 
> mistake.
> 
> BTW, if there's any trouble with getting device_wakeup_path() to work 
> the way you want, you could consider instead calling 
> usb_wakeup_enabled_descendants() on the root hub.  This function returns 
> a count of the number of wakeup-enabled USB devices at or below the 
> device you pass to it.
> 

This series [1] started with usb_wakeup_enabled_descendants() actually. one
of the problem with this API is that we have to call this on both USB2.0 and
USB3.0 root hubs. Do you think we can have a wrapper function like
usb_hcd_wakeup_enabled_descendants() that accepts hcd as an argument and
internally call usb_wakeup_enabled_descendants() on both root hubs and return
the result.

Thanks,
Pavan
Pavan Kondeti May 9, 2022, 2:27 p.m. UTC | #12
On Mon, May 09, 2022 at 07:53:41PM +0530, Pavan Kondeti wrote:
> On Mon, May 09, 2022 at 10:08:41AM -0400, Alan Stern wrote:
> > On Mon, May 09, 2022 at 09:02:38AM +0530, Pavan Kondeti wrote:
> > > On Fri, May 06, 2022 at 04:30:33PM -0400, Alan Stern wrote:
> > > > On Fri, May 06, 2022 at 11:46:06AM -0700, Matthias Kaehlcke wrote:
> > > > > Currently the core/PHYs are always powered off during suspend in host mode:
> > > > > 
> > > > > static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
> > > > > {
> > > > > 	...
> > > > > 
> > > > > 	switch (dwc->current_dr_role) {
> > > > > 	case DWC3_GCTL_PRTCAP_HOST:
> > > > > 		if (!PMSG_IS_AUTO(msg)) {
> > > > > 			dwc3_core_exit(dwc);
> > > > > 			break;
> > > > > 		}
> > > > > 
> > > > > 	...
> > > > > }
> > > > > 
> > > > > With that I would expect wakeup to be broken for all dwc3. I'm a bit confused
> > > > > though, since dwc3-imx8mp.c seems to support wakeup and the driver landed
> > > > > after the above patch ...
> > > > > 
> > > > > This series intends to change the above code to something like this:
> > > > > 
> > > > > 	if (!PMSG_IS_AUTO(msg)) {
> > > > > 	       if (device_may_wakeup(dwc->dev) &&
> > > > > 	                       device_wakeup_path(dwc->dev)) {
> > > > > 	               dwc->phy_power_off = false;
> > > > > 	       } else {
> > > > > 	               dwc->phy_power_off = true;
> > > > > 	               dwc3_core_exit(dwc);
> > > > > 	       }
> > > > > 	}
> > > > 
> > > > > i.e. the core/PHYs would only be powered down if wakeup is disabled or no
> > > > > wakeup capable devices are connected. With that plug/unplug events still
> > > > > wouldn't be detected.
> > > > 
> > > > Indeed.  Shouldn't the "&&" and "||"?  That is, don't you want to leave 
> > > > the core and PHY powered if wakeup is enabled for the root hub or for 
> > > > any devices beneath it?
> > > > 
> > > > It would be simpler to leave the core and PHY powered whenever wakeup is 
> > > > enabled for the controller itself, regardless of the status of the root 
> > > > hub and downstream devices.  Users might not like this so much if the 
> > > > default setting is to enable wakeup for the controller always.  Still, 
> > > > it's an easy solution.
> > > > 
> > > At this point it is not clear if all boards that has DWC3 controller can
> > > support wakeup capability or not. Thats why we have introduced a wakeup device
> > > tree property based on which we advertise our wakeup capability.
> > > 
> > > device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node,
> > > "wakeup-source"));
> > > 
> > > Hence the && condition to make sure that we support wakeup and our children
> > > needs it.
> > 
> > Oh, I see.  I misread the code above, thinking that dwc->dev referred to 
> > the root hub.  It doesn't; it refers to the controller.  Sorry for the 
> > mistake.
> > 
> > BTW, if there's any trouble with getting device_wakeup_path() to work 
> > the way you want, you could consider instead calling 
> > usb_wakeup_enabled_descendants() on the root hub.  This function returns 
> > a count of the number of wakeup-enabled USB devices at or below the 
> > device you pass to it.
> > 
> 
> This series [1] started with usb_wakeup_enabled_descendants() actually. one
> of the problem with this API is that we have to call this on both USB2.0 and
> USB3.0 root hubs. Do you think we can have a wrapper function like
> usb_hcd_wakeup_enabled_descendants() that accepts hcd as an argument and
> internally call usb_wakeup_enabled_descendants() on both root hubs and return
> the result.
> 
Here is the link to the previous series

https://lore.kernel.org/linux-usb/1649704614-31518-3-git-send-email-quic_c_sanm@quicinc.com/

Thanks,
Pavan
Alan Stern May 9, 2022, 2:33 p.m. UTC | #13
On Mon, May 09, 2022 at 07:53:41PM +0530, Pavan Kondeti wrote:
> On Mon, May 09, 2022 at 10:08:41AM -0400, Alan Stern wrote:
> > BTW, if there's any trouble with getting device_wakeup_path() to work 
> > the way you want, you could consider instead calling 
> > usb_wakeup_enabled_descendants() on the root hub.  This function returns 
> > a count of the number of wakeup-enabled USB devices at or below the 
> > device you pass to it.
> > 
> 
> This series [1] started with usb_wakeup_enabled_descendants() actually. one
> of the problem with this API is that we have to call this on both USB2.0 and
> USB3.0 root hubs. Do you think we can have a wrapper function like
> usb_hcd_wakeup_enabled_descendants() that accepts hcd as an argument and
> internally call usb_wakeup_enabled_descendants() on both root hubs and return
> the result.

Sure you can.  Feel free to write such a function and add it to hcd.c.  
Ideally it should work for host controllers with any number of root 
hubs, just adding up the number of wakeup-enabled descendants for all of 
them.

Alan Stern
Pavan Kondeti May 10, 2022, 1:16 a.m. UTC | #14
On Mon, May 09, 2022 at 10:33:59AM -0400, Alan Stern wrote:
> On Mon, May 09, 2022 at 07:53:41PM +0530, Pavan Kondeti wrote:
> > On Mon, May 09, 2022 at 10:08:41AM -0400, Alan Stern wrote:
> > > BTW, if there's any trouble with getting device_wakeup_path() to work 
> > > the way you want, you could consider instead calling 
> > > usb_wakeup_enabled_descendants() on the root hub.  This function returns 
> > > a count of the number of wakeup-enabled USB devices at or below the 
> > > device you pass to it.
> > > 
> > 
> > This series [1] started with usb_wakeup_enabled_descendants() actually. one
> > of the problem with this API is that we have to call this on both USB2.0 and
> > USB3.0 root hubs. Do you think we can have a wrapper function like
> > usb_hcd_wakeup_enabled_descendants() that accepts hcd as an argument and
> > internally call usb_wakeup_enabled_descendants() on both root hubs and return
> > the result.
> 
> Sure you can.  Feel free to write such a function and add it to hcd.c.  
> Ideally it should work for host controllers with any number of root 
> hubs, just adding up the number of wakeup-enabled descendants for all of 
> them.
> 
Thanks Alan for the suggestion. Does the below diff looks good?

Thanks,
Pavan

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index c9443aa..f707f9b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2704,6 +2704,19 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
 
+unsigned int usb_hcd_wakeup_enabled_descendants(struct usb_hcd *hcd)
+{
+	unsigned int nr_wakeup;
+
+	nr_wakeup = usb_wakeup_enabled_descendants(hcd->self.root_hub);
+
+	if (hcd->shared_hcd)
+		nr_wakeup += usb_wakeup_enabled_descendants(hcd->shared_hcd->self.root_hub);
+
+	return nr_wakeup;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_wakeup_enabled_descendants);
+
 int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
 {
 	if (!hcd->driver->find_raw_port_number)
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 1886e81..a5d561b 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -474,6 +474,7 @@ extern void usb_remove_hcd(struct usb_hcd *hcd);
 extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
 int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
 			    dma_addr_t dma, size_t size);
+extern unsigned int usb_hcd_wakeup_enabled_descendants(struct usb_hcd *hcd);
 
 struct platform_device;
 extern void usb_hcd_platform_shutdown(struct platform_device *dev);
Pavan Kondeti May 10, 2022, 1:30 a.m. UTC | #15
On Tue, May 10, 2022 at 06:46:02AM +0530, Pavan Kondeti wrote:
> On Mon, May 09, 2022 at 10:33:59AM -0400, Alan Stern wrote:
> > On Mon, May 09, 2022 at 07:53:41PM +0530, Pavan Kondeti wrote:
> > > On Mon, May 09, 2022 at 10:08:41AM -0400, Alan Stern wrote:
> > > > BTW, if there's any trouble with getting device_wakeup_path() to work 
> > > > the way you want, you could consider instead calling 
> > > > usb_wakeup_enabled_descendants() on the root hub.  This function returns 
> > > > a count of the number of wakeup-enabled USB devices at or below the 
> > > > device you pass to it.
> > > > 
> > > 
> > > This series [1] started with usb_wakeup_enabled_descendants() actually. one
> > > of the problem with this API is that we have to call this on both USB2.0 and
> > > USB3.0 root hubs. Do you think we can have a wrapper function like
> > > usb_hcd_wakeup_enabled_descendants() that accepts hcd as an argument and
> > > internally call usb_wakeup_enabled_descendants() on both root hubs and return
> > > the result.
> > 
> > Sure you can.  Feel free to write such a function and add it to hcd.c.  
> > Ideally it should work for host controllers with any number of root 
> > hubs, just adding up the number of wakeup-enabled descendants for all of 
> > them.
> > 
> Thanks Alan for the suggestion. Does the below diff looks good?
> 
> Thanks,
> Pavan
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index c9443aa..f707f9b 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -2704,6 +2704,19 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
>  }
>  EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
>  
> +unsigned int usb_hcd_wakeup_enabled_descendants(struct usb_hcd *hcd)
> +{
> +	unsigned int nr_wakeup;
> +
> +	nr_wakeup = usb_wakeup_enabled_descendants(hcd->self.root_hub);
> +
> +	if (hcd->shared_hcd)
> +		nr_wakeup += usb_wakeup_enabled_descendants(hcd->shared_hcd->self.root_hub);
> +

btw, should we add an else block here to take care of companion controllers
associcated if any. Can you pls tell us if it is possible that we have all
the below cases together? should the companion check be done only when
shared_hcd is not present?

- primary HCD (USB2.0, EHCI/XHCI)
- secondary HCD (USB3.0 XHCI)
- hs_companion (USB2.0 companion) for OHCI/UHCI

unsigned int usb_hcd_wakeup_enabled_descendants(struct usb_hcd *hcd)
{
	unsigned int nr_wakeup;

	nr_wakeup = usb_wakeup_enabled_descendants(hcd->self.root_hub);

	if (hcd->shared_hcd)
		nr_wakeup += usb_wakeup_enabled_descendants(hcd->shared_hcd->self.root_hub);
	else if (hcd->self.hs_companion)
		nr_wakeup += usb_wakeup_enabled_descendants(hcd->self.hs_companion->root_hub);

	return nr_wakeup;
}

Thanks,
Pavan
Alan Stern May 10, 2022, 3:22 p.m. UTC | #16
On Tue, May 10, 2022 at 06:46:02AM +0530, Pavan Kondeti wrote:
> On Mon, May 09, 2022 at 10:33:59AM -0400, Alan Stern wrote:
> > On Mon, May 09, 2022 at 07:53:41PM +0530, Pavan Kondeti wrote:
> > > On Mon, May 09, 2022 at 10:08:41AM -0400, Alan Stern wrote:
> > > > BTW, if there's any trouble with getting device_wakeup_path() to work 
> > > > the way you want, you could consider instead calling 
> > > > usb_wakeup_enabled_descendants() on the root hub.  This function returns 
> > > > a count of the number of wakeup-enabled USB devices at or below the 
> > > > device you pass to it.
> > > > 
> > > 
> > > This series [1] started with usb_wakeup_enabled_descendants() actually. one
> > > of the problem with this API is that we have to call this on both USB2.0 and
> > > USB3.0 root hubs. Do you think we can have a wrapper function like
> > > usb_hcd_wakeup_enabled_descendants() that accepts hcd as an argument and
> > > internally call usb_wakeup_enabled_descendants() on both root hubs and return
> > > the result.
> > 
> > Sure you can.  Feel free to write such a function and add it to hcd.c.  
> > Ideally it should work for host controllers with any number of root 
> > hubs, just adding up the number of wakeup-enabled descendants for all of 
> > them.
> > 
> Thanks Alan for the suggestion. Does the below diff looks good?

It looks fine, aside from lacking any comments/kerneldoc.

Alan Stern

> Thanks,
> Pavan
> 
> diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
> index c9443aa..f707f9b 100644
> --- a/drivers/usb/core/hcd.c
> +++ b/drivers/usb/core/hcd.c
> @@ -2704,6 +2704,19 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
>  }
>  EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
>  
> +unsigned int usb_hcd_wakeup_enabled_descendants(struct usb_hcd *hcd)
> +{
> +	unsigned int nr_wakeup;
> +
> +	nr_wakeup = usb_wakeup_enabled_descendants(hcd->self.root_hub);
> +
> +	if (hcd->shared_hcd)
> +		nr_wakeup += usb_wakeup_enabled_descendants(hcd->shared_hcd->self.root_hub);
> +
> +	return nr_wakeup;
> +}
> +EXPORT_SYMBOL_GPL(usb_hcd_wakeup_enabled_descendants);
> +
>  int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
>  {
>  	if (!hcd->driver->find_raw_port_number)
> diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
> index 1886e81..a5d561b 100644
> --- a/include/linux/usb/hcd.h
> +++ b/include/linux/usb/hcd.h
> @@ -474,6 +474,7 @@ extern void usb_remove_hcd(struct usb_hcd *hcd);
>  extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
>  int usb_hcd_setup_local_mem(struct usb_hcd *hcd, phys_addr_t phys_addr,
>  			    dma_addr_t dma, size_t size);
> +extern unsigned int usb_hcd_wakeup_enabled_descendants(struct usb_hcd *hcd);
>  
>  struct platform_device;
>  extern void usb_hcd_platform_shutdown(struct platform_device *dev);
>
Alan Stern May 10, 2022, 3:24 p.m. UTC | #17
On Tue, May 10, 2022 at 07:00:54AM +0530, Pavan Kondeti wrote:
> btw, should we add an else block here to take care of companion controllers
> associcated if any. Can you pls tell us if it is possible that we have all
> the below cases together? should the companion check be done only when
> shared_hcd is not present?
> 
> - primary HCD (USB2.0, EHCI/XHCI)
> - secondary HCD (USB3.0 XHCI)
> - hs_companion (USB2.0 companion) for OHCI/UHCI
> 
> unsigned int usb_hcd_wakeup_enabled_descendants(struct usb_hcd *hcd)
> {
> 	unsigned int nr_wakeup;
> 
> 	nr_wakeup = usb_wakeup_enabled_descendants(hcd->self.root_hub);
> 
> 	if (hcd->shared_hcd)
> 		nr_wakeup += usb_wakeup_enabled_descendants(hcd->shared_hcd->self.root_hub);
> 	else if (hcd->self.hs_companion)
> 		nr_wakeup += usb_wakeup_enabled_descendants(hcd->self.hs_companion->root_hub);

No, this is wrong.  Companion controllers do not contribute to the 
descendant count.  You should ignore them.

Alan Stern
Pavan Kondeti May 11, 2022, 1:46 a.m. UTC | #18
On Tue, May 10, 2022 at 11:22:17AM -0400, Alan Stern wrote:
> On Tue, May 10, 2022 at 06:46:02AM +0530, Pavan Kondeti wrote:
> > On Mon, May 09, 2022 at 10:33:59AM -0400, Alan Stern wrote:
> > > On Mon, May 09, 2022 at 07:53:41PM +0530, Pavan Kondeti wrote:
> > > > On Mon, May 09, 2022 at 10:08:41AM -0400, Alan Stern wrote:
> > > > > BTW, if there's any trouble with getting device_wakeup_path() to work 
> > > > > the way you want, you could consider instead calling 
> > > > > usb_wakeup_enabled_descendants() on the root hub.  This function returns 
> > > > > a count of the number of wakeup-enabled USB devices at or below the 
> > > > > device you pass to it.
> > > > > 
> > > > 
> > > > This series [1] started with usb_wakeup_enabled_descendants() actually. one
> > > > of the problem with this API is that we have to call this on both USB2.0 and
> > > > USB3.0 root hubs. Do you think we can have a wrapper function like
> > > > usb_hcd_wakeup_enabled_descendants() that accepts hcd as an argument and
> > > > internally call usb_wakeup_enabled_descendants() on both root hubs and return
> > > > the result.
> > > 
> > > Sure you can.  Feel free to write such a function and add it to hcd.c.  
> > > Ideally it should work for host controllers with any number of root 
> > > hubs, just adding up the number of wakeup-enabled descendants for all of 
> > > them.
> > > 
> > Thanks Alan for the suggestion. Does the below diff looks good?
> 
> It looks fine, aside from lacking any comments/kerneldoc.
> 
Thanks for taking a look. Sure, I will add comments and kerneldoc for
this API, if we plan to use it.

Thanks,
Pavan
diff mbox series

Patch

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 950e238..cf377f5 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -33,6 +33,7 @@ 
 #include <linux/usb/gadget.h>
 #include <linux/usb/of.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/hcd.h>
 
 #include "core.h"
 #include "gadget.h"
@@ -1787,6 +1788,7 @@  static int dwc3_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, dwc);
 	dwc3_cache_hwparams(dwc);
+	device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source"));
 
 	spin_lock_init(&dwc->lock);
 	mutex_init(&dwc->mutex);
@@ -1936,6 +1938,7 @@  static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 {
 	unsigned long	flags;
 	u32 reg;
+	struct usb_hcd  *hcd = platform_get_drvdata(dwc->xhci);
 
 	switch (dwc->current_dr_role) {
 	case DWC3_GCTL_PRTCAP_DEVICE:
@@ -1948,10 +1951,7 @@  static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 		dwc3_core_exit(dwc);
 		break;
 	case DWC3_GCTL_PRTCAP_HOST:
-		if (!PMSG_IS_AUTO(msg)) {
-			dwc3_core_exit(dwc);
-			break;
-		}
+		dwc3_check_phy_speed_mode(dwc);
 
 		/* Let controller to suspend HSPHY before PHY driver suspends */
 		if (dwc->dis_u2_susphy_quirk ||
@@ -1967,6 +1967,16 @@  static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 
 		phy_pm_runtime_put_sync(dwc->usb2_generic_phy);
 		phy_pm_runtime_put_sync(dwc->usb3_generic_phy);
+
+		if (!PMSG_IS_AUTO(msg)) {
+			if (device_may_wakeup(dwc->dev) &&
+					device_wakeup_path(dwc->dev)) {
+				dwc->phy_power_off = false;
+			} else {
+				dwc->phy_power_off = true;
+				dwc3_core_exit(dwc);
+			}
+		}
 		break;
 	case DWC3_GCTL_PRTCAP_OTG:
 		/* do nothing during runtime_suspend */
@@ -2010,11 +2020,12 @@  static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
 		break;
 	case DWC3_GCTL_PRTCAP_HOST:
 		if (!PMSG_IS_AUTO(msg)) {
-			ret = dwc3_core_init_for_resume(dwc);
-			if (ret)
-				return ret;
-			dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
-			break;
+			if (dwc->phy_power_off) {
+				ret = dwc3_core_init_for_resume(dwc);
+				if (ret)
+					return ret;
+				dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
+			}
 		}
 		/* Restore GUSB2PHYCFG bits that were modified in suspend */
 		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -2086,8 +2097,6 @@  static int dwc3_runtime_suspend(struct device *dev)
 	if (ret)
 		return ret;
 
-	device_init_wakeup(dev, true);
-
 	return 0;
 }
 
@@ -2096,8 +2105,6 @@  static int dwc3_runtime_resume(struct device *dev)
 	struct dwc3     *dwc = dev_get_drvdata(dev);
 	int		ret;
 
-	device_init_wakeup(dev, false);
-
 	ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
 	if (ret)
 		return ret;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 81c486b..37397a8 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1155,6 +1155,9 @@  struct dwc3 {
 
 	bool			phys_ready;
 
+	unsigned int            hs_phy_mode;
+	bool			phy_power_off;
+
 	struct ulpi		*ulpi;
 	bool			ulpi_ready;
 
@@ -1539,6 +1542,7 @@  int dwc3_core_soft_reset(struct dwc3 *dwc);
 #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
+void dwc3_check_phy_speed_mode(struct dwc3 *dwc);
 #else
 static inline int dwc3_host_init(struct dwc3 *dwc)
 { return 0; }
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index eda8719..3902b56 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -13,6 +13,7 @@ 
 #include <linux/platform_device.h>
 
 #include "core.h"
+#include "../host/xhci.h"
 
 static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
 					int irq, char *name)
@@ -138,3 +139,26 @@  void dwc3_host_exit(struct dwc3 *dwc)
 {
 	platform_device_unregister(dwc->xhci);
 }
+
+void dwc3_check_phy_speed_mode(struct dwc3 *dwc)
+{
+	int i, num_ports;
+	u32 reg;
+	struct usb_hcd	*hcd = platform_get_drvdata(dwc->xhci);
+	struct xhci_hcd	*xhci_hcd = hcd_to_xhci(hcd);
+
+	dwc->hs_phy_mode = 0;
+
+	reg = readl(&xhci_hcd->cap_regs->hcs_params1);
+
+	num_ports = HCS_MAX_PORTS(reg);
+	for (i = 0; i < num_ports; i++) {
+		reg = readl(&xhci_hcd->op_regs->port_status_base + i * NUM_PORT_REGS);
+		if (reg & PORT_PE) {
+			if (DEV_HIGHSPEED(reg) || DEV_FULLSPEED(reg))
+				dwc->hs_phy_mode |= PHY_MODE_USB_HOST_HS;
+			else if (DEV_LOWSPEED(reg))
+				dwc->hs_phy_mode |= PHY_MODE_USB_HOST_LS;
+		}
+	}
+}