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 |
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.
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.
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
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.
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.
[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
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.
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
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
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
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
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
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
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);
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
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); >
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
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 --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; + } + } +}