usb: dwc2: Update exit hibernation when port reset is asserted
Subsystems (2)
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v2 1/15 usb: dwc2: Update exit hibernation when port reset is asserted
No need to check for "DWC2_POWER_DOWN_PARAM_HIBERNATION" param as "hsotg->hibernated" flag is already enough for exiting from hibernation mode.
- Removes checking of "DWC2_POWER_DOWN_PARAM_HIBERNATION" param.
- For code readability Hibernation exit code moved after debug message print.
- Added "dwc2_exit_hibernation()" function error checking.
--- drivers/usb/dwc2/hcd.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +11 -6
@@ -3668,9 +3668,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,break ;case USB_PORT_FEAT_RESET : -if (hsotg->params.power_down ==DWC2_POWER_DOWN_PARAM_HIBERNATION && - hsotg->hibernated) -dwc2_exit_hibernation (hsotg,0 ,1 ,1 ); +dev_dbg (hsotg->dev, +"SetPortFeature - USB_PORT_FEAT_RESET\n" ); + + hprt0 =dwc2_read_hprt0 (hsotg); + +if (hsotg->hibernated) { + retval =dwc2_exit_hibernation (hsotg,0 ,1 ,1 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed\n" ); + }if (hsotg->in_ppd) { retval = dwc2_exit_partial_power_down(hsotg, 1,
@@ -3684,9 +3692,6 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)dwc2_host_exit_clock_gating (hsotg,0 ); - hprt0 =dwc2_read_hprt0 (hsotg); -dev_dbg (hsotg->dev, -"SetPortFeature - USB_PORT_FEAT_RESET\n" ); pcgctl =dwc2_readl (hsotg,PCGCTL ); pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING |PCGCTL_STOPPCLK );dwc2_writel (hsotg, pcgctl,PCGCTL );
Signature · 1 line
2.25.1
PATCH v2 1/15 usb: dwc2: Update exit hibernation when port reset is asserted
In reply to a message not in the archiveNo need to check for "DWC2_POWER_DOWN_PARAM_HIBERNATION" param as "hsotg->hibernated" flag is already enough for exiting from hibernation mode.
- Removes checking of "DWC2_POWER_DOWN_PARAM_HIBERNATION" param.
- For code readability Hibernation exit code moved after debug message print.
- Added "dwc2_exit_hibernation()" function error checking.
---
Changes in v2:
- None
drivers/usb/dwc2/hcd.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +11 -6
@@ -3668,9 +3668,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,break ;case USB_PORT_FEAT_RESET : -if (hsotg->params.power_down ==DWC2_POWER_DOWN_PARAM_HIBERNATION && - hsotg->hibernated) -dwc2_exit_hibernation (hsotg,0 ,1 ,1 ); +dev_dbg (hsotg->dev, +"SetPortFeature - USB_PORT_FEAT_RESET\n" ); + + hprt0 =dwc2_read_hprt0 (hsotg); + +if (hsotg->hibernated) { + retval =dwc2_exit_hibernation (hsotg,0 ,1 ,1 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed\n" ); + }if (hsotg->in_ppd) { retval = dwc2_exit_partial_power_down(hsotg, 1,
@@ -3684,9 +3692,6 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)dwc2_host_exit_clock_gating (hsotg,0 ); - hprt0 =dwc2_read_hprt0 (hsotg); -dev_dbg (hsotg->dev, -"SetPortFeature - USB_PORT_FEAT_RESET\n" ); pcgctl =dwc2_readl (hsotg,PCGCTL ); pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING |PCGCTL_STOPPCLK );dwc2_writel (hsotg, pcgctl,PCGCTL );
Signature · 1 line
2.25.1
Quoted 4 lines · Artur Petrosyan
No need to check for "
DWC2_POWER_DOWN_PARAM_HIBERNATION" param as "hsotg->hibernated" flag is already enough for exiting from hibernation mode.
Quoted 8 lines
- Removes checking of "
DWC2_POWER_DOWN_PARAM_HIBERNATION" param.- For code readability Hibernation exit code moved after debug message print.
- Added "
dwc2_exit_hibernation()" function error checking.Signed-off-by Artur Petrosyan <[email protected]>
Quoted 43 lines
---
Changes in v2:
- Nonedrivers/usb/dwc2/hcd.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)drivers/usb/dwc2/hcd.c +11
-6@@ -3668,9 +3668,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,break ;case USB_PORT_FEAT_RESET : -if (hsotg->params.power_down ==DWC2_POWER_DOWN_PARAM_HIBERNATION && - hsotg->hibernated) -dwc2_exit_hibernation (hsotg,0 ,1 ,1 ); +dev_dbg (hsotg->dev, +"SetPortFeature - USB_PORT_FEAT_RESET\n" ); + + hprt0 =dwc2_read_hprt0 (hsotg); + +if (hsotg->hibernated) { + retval =dwc2_exit_hibernation (hsotg,0 ,1 ,1 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed\n" ); + }if (hsotg->in_ppd) { retval = dwc2_exit_partial_power_down(hsotg, 1,@@ -3684,9 +3692,6 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended)dwc2_host_exit_clock_gating (hsotg,0 ); - hprt0 =dwc2_read_hprt0 (hsotg); -dev_dbg (hsotg->dev, -"SetPortFeature - USB_PORT_FEAT_RESET\n" ); pcgctl =dwc2_readl (hsotg,PCGCTL ); pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING |PCGCTL_STOPPCLK );dwc2_writel (hsotg, pcgctl,PCGCTL );
PATCH v2 2/15 usb: dwc2: Reset DEVADDR after exiting gadget hibernation.
In reply to a message not in the archiveInitially resetting device address was done in dwc2_hsotg_irq() interrupt handler. However, when core is hibernated USB RESET is not handled in dwc2_hsotg_irq() handler, instead USB RESET interrupt is handled in dwc2_handle_gpwrdn_intr() handler.
- Added reset device address to zero when core exits from gadget hibernation.
--- drivers/usb/dwc2/gadget.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/dwc2/gadget.c +4 -0
@@ -5305,6 +5305,10 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,dwc2_writel (hsotg, dr->dcfg,DCFG );dwc2_writel (hsotg, dr->dctl,DCTL ); +/* On USB Reset, reset device address to zero */ +if (reset) +dwc2_clear_bit (hsotg,DCFG ,DCFG_DEVADDR_MASK ); +/* De-assert Wakeup Logic */ gpwrdn =dwc2_readl (hsotg,GPWRDN ); gpwrdn &= ~GPWRDN_PMUACTV ;
Signature · 1 line
2.25.1
PATCH v2 2/15 usb: dwc2: Reset DEVADDR after exiting gadget hibernation.
In reply to a message not in the archiveInitially resetting device address was done in dwc2_hsotg_irq() interrupt handler. However, when core is hibernated USB RESET is not handled in dwc2_hsotg_irq() handler, instead USB RESET interrupt is handled in dwc2_handle_gpwrdn_intr() handler.
- Added reset device address to zero when core exits from gadget hibernation.
--- drivers/usb/dwc2/gadget.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/dwc2/gadget.c +4 -0
@@ -5305,6 +5305,10 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,dwc2_writel (hsotg, dr->dcfg,DCFG );dwc2_writel (hsotg, dr->dctl,DCTL ); +/* On USB Reset, reset device address to zero */ +if (reset) +dwc2_clear_bit (hsotg,DCFG ,DCFG_DEVADDR_MASK ); +/* De-assert Wakeup Logic */ gpwrdn =dwc2_readl (hsotg,GPWRDN ); gpwrdn &= ~GPWRDN_PMUACTV ;
Signature · 1 line
2.25.1
PATCH v2 3/15 usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
In reply to a message not in the archiveAdded setting "port_connect_status_change" flag to "1" in order to re-enumerate, because after exit from hibernation port connection status is not detected.
--- drivers/usb/dwc2/hcd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/usb/dwc2/hcd.c +9 -1
@@ -5650,7 +5650,15 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,return ret; } -dwc2_hcd_rem_wakeup (hsotg); +if (rem_wakeup) { +dwc2_hcd_rem_wakeup (hsotg); +/* +* Change "port_connect_status_change" flag to re-enumerate, +* because after exit from hibernation port connection status +* is not detected. +*/ + hsotg->flags.b.port_connect_status_change =1 ; + } hsotg->hibernated =0 ; hsotg->bus_suspended =0 ;
Signature · 1 line
2.25.1
PATCH v2 3/15 usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
In reply to a message not in the archiveAdded setting "port_connect_status_change" flag to "1" in order to re-enumerate, because after exit from hibernation port connection status is not detected.
---
Changes in v2:
- None
drivers/usb/dwc2/hcd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/usb/dwc2/hcd.c +9 -1
@@ -5650,7 +5650,15 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,return ret; } -dwc2_hcd_rem_wakeup (hsotg); +if (rem_wakeup) { +dwc2_hcd_rem_wakeup (hsotg); +/* +* Change "port_connect_status_change" flag to re-enumerate, +* because after exit from hibernation port connection status +* is not detected. +*/ + hsotg->flags.b.port_connect_status_change =1 ; + } hsotg->hibernated =0 ; hsotg->bus_suspended =0 ;
Signature · 1 line
2.25.1
Re: [PATCH v2 03/15] usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
Quoted 6 lines · Artur Petrosyan
Added setting "
port_connect_status_change" flag to "1" in order to re-enumerate, because after exit from hibernation port connection status is not detected.Fixes c5c403dc4336 ("usb: dwc2: Add host/device hibernation functions")Signed-off-by Artur Petrosyan <[email protected]>
Quoted 29 lines
---
Changes in v2:
- Nonedrivers/usb/dwc2/hcd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)drivers/usb/dwc2/hcd.c +9
-1@@ -5650,7 +5650,15 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,return ret; } -dwc2_hcd_rem_wakeup (hsotg); +if (rem_wakeup) { +dwc2_hcd_rem_wakeup (hsotg); +/* +* Change "port_connect_status_change" flag to re-enumerate, +* because after exit from hibernation port connection status +* is not detected. +*/ + hsotg->flags.b.port_connect_status_change =1 ; + } hsotg->hibernated =0 ; hsotg->bus_suspended =0 ;
PATCH v2 4/15 usb: dwc2: Fix hibernation between host and device modes.
In reply to a message not in the archiveWhen core is in hibernation in host mode and a device cable was connected then driver exited from device hibernation. However, registers saved for host mode and when exited from device hibernation register restore would be done for device register which was wrong because there was no device registers stored to restore.
- Added dwc_handle_gpwrdn_disc_det() function which handles gpwrdn disconnect detect flow and exits hibernation without restoring the registers.
- Updated exiting from hibernation in GPWRDN_STS_CHGINT with calling dwc_handle_gpwrdn_disc_det() function. Here no register is restored which is the solution described above.
--- drivers/usb/dwc2/core_intr.c | 154 +++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 71 deletions(-)
drivers/usb/dwc2/core_intr.c +83 -71
@@ -680,6 +680,71 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)return 0 ; } +/** +* dwc_handle_gpwrdn_disc_det() - Handles the gpwrdn disconnect detect. +* Exits hibernation without restoring registers. +* +* @hsotg: Programming view of DWC_otg controller +* @gpwrdn: GPWRDN register +*/ +static inline void dwc_handle_gpwrdn_disc_det (struct dwc2_hsotg *hsotg, +u32 gpwrdn) +{ +u32 gpwrdn_tmp; + +/* Switch-on voltage to the core */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Reset core */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Disable Power Down Clamp */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Deassert reset core */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp |=GPWRDN_PWRDNRSTN ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Disable PMU interrupt */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PMUINTSEL ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); + +/* De-assert Wakeup Logic */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PMUACTV ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); + + hsotg->hibernated =0 ; + hsotg->bus_suspended =0 ; + +if (gpwrdn &GPWRDN_IDSTS ) { + hsotg->op_state =OTG_STATE_B_PERIPHERAL ; +dwc2_core_init (hsotg, false); +dwc2_enable_global_interrupts (hsotg); +dwc2_hsotg_core_init_disconnected (hsotg, false); +dwc2_hsotg_core_connect (hsotg); + }else { + hsotg->op_state =OTG_STATE_A_HOST ; + +/* Initialize the Core for Host mode */ +dwc2_core_init (hsotg, false); +dwc2_enable_global_interrupts (hsotg); +dwc2_hcd_start (hsotg); + } +} +/* * GPWRDN interrupt handler. *
@@ -701,64 +766,14 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)if ((gpwrdn &GPWRDN_DISCONN_DET ) && (gpwrdn &GPWRDN_DISCONN_DET_MSK ) && !linestate) { -u32 gpwrdn_tmp; -dev_dbg (hsotg->dev,"%s: GPWRDN_DISCONN_DET\n" , __func__); - -/* Switch-on voltage to the core */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Reset core */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Disable Power Down Clamp */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Deassert reset core */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp |=GPWRDN_PWRDNRSTN ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Disable PMU interrupt */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PMUINTSEL ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); - -/* De-assert Wakeup Logic */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PMUACTV ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); - - hsotg->hibernated =0 ; - -if (gpwrdn &GPWRDN_IDSTS ) { - hsotg->op_state =OTG_STATE_B_PERIPHERAL ; -dwc2_core_init (hsotg, false); -dwc2_enable_global_interrupts (hsotg); -dwc2_hsotg_core_init_disconnected (hsotg, false); -dwc2_hsotg_core_connect (hsotg); - }else { - hsotg->op_state =OTG_STATE_A_HOST ; - -/* Initialize the Core for Host mode */ -dwc2_core_init (hsotg, false); -dwc2_enable_global_interrupts (hsotg); -dwc2_hcd_start (hsotg); - } - } - -if ((gpwrdn &GPWRDN_LNSTSCHG ) && - (gpwrdn &GPWRDN_LNSTSCHG_MSK ) && linestate) { +/* +* Call disconnect detect function to exit from +* hibernation +*/ +dwc_handle_gpwrdn_disc_det (hsotg, gpwrdn); + }else if ((gpwrdn &GPWRDN_LNSTSCHG ) && + (gpwrdn &GPWRDN_LNSTSCHG_MSK ) && linestate) {dev_dbg (hsotg->dev,"%s: GPWRDN_LNSTSCHG\n" , __func__);if (hsotg->hw_params.hibernation && hsotg->hibernated) {
@@ -769,24 +784,21 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); } } - } -if ((gpwrdn &GPWRDN_RST_DET ) && (gpwrdn &GPWRDN_RST_DET_MSK )) { + }else if ((gpwrdn &GPWRDN_RST_DET ) && + (gpwrdn &GPWRDN_RST_DET_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_RST_DET\n" , __func__);if (!linestate && (gpwrdn &GPWRDN_BSESSVLD ))dwc2_exit_hibernation (hsotg,0 ,1 ,0 ); - } -if ((gpwrdn &GPWRDN_STS_CHGINT ) && - (gpwrdn &GPWRDN_STS_CHGINT_MSK ) && linestate) { + }else if ((gpwrdn &GPWRDN_STS_CHGINT ) && + (gpwrdn &GPWRDN_STS_CHGINT_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_STS_CHGINT\n" , __func__); -if (hsotg->hw_params.hibernation && - hsotg->hibernated) { -if (gpwrdn &GPWRDN_IDSTS ) { -dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); -call_gadget (hsotg, resume); - }else { -dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); - } - } +/* +* As GPWRDN_STS_CHGINT exit from hibernation flow is +* the same as in GPWRDN_DISCONN_DET flow. Call +* disconnect detect helper function to exit from +* hibernation. +*/ +dwc_handle_gpwrdn_disc_det (hsotg, gpwrdn); } }
Signature · 1 line
2.25.1
PATCH v2 4/15 usb: dwc2: Fix hibernation between host and device modes.
In reply to a message not in the archiveWhen core is in hibernation in host mode and a device cable was connected then driver exited from device hibernation. However, registers saved for host mode and when exited from device hibernation register restore would be done for device register which was wrong because there was no device registers stored to restore.
- Added dwc_handle_gpwrdn_disc_det() function which handles gpwrdn disconnect detect flow and exits hibernation without restoring the registers.
- Updated exiting from hibernation in GPWRDN_STS_CHGINT with calling dwc_handle_gpwrdn_disc_det() function. Here no register is restored which is the solution described above.
--- drivers/usb/dwc2/core_intr.c | 154 +++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 71 deletions(-)
drivers/usb/dwc2/core_intr.c +83 -71
@@ -680,6 +680,71 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)return 0 ; } +/** +* dwc_handle_gpwrdn_disc_det() - Handles the gpwrdn disconnect detect. +* Exits hibernation without restoring registers. +* +* @hsotg: Programming view of DWC_otg controller +* @gpwrdn: GPWRDN register +*/ +static inline void dwc_handle_gpwrdn_disc_det (struct dwc2_hsotg *hsotg, +u32 gpwrdn) +{ +u32 gpwrdn_tmp; + +/* Switch-on voltage to the core */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Reset core */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Disable Power Down Clamp */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Deassert reset core */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp |=GPWRDN_PWRDNRSTN ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); +udelay (5 ); + +/* Disable PMU interrupt */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PMUINTSEL ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); + +/* De-assert Wakeup Logic */ + gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); + gpwrdn_tmp &= ~GPWRDN_PMUACTV ; +dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); + + hsotg->hibernated =0 ; + hsotg->bus_suspended =0 ; + +if (gpwrdn &GPWRDN_IDSTS ) { + hsotg->op_state =OTG_STATE_B_PERIPHERAL ; +dwc2_core_init (hsotg, false); +dwc2_enable_global_interrupts (hsotg); +dwc2_hsotg_core_init_disconnected (hsotg, false); +dwc2_hsotg_core_connect (hsotg); + }else { + hsotg->op_state =OTG_STATE_A_HOST ; + +/* Initialize the Core for Host mode */ +dwc2_core_init (hsotg, false); +dwc2_enable_global_interrupts (hsotg); +dwc2_hcd_start (hsotg); + } +} +/* * GPWRDN interrupt handler. *
@@ -701,64 +766,14 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)if ((gpwrdn &GPWRDN_DISCONN_DET ) && (gpwrdn &GPWRDN_DISCONN_DET_MSK ) && !linestate) { -u32 gpwrdn_tmp; -dev_dbg (hsotg->dev,"%s: GPWRDN_DISCONN_DET\n" , __func__); - -/* Switch-on voltage to the core */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Reset core */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Disable Power Down Clamp */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Deassert reset core */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp |=GPWRDN_PWRDNRSTN ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); -udelay (10 ); - -/* Disable PMU interrupt */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PMUINTSEL ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); - -/* De-assert Wakeup Logic */ - gpwrdn_tmp =dwc2_readl (hsotg,GPWRDN ); - gpwrdn_tmp &= ~GPWRDN_PMUACTV ; -dwc2_writel (hsotg, gpwrdn_tmp,GPWRDN ); - - hsotg->hibernated =0 ; - -if (gpwrdn &GPWRDN_IDSTS ) { - hsotg->op_state =OTG_STATE_B_PERIPHERAL ; -dwc2_core_init (hsotg, false); -dwc2_enable_global_interrupts (hsotg); -dwc2_hsotg_core_init_disconnected (hsotg, false); -dwc2_hsotg_core_connect (hsotg); - }else { - hsotg->op_state =OTG_STATE_A_HOST ; - -/* Initialize the Core for Host mode */ -dwc2_core_init (hsotg, false); -dwc2_enable_global_interrupts (hsotg); -dwc2_hcd_start (hsotg); - } - } - -if ((gpwrdn &GPWRDN_LNSTSCHG ) && - (gpwrdn &GPWRDN_LNSTSCHG_MSK ) && linestate) { +/* +* Call disconnect detect function to exit from +* hibernation +*/ +dwc_handle_gpwrdn_disc_det (hsotg, gpwrdn); + }else if ((gpwrdn &GPWRDN_LNSTSCHG ) && + (gpwrdn &GPWRDN_LNSTSCHG_MSK ) && linestate) {dev_dbg (hsotg->dev,"%s: GPWRDN_LNSTSCHG\n" , __func__);if (hsotg->hw_params.hibernation && hsotg->hibernated) {
@@ -769,24 +784,21 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); } } - } -if ((gpwrdn &GPWRDN_RST_DET ) && (gpwrdn &GPWRDN_RST_DET_MSK )) { + }else if ((gpwrdn &GPWRDN_RST_DET ) && + (gpwrdn &GPWRDN_RST_DET_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_RST_DET\n" , __func__);if (!linestate && (gpwrdn &GPWRDN_BSESSVLD ))dwc2_exit_hibernation (hsotg,0 ,1 ,0 ); - } -if ((gpwrdn &GPWRDN_STS_CHGINT ) && - (gpwrdn &GPWRDN_STS_CHGINT_MSK ) && linestate) { + }else if ((gpwrdn &GPWRDN_STS_CHGINT ) && + (gpwrdn &GPWRDN_STS_CHGINT_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_STS_CHGINT\n" , __func__); -if (hsotg->hw_params.hibernation && - hsotg->hibernated) { -if (gpwrdn &GPWRDN_IDSTS ) { -dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); -call_gadget (hsotg, resume); - }else { -dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); - } - } +/* +* As GPWRDN_STS_CHGINT exit from hibernation flow is +* the same as in GPWRDN_DISCONN_DET flow. Call +* disconnect detect helper function to exit from +* hibernation. +*/ +dwc_handle_gpwrdn_disc_det (hsotg, gpwrdn); } }
Signature · 1 line
2.25.1
PATCH v2 5/15 usb: dwc2: Allow exiting hibernation from gpwrdn rst detect
In reply to a message not in the archiveWhen device cable is disconnected core receives suspend interrupt and enters hibernation. After entering into hibernation GPWRDN_RST_DET and GPWRDN_STS_CHGINT interrupts are asserted.
Allowed exit from gadget hibernation fromGPWRDN_RST_DET by checking only linestate.
Changed the return type of "dwc2_handle_gpwrdn_intr()" function from void to int because exit from hibernation functions have a return value.
--- drivers/usb/dwc2/core_intr.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
drivers/usb/dwc2/core_intr.c +18 -5
@@ -751,10 +751,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg,* The GPWRDN interrupts are those that occur in both Host and * Device mode while core is in hibernated state. */ -static void dwc2_handle_gpwrdn_intr (struct dwc2_hsotg *hsotg) +static int dwc2_handle_gpwrdn_intr (struct dwc2_hsotg *hsotg) {u32 gpwrdn;int linestate; +int ret =0 ; gpwrdn =dwc2_readl (hsotg,GPWRDN );/* clear all interrupt */
@@ -778,17 +779,27 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)if (hsotg->hw_params.hibernation && hsotg->hibernated) {if (gpwrdn &GPWRDN_IDSTS ) { -dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" );call_gadget (hsotg, resume); }else { -dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); + ret =dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); } } }else if ((gpwrdn &GPWRDN_RST_DET ) && (gpwrdn &GPWRDN_RST_DET_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_RST_DET\n" , __func__); -if (!linestate && (gpwrdn &GPWRDN_BSESSVLD )) -dwc2_exit_hibernation (hsotg,0 ,1 ,0 ); +if (!linestate) { + ret =dwc2_exit_hibernation (hsotg,0 ,1 ,0 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } }else if ((gpwrdn &GPWRDN_STS_CHGINT ) && (gpwrdn &GPWRDN_STS_CHGINT_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_STS_CHGINT\n" , __func__);
@@ -800,6 +811,8 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)*/ dwc_handle_gpwrdn_disc_det (hsotg, gpwrdn); } + +return ret; }/*
Signature · 1 line
2.25.1
PATCH v2 5/15 usb: dwc2: Allow exiting hibernation from gpwrdn rst detect
In reply to a message not in the archiveWhen device cable is disconnected core receives suspend interrupt and enters hibernation. After entering into hibernation GPWRDN_RST_DET and GPWRDN_STS_CHGINT interrupts are asserted.
Allowed exit from gadget hibernation fromGPWRDN_RST_DET by checking only linestate.
Changed the return type of "dwc2_handle_gpwrdn_intr()" function from void to int because exit from hibernation functions have a return value.
--- drivers/usb/dwc2/core_intr.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
drivers/usb/dwc2/core_intr.c +18 -5
@@ -751,10 +751,11 @@ static inline void dwc_handle_gpwrdn_disc_det(struct dwc2_hsotg *hsotg,* The GPWRDN interrupts are those that occur in both Host and * Device mode while core is in hibernated state. */ -static void dwc2_handle_gpwrdn_intr (struct dwc2_hsotg *hsotg) +static int dwc2_handle_gpwrdn_intr (struct dwc2_hsotg *hsotg) {u32 gpwrdn;int linestate; +int ret =0 ; gpwrdn =dwc2_readl (hsotg,GPWRDN );/* clear all interrupt */
@@ -778,17 +779,27 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)if (hsotg->hw_params.hibernation && hsotg->hibernated) {if (gpwrdn &GPWRDN_IDSTS ) { -dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" );call_gadget (hsotg, resume); }else { -dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); + ret =dwc2_exit_hibernation (hsotg,1 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); } } }else if ((gpwrdn &GPWRDN_RST_DET ) && (gpwrdn &GPWRDN_RST_DET_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_RST_DET\n" , __func__); -if (!linestate && (gpwrdn &GPWRDN_BSESSVLD )) -dwc2_exit_hibernation (hsotg,0 ,1 ,0 ); +if (!linestate) { + ret =dwc2_exit_hibernation (hsotg,0 ,1 ,0 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } }else if ((gpwrdn &GPWRDN_STS_CHGINT ) && (gpwrdn &GPWRDN_STS_CHGINT_MSK )) {dev_dbg (hsotg->dev,"%s: GPWRDN_STS_CHGINT\n" , __func__);
@@ -800,6 +811,8 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)*/ dwc_handle_gpwrdn_disc_det (hsotg, gpwrdn); } + +return ret; }/*
Signature · 1 line
2.25.1
PATCH v2 6/15 usb: dwc2: Clear fifo_map when resetting core.
In reply to a message not in the archiveSwitching from device mode to host mode by disconnecting device cable core enters and exits form hibernation. However, the fifo map remains not cleared. It results to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) if in host mode we disconnect the micro a to b host cable. Because core reset occurs.
To avoid the WARNING, fifo_map should be cleared
in dwc2_core_reset() function by taking into account configs. fifo_map must be cleared only if driver is configured in "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" mode.
- Added "static inline void dwc2_clear_fifo_map()" helper function to clear fifo_map with peripheral or dual role mode.
- Added a dummy version of "dwc2_clear_fifo_map()" helper for host-only mode.
--- drivers/usb/dwc2/core.c | 16 ++++++++++++++++ drivers/usb/dwc2/core.h | 3 +++ 2 files changed, 19 insertions(+)
drivers/usb/dwc2/core.c +16 -0
@@ -470,6 +470,22 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)dwc2_writel (hsotg, greset,GRSTCTL ); } +/* +* Switching from device mode to host mode by disconnecting +* device cable core enters and exits form hibernation. +* However, the fifo map remains not cleared. It results +* to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ +* gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) +* if in host mode we disconnect the micro a to b host +* cable. Because core reset occurs. +* To avoid the WARNING, fifo_map should be cleared +* in dwc2_core_reset() function by taking into account configs. +* fifo_map must be cleared only if driver is configured in +* "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" +* mode. +*/ +dwc2_clear_fifo_map (hsotg); +/* Wait for AHB master IDLE state */ if (dwc2_hsotg_wait_bit_set (hsotg,GRSTCTL ,GRSTCTL_AHBIDLE ,10000 )) { dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
drivers/usb/dwc2/core.h +3 -0
@@ -1423,6 +1423,8 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);int dwc2_hsotg_tx_fifo_average_depth (struct dwc2_hsotg *hsotg);void dwc2_gadget_init_lpm (struct dwc2_hsotg *hsotg);void dwc2_gadget_program_ref_clk (struct dwc2_hsotg *hsotg); +static inline void dwc2_clear_fifo_map (struct dwc2_hsotg *hsotg) +{ hsotg->fifo_map =0 ; }#else static inline int dwc2_hsotg_remove (struct dwc2_hsotg *dwc2) {return 0 ; }
@@ -1467,6 +1469,7 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) {return 0 ; }static inline void dwc2_gadget_init_lpm (struct dwc2_hsotg *hsotg) {}static inline void dwc2_gadget_program_ref_clk (struct dwc2_hsotg *hsotg) {} +static inline void dwc2_clear_fifo_map (struct dwc2_hsotg *hsotg) {}#endif #if IS_ENABLED (CONFIG_USB_DWC2_HOST ) ||IS_ENABLED (CONFIG_USB_DWC2_DUAL_ROLE )
Signature · 1 line
2.25.1
PATCH v2 6/15 usb: dwc2: Clear fifo_map when resetting core.
In reply to a message not in the archiveSwitching from device mode to host mode by disconnecting device cable core enters and exits form hibernation. However, the fifo map remains not cleared. It results to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) if in host mode we disconnect the micro a to b host cable. Because core reset occurs.
To avoid the WARNING, fifo_map should be cleared
in dwc2_core_reset() function by taking into account configs. fifo_map must be cleared only if driver is configured in "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" mode.
- Added "static inline void dwc2_clear_fifo_map()" helper function to clear fifo_map with peripheral or dual role mode.
- Added a dummy version of "dwc2_clear_fifo_map()" helper for host-only mode.
--- drivers/usb/dwc2/core.c | 16 ++++++++++++++++ drivers/usb/dwc2/core.h | 3 +++ 2 files changed, 19 insertions(+)
drivers/usb/dwc2/core.c +16 -0
@@ -470,6 +470,22 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)dwc2_writel (hsotg, greset,GRSTCTL ); } +/* +* Switching from device mode to host mode by disconnecting +* device cable core enters and exits form hibernation. +* However, the fifo map remains not cleared. It results +* to a WARNING (WARNING: CPU: 5 PID: 0 at drivers/usb/dwc2/ +* gadget.c:307 dwc2_hsotg_init_fifo+0x12/0x152 [dwc2]) +* if in host mode we disconnect the micro a to b host +* cable. Because core reset occurs. +* To avoid the WARNING, fifo_map should be cleared +* in dwc2_core_reset() function by taking into account configs. +* fifo_map must be cleared only if driver is configured in +* "CONFIG_USB_DWC2_PERIPHERAL" or "CONFIG_USB_DWC2_DUAL_ROLE" +* mode. +*/ +dwc2_clear_fifo_map (hsotg); +/* Wait for AHB master IDLE state */ if (dwc2_hsotg_wait_bit_set (hsotg,GRSTCTL ,GRSTCTL_AHBIDLE ,10000 )) { dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
drivers/usb/dwc2/core.h +3 -0
@@ -1423,6 +1423,8 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);int dwc2_hsotg_tx_fifo_average_depth (struct dwc2_hsotg *hsotg);void dwc2_gadget_init_lpm (struct dwc2_hsotg *hsotg);void dwc2_gadget_program_ref_clk (struct dwc2_hsotg *hsotg); +static inline void dwc2_clear_fifo_map (struct dwc2_hsotg *hsotg) +{ hsotg->fifo_map =0 ; }#else static inline int dwc2_hsotg_remove (struct dwc2_hsotg *dwc2) {return 0 ; }
@@ -1467,6 +1469,7 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) {return 0 ; }static inline void dwc2_gadget_init_lpm (struct dwc2_hsotg *hsotg) {}static inline void dwc2_gadget_program_ref_clk (struct dwc2_hsotg *hsotg) {} +static inline void dwc2_clear_fifo_map (struct dwc2_hsotg *hsotg) {}#endif #if IS_ENABLED (CONFIG_USB_DWC2_HOST ) ||IS_ENABLED (CONFIG_USB_DWC2_DUAL_ROLE )
Signature · 1 line
2.25.1
PATCH v2 7/15 usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.
In reply to a message not in the archiveWhen hibernation exit is performed the dwc2_hib_restore_common() function is called. In that function we wait until GINTSTS_RESTOREDONE bit is set. However, after the setting of that bit we get a lot of (dwc2_hsotg_irq:) interrupts which indicates that (GINTSTS.RstrDoneInt) restore done interrupt is asserted.
To avoid restore done interrupt storm after restore is generated clear GINTSTS_RESTOREDONE bit in GINTSTS register.
--- drivers/usb/dwc2/core.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/usb/dwc2/core.c +6 -0
@@ -299,6 +299,12 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, __func__); }else {dev_dbg (hsotg->dev,"restore done generated here\n" ); + +/* +* To avoid restore done interrupt storm after restore is +* generated clear GINTSTS_RESTOREDONE bit. +*/ +dwc2_writel (hsotg,GINTSTS_RESTOREDONE ,GINTSTS ); } }
Signature · 1 line
2.25.1
PATCH v2 7/15 usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.
In reply to a message not in the archiveWhen hibernation exit is performed the dwc2_hib_restore_common() function is called. In that function we wait until GINTSTS_RESTOREDONE bit is set. However, after the setting of that bit we get a lot of (dwc2_hsotg_irq:) interrupts which indicates that (GINTSTS.RstrDoneInt) restore done interrupt is asserted.
To avoid restore done interrupt storm after restore is generated clear GINTSTS_RESTOREDONE bit in GINTSTS register.
--- drivers/usb/dwc2/core.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/usb/dwc2/core.c +6 -0
@@ -299,6 +299,12 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, __func__); }else {dev_dbg (hsotg->dev,"restore done generated here\n" ); + +/* +* To avoid restore done interrupt storm after restore is +* generated clear GINTSTS_RESTOREDONE bit. +*/ +dwc2_writel (hsotg,GINTSTS_RESTOREDONE ,GINTSTS ); } }
Signature · 1 line
2.25.1
PATCH v2 8/15 usb: dwc2: Move enter hibernation to dwc2_port_suspend() function
In reply to a message not in the archiveThis move is done to call enter hibernation handler in "dwc2_port_suspend()" function when core receives port suspend. Otherwise it could be confusing to enter to hibernation in "dwc2_hcd_hub_control()" function but other power saving modes in "dwc2_port_suspend()" function.
--- drivers/usb/dwc2/hcd.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/usb/dwc2/hcd.c +14 -4
@@ -3321,6 +3321,18 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) "enter partial_power_down failed.\n");break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* +* Perform spin unlock and lock because in +* "dwc2_host_enter_hibernation()" function there is a spinlock +* logic which prevents servicing of any IRQ during entering +* hibernation. +*/ +spin_unlock_irqrestore (&hsotg->lock, flags); + ret =dwc2_enter_hibernation (hsotg,1 ); +if (ret) +dev_err (hsotg->dev,"enter hibernation failed.\n" ); +spin_lock_irqsave (&hsotg->lock, flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
@@ -3650,10 +3662,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");if (windex != hsotg->otg_port) goto error; -if (hsotg->params.power_down ==DWC2_POWER_DOWN_PARAM_HIBERNATION ) -dwc2_enter_hibernation (hsotg,1 ); -else -dwc2_port_suspend (hsotg, windex); +if (!hsotg->bus_suspended) + retval =dwc2_port_suspend (hsotg, windex);break ;case USB_PORT_FEAT_POWER :
Signature · 1 line
2.25.1
v2 cover usb: dwc2: Fix Hibernation issues.
In reply to a message not in the archiveThis patch set fixes and improves hibernation mode for dwc2 core. It adds support for the following cases
1. Hibernation entering/exiting flow by system suspend/resume.
2. Exiting hibernation mode before removing driver and urb enqueue.
3. Exiting hibernation from gpwrdn rst detect.
It updates the implementation of dwc2 entering and exiting hibernation mode when a port is suspended or resumed or reset asserted.
It fixes hibernation issues between host and device mode when core enters to hibernation in host mode and mode change happens. Also, a fix is introduced for remote wakeup flow.
The patch set also improves implementation of entering to hibernation from dwc2_handle_usb_suspend_intr() handler.
Changes since V1:
Updated bellow patches. Moved duplicated error checking *if* conditions from innermost to outside if.
1. usb: dwc2: Add exit hibernation mode before removing drive
2. usb: dwc2: Allow exit hibernation in urb enqueue
Fixed an uninitialized pointer variable which was reported by kernel test robot in "usb: dwc2: Add exit hibernation mode before removing drive" patch. After fixing added Reported-by tags for kernel test robot and Dan Carpenter.
Also removed some text from cover letter because I think that is why vger.kernel.org was rejecting it.
Artur Petrosyan (15):
usb: dwc2: Update exit hibernation when port reset is asserted
usb: dwc2: Reset DEVADDR after exiting gadget hibernation.
usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.
usb: dwc2: Fix hibernation between host and device modes.
usb: dwc2: Allow exiting hibernation from gpwrdn rst detect
usb: dwc2: Clear fifo_map when resetting core.
usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.
usb: dwc2: Move enter hibernation to dwc2_port_suspend() function
usb: dwc2: Move exit hibernation to dwc2_port_resume() function
usb: dwc2: Allow exit hibernation in urb enqueue
usb: dwc2: Add hibernation entering flow by system suspend
usb: dwc2: Add hibernation exiting flow by system resume
usb: dwc2: Add exit hibernation mode before removing drive
usb: dwc2: Update dwc2_handle_usb_suspend_intr function.
usb: dwc2: Get rid of useless error checks in suspend interrupt
drivers/usb/dwc2/core.c | 25 ++++- drivers/usb/dwc2/core.h | 3 + drivers/usb/dwc2/core_intr.c | 205 +++++++++++++++++++---------------- drivers/usb/dwc2/gadget.c | 4 + drivers/usb/dwc2/hcd.c | 92 +++++++++++++--- drivers/usb/dwc2/platform.c | 15 +++ 6 files changed, 233 insertions(+), 111 deletions(-)
base-commit: 4b853c236c7b5161a2e444bd8b3c76fe5aa5ddcb
Signature · 1 line
2.25.1
PATCH v2 8/15 usb: dwc2: Move enter hibernation to dwc2_port_suspend() function
In reply to a message not in the archiveThis move is done to call enter hibernation handler in "dwc2_port_suspend()" function when core receives port suspend. Otherwise it could be confusing to enter to hibernation in "dwc2_hcd_hub_control()" function but other power saving modes in "dwc2_port_suspend()" function.
---
Changes in v2:
- None
drivers/usb/dwc2/hcd.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/usb/dwc2/hcd.c +14 -4
@@ -3321,6 +3321,18 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) "enter partial_power_down failed.\n");break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* +* Perform spin unlock and lock because in +* "dwc2_host_enter_hibernation()" function there is a spinlock +* logic which prevents servicing of any IRQ during entering +* hibernation. +*/ +spin_unlock_irqrestore (&hsotg->lock, flags); + ret =dwc2_enter_hibernation (hsotg,1 ); +if (ret) +dev_err (hsotg->dev,"enter hibernation failed.\n" ); +spin_lock_irqsave (&hsotg->lock, flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
@@ -3650,10 +3662,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");if (windex != hsotg->otg_port) goto error; -if (hsotg->params.power_down ==DWC2_POWER_DOWN_PARAM_HIBERNATION ) -dwc2_enter_hibernation (hsotg,1 ); -else -dwc2_port_suspend (hsotg, windex); +if (!hsotg->bus_suspended) + retval =dwc2_port_suspend (hsotg, windex);break ;case USB_PORT_FEAT_POWER :
Signature · 1 line
2.25.1
Re: [PATCH v2 08/15] usb: dwc2: Move enter hibernation to dwc2_port_suspend() function
Quoted 7 lines · Artur Petrosyan
This move is done to call enter hibernation handler in "
dwc2_port_suspend()" function when core receives port suspend. Otherwise it could be confusing to enter to hibernation in "dwc2_hcd_hub_control()" function but other power saving modes in "dwc2_port_suspend()" function.Signed-off-by Artur Petrosyan <[email protected]>
Quoted 44 lines
---
Changes in v2:
- Nonedrivers/usb/dwc2/hcd.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)drivers/usb/dwc2/hcd.c +14
-4@@ -3321,6 +3321,18 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) "enter partial_power_down failed.\n");break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* +* Perform spin unlock and lock because in +* "dwc2_host_enter_hibernation()" function there is a spinlock +* logic which prevents servicing of any IRQ during entering +* hibernation. +*/ +spin_unlock_irqrestore (&hsotg->lock, flags); + ret =dwc2_enter_hibernation (hsotg,1 ); +if (ret) +dev_err (hsotg->dev,"enter hibernation failed.\n" ); +spin_lock_irqsave (&hsotg->lock, flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported, @@ -3650,10 +3662,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");if (windex != hsotg->otg_port) goto error; -if (hsotg->params.power_down ==DWC2_POWER_DOWN_PARAM_HIBERNATION ) -dwc2_enter_hibernation (hsotg,1 ); -else -dwc2_port_suspend (hsotg, windex); +if (!hsotg->bus_suspended) + retval =dwc2_port_suspend (hsotg, windex);break ;case USB_PORT_FEAT_POWER :
PATCH v2 9/15 usb: dwc2: Move exit hibernation to dwc2_port_resume() function
In reply to a message not in the archiveThis move is done to call hibernation exit handler in "dwc2_port_resume()" function when core receives port resume. Otherwise it could be confusing to exit hibernation in "dwc2_hcd_hub_control()" function but other power saving modes in "dwc2_port_resume()" function.
--- drivers/usb/dwc2/hcd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +7 -6
@@ -3383,6 +3383,11 @@ int dwc2_port_resume(struct dwc2_hsotg *hsotg) "exit partial_power_down failed.\n");break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* Exit host hibernation. */ + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev,"exit hibernation failed.\n" ); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
@@ -3446,12 +3451,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,dev_dbg (hsotg->dev,"ClearPortFeature USB_PORT_FEAT_SUSPEND\n" ); -if (hsotg->bus_suspended) { -if (hsotg->hibernated) -dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); -else -dwc2_port_resume (hsotg); - } +if (hsotg->bus_suspended) + retval =dwc2_port_resume (hsotg);break ;case USB_PORT_FEAT_POWER :
Signature · 1 line
2.25.1
PATCH v2 9/15 usb: dwc2: Move exit hibernation to dwc2_port_resume() function
In reply to a message not in the archiveThis move is done to call hibernation exit handler in "dwc2_port_resume()" function when core receives port resume. Otherwise it could be confusing to exit hibernation in "dwc2_hcd_hub_control()" function but other power saving modes in "dwc2_port_resume()" function.
---
Changes in v2:
- None
drivers/usb/dwc2/hcd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +7 -6
@@ -3383,6 +3383,11 @@ int dwc2_port_resume(struct dwc2_hsotg *hsotg) "exit partial_power_down failed.\n");break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* Exit host hibernation. */ + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev,"exit hibernation failed.\n" ); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
@@ -3446,12 +3451,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,dev_dbg (hsotg->dev,"ClearPortFeature USB_PORT_FEAT_SUSPEND\n" ); -if (hsotg->bus_suspended) { -if (hsotg->hibernated) -dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); -else -dwc2_port_resume (hsotg); - } +if (hsotg->bus_suspended) + retval =dwc2_port_resume (hsotg);break ;case USB_PORT_FEAT_POWER :
Signature · 1 line
2.25.1
Re: [PATCH v2 09/15] usb: dwc2: Move exit hibernation to dwc2_port_resume() function
Quoted 7 lines · Artur Petrosyan
This move is done to call hibernation exit handler in "
dwc2_port_resume()" function when core receives port resume. Otherwise it could be confusing to exit hibernation in "dwc2_hcd_hub_control()" function but other power saving modes in "dwc2_port_resume()" function.Signed-off-by Artur Petrosyan <[email protected]>
Quoted 39 lines
---
Changes in v2:
- Nonedrivers/usb/dwc2/hcd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)drivers/usb/dwc2/hcd.c +7
-6@@ -3383,6 +3383,11 @@ int dwc2_port_resume(struct dwc2_hsotg *hsotg) "exit partial_power_down failed.\n");break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* Exit host hibernation. */ + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev,"exit hibernation failed.\n" ); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported, @@ -3446,12 +3451,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,dev_dbg (hsotg->dev,"ClearPortFeature USB_PORT_FEAT_SUSPEND\n" ); -if (hsotg->bus_suspended) { -if (hsotg->hibernated) -dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); -else -dwc2_port_resume (hsotg); - } +if (hsotg->bus_suspended) + retval =dwc2_port_resume (hsotg);break ;case USB_PORT_FEAT_POWER :
PATCH v2 10/15 usb: dwc2: Allow exit hibernation in urb enqueue
In reply to a message not in the archiveWhen core is in hibernation state and an external hub is connected, upper layer sends URB enqueue request, which results in port reset issue.
- Added exit from hibernation state to avoid port reset issue and process upper layer request properly.
--- drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/usb/dwc2/hcd.c +17 -0
@@ -4631,12 +4631,29 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,struct dwc2_qh *qh;bool qh_allocated = false;struct dwc2_qtd *qtd; +struct dwc2_gregs_backup *gr; + + gr = &hsotg->gr_backup;if (dbg_urb (urb)) {dev_vdbg (hsotg->dev,"DWC OTG HCD URB Enqueue\n" );dwc2_dump_urb_info (hcd, urb,"urb_enqueue" ); } +if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + }else { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } + } +if (hsotg->in_ppd) { retval =dwc2_exit_partial_power_down (hsotg,0 , true);if (retval)
Signature · 1 line
2.25.1
Re: [PATCH 10/15] usb: dwc2: Allow exit hibernation in urb enqueue
Quoted 30 lines · Artur Petrosyan
When core is in hibernation state and an external hub is connected, upper layer sends URB enqueue request, which results in port reset issue.
- Added exit from hibernation state to avoid port reset issue and process upper layer request properly.
Signed-off-by Artur Petrosyan <[email protected]>--- drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)drivers/usb/dwc2/hcd.c +4
-0@@ -4631,12 +4631,29 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,struct dwc2_qh *qh;bool qh_allocated = false;struct dwc2_qtd *qtd; +struct dwc2_gregs_backup *gr; + + gr = &hsotg->gr_backup;if (dbg_urb (urb)) {dev_vdbg (hsotg->dev,"DWC OTG HCD URB Enqueue\n" );dwc2_dump_urb_info (hcd, urb,"urb_enqueue" ); } +if (hsotg->hibernated) {
drivers/usb/dwc2/hcd.c static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, · line 4653
Quoted 10 lines
drivers/usb/dwc2/hcd.c +10
-0+if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + }else { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" );
Why not put these identical *if*s outside the the outer *if*?
drivers/usb/dwc2/hcd.c static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, · line 4659
Quoted 6 lines
drivers/usb/dwc2/hcd.c +3
-0+ } + } +if (hsotg->in_ppd) { retval =dwc2_exit_partial_power_down (hsotg,0 , true);if (retval)
MBR, Sergei
Re: [PATCH 10/15] usb: dwc2: Allow exit hibernation in urb enqueue
Hi Sergei,
Quoted 31 lines · Sergei Shtylyov
Quoted 29 lines · Artur Petrosyan
When core is in hibernation state and an external hub is connected, upper layer sends URB enqueue request, which results in port reset issue.
- Added exit from hibernation state to avoid port reset issue and process upper layer request properly.
Signed-off-by Artur Petrosyan <[email protected]>--- drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)drivers/usb/dwc2/hcd.c +3
-0@@ -4631,12 +4631,29 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,struct dwc2_qh *qh;bool qh_allocated = false;struct dwc2_qtd *qtd; +struct dwc2_gregs_backup *gr; + + gr = &hsotg->gr_backup;if (dbg_urb (urb)) {dev_vdbg (hsotg->dev,"DWC OTG HCD URB Enqueue\n" );dwc2_dump_urb_info (hcd, urb,"urb_enqueue" ); }
Quoted 14 lines
drivers/usb/dwc2/hcd.c static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, · line 4653
Quoted 11 lines
drivers/usb/dwc2/hcd.c +11
-0+if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + }else { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" );Why not put these identical *if*s outside the the outer *if*?
Well the reason that the conditions are implemented like they are, is that the inner if checks whether core operates in host mode or device mode and the outside if checks if the core is hibernated or not.
So now imagine that the ifs are combined and core is not hibernated but the operational mode of the driver is let's say gadget. If the case is such then the driver will try to exit from gadget hibernation because of the else condition as the if condition will be false again because core is not hibernated. As a result if we combine the outside and inner ifs then it will try to exit from gadget hibernation but core is not hibernated and that would be an issue.
Quoted 10 lines
drivers/usb/dwc2/hcd.c static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, · line 4659
Quoted 7 lines
drivers/usb/dwc2/hcd.c +3
-0+ } + } +if (hsotg->in_ppd) { retval =dwc2_exit_partial_power_down (hsotg,0 , true);if (retval)MBR, Sergei
Regards,
Artur
Re: [PATCH 10/15] usb: dwc2: Allow exit hibernation in urb enqueue
Hi Sergei,
Quoted 52 lines · Artur Petrosyan
Hi Sergei,
Quoted 31 lines · Sergei Shtylyov
Quoted 29 lines · Artur Petrosyan
When core is in hibernation state and an external hub is connected, upper layer sends URB enqueue request, which results in port reset issue.
- Added exit from hibernation state to avoid port reset issue and process upper layer request properly.
Signed-off-by Artur Petrosyan <[email protected]>--- drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)drivers/usb/dwc2/hcd.c +3
-0@@ -4631,12 +4631,29 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,struct dwc2_qh *qh;bool qh_allocated = false;struct dwc2_qtd *qtd; +struct dwc2_gregs_backup *gr; + + gr = &hsotg->gr_backup;if (dbg_urb (urb)) {dev_vdbg (hsotg->dev,"DWC OTG HCD URB Enqueue\n" );dwc2_dump_urb_info (hcd, urb,"urb_enqueue" ); }Quoted 14 lines
drivers/usb/dwc2/hcd.c static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, · line 4653
Quoted 11 lines
drivers/usb/dwc2/hcd.c +11
-0+if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + }else { + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" );Why not put these identical *if*s outside the the outer *if*?
Well the reason that the conditions are implemented like they are, is that the inner if checks whether core operates in host mode or device mode and the outside if checks if the core is hibernated or not.
Quoted 8 lines
So now imagine that the ifs are combined and core is not hibernated but the operational mode of the driver is let's say gadget. If the case is such then the driver will try to exit from gadget hibernation because of the else condition as the if condition will be false again because core is not hibernated. As a result if we combine the outside and inner ifs then it will try to exit from gadget hibernation but core is not hibernated and that would be an issue.
Sorry I got your point wrong there. You meant the ifs for dev_err(). Thank you for the review I will update them.
Quoted 15 lines
Quoted 11 lines
drivers/usb/dwc2/hcd.c static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, · line 4659
Quoted 8 lines
drivers/usb/dwc2/hcd.c +3
-0+ } + } +if (hsotg->in_ppd) { retval =dwc2_exit_partial_power_down (hsotg,0 , true);if (retval)MBR, Sergei
Regards,
Artur
PATCH v2 10/15 usb: dwc2: Allow exit hibernation in urb enqueue
In reply to a message not in the archiveWhen core is in hibernation state and an external hub is connected, upper layer sends URB enqueue request, which results in port reset issue.
- Added exit from hibernation state to avoid port reset issue and process upper layer request properly.
---
Changes in v2:
- Moved duplicated error checking *if* conditions from innermost to outside if.
drivers/usb/dwc2/hcd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/usb/dwc2/hcd.c +14 -0
@@ -4631,12 +4631,26 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,struct dwc2_qh *qh;bool qh_allocated = false;struct dwc2_qtd *qtd; +struct dwc2_gregs_backup *gr; + + gr = &hsotg->gr_backup;if (dbg_urb (urb)) {dev_vdbg (hsotg->dev,"DWC OTG HCD URB Enqueue\n" );dwc2_dump_urb_info (hcd, urb,"urb_enqueue" ); } +if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +else + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); + +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } +if (hsotg->in_ppd) { retval =dwc2_exit_partial_power_down (hsotg,0 , true);if (retval)
Signature · 1 line
2.25.1
Re: [PATCH v2 10/15] usb: dwc2: Allow exit hibernation in urb enqueue
Quoted 8 lines · Artur Petrosyan
When core is in hibernation state and an external hub is connected, upper layer sends URB enqueue request, which results in port reset issue.
- Added exit from hibernation state to avoid port reset issue and process upper layer request properly.
Signed-off-by Artur Petrosyan <[email protected]>
Quoted 39 lines
---
Changes in v2:
- Moved duplicated error checking *if* conditions from innermost to outside if.drivers/usb/dwc2/hcd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)drivers/usb/dwc2/hcd.c +14
-0@@ -4631,12 +4631,26 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,struct dwc2_qh *qh;bool qh_allocated = false;struct dwc2_qtd *qtd; +struct dwc2_gregs_backup *gr; + + gr = &hsotg->gr_backup;if (dbg_urb (urb)) {dev_vdbg (hsotg->dev,"DWC OTG HCD URB Enqueue\n" );dwc2_dump_urb_info (hcd, urb,"urb_enqueue" ); } +if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +else + retval =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); + +if (retval) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } +if (hsotg->in_ppd) { retval =dwc2_exit_partial_power_down (hsotg,0 , true);if (retval)
PATCH v2 11/15 usb: dwc2: Add hibernation entering flow by system suspend
In reply to a message not in the archiveAdds a new flow of entering hibernation when PC is hibernated or suspended.
--- drivers/usb/dwc2/hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/usb/dwc2/hcd.c +10 -0
@@ -4387,6 +4387,16 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)clear_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags);break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* Enter hibernation */ +spin_unlock_irqrestore (&hsotg->lock, flags); + ret =dwc2_enter_hibernation (hsotg,1 ); +if (ret) +dev_err (hsotg->dev,"enter hibernation failed\n" ); +spin_lock_irqsave (&hsotg->lock, flags); + +/* After entering suspend, hardware is not accessible */ +clear_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
Signature · 1 line
2.25.1
PATCH v2 11/15 usb: dwc2: Add hibernation entering flow by system suspend
In reply to a message not in the archiveAdds a new flow of entering hibernation when PC is hibernated or suspended.
---
Changes in v2:
- None
drivers/usb/dwc2/hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/usb/dwc2/hcd.c +10 -0
@@ -4387,6 +4387,16 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)clear_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags);break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* Enter hibernation */ +spin_unlock_irqrestore (&hsotg->lock, flags); + ret =dwc2_enter_hibernation (hsotg,1 ); +if (ret) +dev_err (hsotg->dev,"enter hibernation failed\n" ); +spin_lock_irqsave (&hsotg->lock, flags); + +/* After entering suspend, hardware is not accessible */ +clear_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
Signature · 1 line
2.25.1
Re: [PATCH v2 11/15] usb: dwc2: Add hibernation entering flow by system suspend
Quoted 4 lines · Artur Petrosyan
Adds a new flow of entering hibernation when PC is hibernated or suspended.
Signed-off-by Artur Petrosyan <[email protected]>
Quoted 29 lines
---
Changes in v2:
- Nonedrivers/usb/dwc2/hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)drivers/usb/dwc2/hcd.c +10
-0@@ -4387,6 +4387,16 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)clear_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags);break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : +/* Enter hibernation */ +spin_unlock_irqrestore (&hsotg->lock, flags); + ret =dwc2_enter_hibernation (hsotg,1 ); +if (ret) +dev_err (hsotg->dev,"enter hibernation failed\n" ); +spin_lock_irqsave (&hsotg->lock, flags); + +/* After entering suspend, hardware is not accessible */ +clear_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
PATCH v2 12/15 usb: dwc2: Add hibernation exiting flow by system resume
In reply to a message not in the archiveAdds a new flow of exiting hibernation when PC is resumed from suspend state.
--- drivers/usb/dwc2/hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/usb/dwc2/hcd.c +10 -0
@@ -4470,6 +4470,16 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)set_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags);break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev,"exit hibernation failed.\n" ); + +/* +* Set HW accessible bit before powering on the controller +* since an interrupt may rise. +*/ +set_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
Signature · 1 line
2.25.1
PATCH v2 12/15 usb: dwc2: Add hibernation exiting flow by system resume
In reply to a message not in the archiveAdds a new flow of exiting hibernation when PC is resumed from suspend state.
---
Changes in v2:
- None
drivers/usb/dwc2/hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/usb/dwc2/hcd.c +10 -0
@@ -4470,6 +4470,16 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)set_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags);break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev,"exit hibernation failed.\n" ); + +/* +* Set HW accessible bit before powering on the controller +* since an interrupt may rise. +*/ +set_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
Signature · 1 line
2.25.1
Re: [PATCH v2 12/15] usb: dwc2: Add hibernation exiting flow by system resume
Quoted 4 lines · Artur Petrosyan
Adds a new flow of exiting hibernation when PC is resumed from suspend state.
Signed-off-by Artur Petrosyan <[email protected]>
Quoted 29 lines
---
Changes in v2:
- Nonedrivers/usb/dwc2/hcd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)drivers/usb/dwc2/hcd.c +10
-0@@ -4470,6 +4470,16 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)set_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags);break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev,"exit hibernation failed.\n" ); + +/* +* Set HW accessible bit before powering on the controller +* since an interrupt may rise. +*/ +set_bit (HCD_FLAG_HW_ACCESSIBLE , &hcd->flags); +break ;case DWC2_POWER_DOWN_PARAM_NONE :/* * If not hibernation nor partial power down are supported,
PATCH v2 13/15 usb: dwc2: Add exit hibernation mode before removing drive
In reply to a message not in the archiveWhen dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.
In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()" function. If core is in hibernation, then checking the operational mode of the driver. To check whether dwc2 core is operating in host mode or device mode there is one way which is retrieving the backup value of "gotgctl" and compare the "CurMod" value. If previously core entered hibernation in host mode then the exit is performed for host if not then exit is performed for device mode. The introduced checking is because in hibernation state all registers are not accessible.
--- drivers/usb/dwc2/platform.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/usb/dwc2/platform.c +16 -0
@@ -316,8 +316,24 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)static int dwc2_driver_remove (struct platform_device *dev) {struct dwc2_hsotg *hsotg =platform_get_drvdata (dev); +struct dwc2_gregs_backup *gr;int ret =0 ; +/* Exit Hibernation when driver is removed. */ +if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) { + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + }else { + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } + } +/* Exit Partial Power Down when driver is removed. */ if (hsotg->in_ppd) { ret =dwc2_exit_partial_power_down (hsotg,0 , true);
Signature · 1 line
2.25.1
Re: [PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive
Quoted 34 lines · Artur Petrosyan
When dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()" function. If core is in hibernation, then checking the operational mode of the driver. To check whether dwc2 core is operating in host mode or device mode there is one way which is retrieving the backup value of "gotgctl" and compare the "CurMod" value. If previously core entered hibernation in host mode then the exit is performed for host if not then exit is performed for device mode. The introduced checking is because in hibernation state all registers are not accessible.Signed-off-by Artur Petrosyan <[email protected]>--- drivers/usb/dwc2/platform.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)drivers/usb/dwc2/platform.c +3
-0@@ -316,8 +316,24 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)static int dwc2_driver_remove (struct platform_device *dev) {struct dwc2_hsotg *hsotg =platform_get_drvdata (dev); +struct dwc2_gregs_backup *gr;int ret =0 ; +/* Exit Hibernation when driver is removed. */ +if (hsotg->hibernated) {
drivers/usb/dwc2/platform.c static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) · line 333
Quoted 10 lines
drivers/usb/dwc2/platform.c +10
-0+if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) { + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + }else { + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" );
Again, why duplicate the innermost *if*?
drivers/usb/dwc2/platform.c static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) · line 339
Quoted 6 lines
drivers/usb/dwc2/platform.c +2
-0+ } + } +/* Exit Partial Power Down when driver is removed. */ if (hsotg->in_ppd) { ret =dwc2_exit_partial_power_down (hsotg,0 , true);
MBR, Sergei
Re: [PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive
Hi Sergei,
Quoted 34 lines · Sergei Shtylyov
Quoted 32 lines · Artur Petrosyan
When dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()" function. If core is in hibernation, then checking the operational mode of the driver. To check whether dwc2 core is operating in host mode or device mode there is one way which is retrieving the backup value of "gotgctl" and compare the "CurMod" value. If previously core entered hibernation in host mode then the exit is performed for host if not then exit is performed for device mode. The introduced checking is because in hibernation state all registers are not accessible.Signed-off-by Artur Petrosyan <[email protected]>--- drivers/usb/dwc2/platform.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)drivers/usb/dwc2/platform.c +1
-0@@ -316,8 +316,24 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)static int dwc2_driver_remove (struct platform_device *dev) {struct dwc2_hsotg *hsotg =platform_get_drvdata (dev); +struct dwc2_gregs_backup *gr;int ret =0 ;
Quoted 14 lines
drivers/usb/dwc2/platform.c static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) · line 333
Quoted 12 lines
drivers/usb/dwc2/platform.c +12
-0+/* Exit Hibernation when driver is removed. */ +if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) { + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + }else { + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" );Again, why duplicate the innermost *if*?
Again the reason is that combination of inner and outside ifs would give as a situation when core would not be hibernated but driver would try to exit from host or device hibernation.
Quoted 10 lines
drivers/usb/dwc2/platform.c static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) · line 339
Quoted 7 lines
drivers/usb/dwc2/platform.c +2
-0+ } + } +/* Exit Partial Power Down when driver is removed. */ if (hsotg->in_ppd) { ret =dwc2_exit_partial_power_down (hsotg,0 , true);MBR, Sergei
Regards,
Artur
kernel test robot
build botRe: [PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive
In reply to Artur PetrosyanThank you for the patch! Perhaps something to improve:
Hi Artur,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on usb/usb-testing]
[also build test WARNING on next-20210414]
[cannot apply to peter.chen-usb/for-usb-next linus/master balbi-usb/testing/next v5.12-rc7] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Artur-Petrosyan/usb-dwc2-Update-exit-hibernation-when-port-reset-is-asserted/20210415-144021 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing config: x86_64-randconfig-a014-20210415 (attached as .config) compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 6a18cc23efad410db48a3ccfc233d215de7d4cb9)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/8e4dbc0200040af9c752aca4090cd41572e6fb86
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Artur-Petrosyan/usb-dwc2-Update-exit-hibernation-when-port-reset-is-asserted/20210415-144021 git checkout 8e4dbc0200040af9c752aca4090cd41572e6fb86
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 ARCH=x86_64
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
>> drivers/usb/dwc2/platform.c:324:7: warning: variable 'gr' is uninitialized when used here [-Wuninitialized]
if (gr->gotgctl & GOTGCTL_CURMODE_HOST) {
^~
drivers/usb/dwc2/platform.c:319:30: note: initialize the variable 'gr' to silence this warning
struct dwc2_gregs_backup *gr;
^
= NULL1 warning generated.
vim +/gr +324 drivers/usb/dwc2/platform.c
304
305 /**
306 * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
307 * DWC_otg driver
308 *
309 * @dev: Platform device
310 *
311 * This routine is called, for example, when the rmmod command is executed. The
312 * device may or may not be electrically present. If it is present, the driver
313 * stops device processing. Any resources used on behalf of this device are
314 * freed.
315 */
316 static int dwc2_driver_remove(struct platform_device *dev)
317 {
318 struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
319 struct dwc2_gregs_backup *gr;
320 int ret = 0;
321
322 /* Exit Hibernation when driver is removed. */
323 if (hsotg->hibernated) {
> 324 if (gr->gotgctl & GOTGCTL_CURMODE_HOST) { 325 ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
326 if (ret)
327 dev_err(hsotg->dev,
328 "exit hibernation failed.\n");
329 } else {
330 ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
331 if (ret)
332 dev_err(hsotg->dev,
333 "exit hibernation failed.\n");
334 }
335 }
336
337 /* Exit Partial Power Down when driver is removed. */
338 if (hsotg->in_ppd) {
339 ret = dwc2_exit_partial_power_down(hsotg, 0, true);
340 if (ret)
341 dev_err(hsotg->dev,
342 "exit partial_power_down failed\n");
343 }
344
345 /* Exit clock gating when driver is removed. */
346 if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
347 hsotg->bus_suspended) {
348 if (dwc2_is_device_mode(hsotg))
349 dwc2_gadget_exit_clock_gating(hsotg, 0);
350 else
351 dwc2_host_exit_clock_gating(hsotg, 0);
352 }
353
354 dwc2_debugfs_exit(hsotg);
355 if (hsotg->hcd_enabled)
356 dwc2_hcd_remove(hsotg);
357 if (hsotg->gadget_enabled)
358 dwc2_hsotg_remove(hsotg);
359
360 dwc2_drd_exit(hsotg);
361
362 if (hsotg->params.activate_stm_id_vb_detection)
363 regulator_disable(hsotg->usb33d);
364
365 if (hsotg->ll_hw_enabled)
366 dwc2_lowlevel_hw_disable(hsotg);
367
368 reset_control_assert(hsotg->reset);
369 reset_control_assert(hsotg->reset_ecc);
370
371 return ret;
372 }
373
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[kbuild] Re: [PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive
In reply to Artur PetrosyanHi Artur,
https://git-scm.com/docs/git-format-patch ]
url: https://github.com/0day-ci/linux/commits/Artur-Petrosyan/usb-dwc2-Update-exit-hibernation-when-port-reset-is-asserted/20210415-144021 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing config: i386-randconfig-m021-20210415 (attached as .config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
If you fix the issue, kindly add following tag as appropriate
smatch warnings:drivers/usb/dwc2/platform.c:324 dwc2_driver_remove() error: potentially dereferencing uninitialized 'gr'.
vim +/gr +324 drivers/usb/dwc2/platform.c
5b9974b13e3648 drivers/staging/dwc2/platform.c Matthijs Kooijman 2013-04-22 316 static int dwc2_driver_remove(struct platform_device *dev)
5b9974b13e3648 drivers/staging/dwc2/platform.c Matthijs Kooijman 2013-04-22 317 {
5b9974b13e3648 drivers/staging/dwc2/platform.c Matthijs Kooijman 2013-04-22 318 struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 319 struct dwc2_gregs_backup *gr;
^^
b46b1ef7b0da5c drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-08 320 int ret = 0;
b46b1ef7b0da5c drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-08 321
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 322 /* Exit Hibernation when driver is removed. */
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 323 if (hsotg->hibernated) {
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 @324 if (gr->gotgctl & GOTGCTL_CURMODE_HOST) {
^^^^^^^^^^^
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 325 ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 326 if (ret)
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 327 dev_err(hsotg->dev,
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 328 "exit hibernation failed.\n");
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 329 } else {
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 330 ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 331 if (ret)
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 332 dev_err(hsotg->dev,
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 333 "exit hibernation failed.\n");
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 334 }
8e4dbc0200040a drivers/usb/dwc2/platform.c Artur Petrosyan 2021-04-15 335 }---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
_______________________________________________
kbuild mailing list -- kbuild(a)lists.01.org
To unsubscribe send an email to kbuild-leave(a)lists.01.org
PATCH v2 13/15 usb: dwc2: Add exit hibernation mode before removing drive
In reply to a message not in the archiveWhen dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.
In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()" function. If core is in hibernation, then checking the operational mode of the driver. To check whether dwc2 core is operating in host mode or device mode there is one way which is retrieving the backup value of "gotgctl" and compare the "CurMod" value. If previously core entered hibernation in host mode then the exit is performed for host if not then exit is performed for device mode. The introduced checking is because in hibernation state all registers are not accessible.
--- drivers/usb/dwc2/platform.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
drivers/usb/dwc2/platform.c +15 -0
@@ -316,8 +316,23 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)static int dwc2_driver_remove (struct platform_device *dev) {struct dwc2_hsotg *hsotg =platform_get_drvdata (dev); +struct dwc2_gregs_backup *gr;int ret =0 ; + gr = &hsotg->gr_backup; + +/* Exit Hibernation when driver is removed. */ +if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +else + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); + +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } +/* Exit Partial Power Down when driver is removed. */ if (hsotg->in_ppd) { ret =dwc2_exit_partial_power_down (hsotg,0 , true);
Signature · 1 line
2.25.1
Re: [PATCH v2 13/15] usb: dwc2: Add exit hibernation mode before removing drive
Quoted 16 lines · Artur Petrosyan
When dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()" function. If core is in hibernation, then checking the operational mode of the driver. To check whether dwc2 core is operating in host mode or device mode there is one way which is retrieving the backup value of "gotgctl" and compare the "CurMod" value. If previously core entered hibernation in host mode then the exit is performed for host if not then exit is performed for device mode. The introduced checking is because in hibernation state all registers are not accessible.
Quoted 3 lines
Signed-off-by Artur Petrosyan <[email protected]>Reported-by kernel test robot <[email protected]>Reported-by Dan Carpenter <[email protected]>
Quoted 33 lines
--- drivers/usb/dwc2/platform.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)drivers/usb/dwc2/platform.c +15
-0@@ -316,8 +316,23 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)static int dwc2_driver_remove (struct platform_device *dev) {struct dwc2_hsotg *hsotg =platform_get_drvdata (dev); +struct dwc2_gregs_backup *gr;int ret =0 ; + gr = &hsotg->gr_backup; + +/* Exit Hibernation when driver is removed. */ +if (hsotg->hibernated) { +if (gr->gotgctl &GOTGCTL_CURMODE_HOST ) + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,1 ); +else + ret =dwc2_exit_hibernation (hsotg,0 ,0 ,0 ); + +if (ret) +dev_err (hsotg->dev, +"exit hibernation failed.\n" ); + } +/* Exit Partial Power Down when driver is removed. */ if (hsotg->in_ppd) { ret =dwc2_exit_partial_power_down (hsotg,0 , true);
PATCH v2 14/15 usb: dwc2: Update dwc2_handle_usb_suspend_intr function.
In reply to a message not in the archiveTo avoid working in two modes (partial power down
and hibernation) changed conditions for entering
partial power down or hibernation.
Instead of checking hw_params.power_optimized and
hw_params.hibernation now checking power_down
param which already set to one of the options
(Hibernation or Partial Power Down) based onOTG_EN_PWROPT.
--- drivers/usb/dwc2/core_intr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/usb/dwc2/core_intr.c +7 -5
@@ -532,7 +532,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)return ; }if (dsts &DSTS_SUSPSTS ) { -if (hsotg->hw_params.power_optimized) { +switch (hsotg->params.power_down) { +case DWC2_POWER_DOWN_PARAM_PARTIAL : ret =dwc2_enter_partial_power_down (hsotg);if (ret) {if (ret != -ENOTSUPP )
@@ -541,21 +542,22 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) __func__); goto skip_power_saving; } -udelay (100 );/* Ask phy to be suspended */ if (!IS_ERR_OR_NULL (hsotg->uphy))usb_phy_set_suspend (hsotg->uphy, true); - }else if (hsotg->hw_params.hibernation) { +break ; +case DWC2_POWER_DOWN_PARAM_HIBERNATION : ret =dwc2_enter_hibernation (hsotg,0 );if (ret && ret != -ENOTSUPP )dev_err (hsotg->dev,"%s: enter hibernation failed\n" , __func__); - }else { +break ; +case DWC2_POWER_DOWN_PARAM_NONE :/* -* If not hibernation nor partial power down are supported, +* If neither hibernation nor partial power down are supported, * clock gating is used to save power. */ dwc2_gadget_enter_clock_gating (hsotg);
Signature · 1 line
2.25.1
PATCH v2 14/15 usb: dwc2: Update dwc2_handle_usb_suspend_intr function.
In reply to a message not in the archiveTo avoid working in two modes (partial power down
and hibernation) changed conditions for entering
partial power down or hibernation.
Instead of checking hw_params.power_optimized and
hw_params.hibernation now checking power_down
param which already set to one of the options
(Hibernation or Partial Power Down) based onOTG_EN_PWROPT.
--- drivers/usb/dwc2/core_intr.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/usb/dwc2/core_intr.c +7 -5
@@ -532,7 +532,8 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)return ; }if (dsts &DSTS_SUSPSTS ) { -if (hsotg->hw_params.power_optimized) { +switch (hsotg->params.power_down) { +case DWC2_POWER_DOWN_PARAM_PARTIAL : ret =dwc2_enter_partial_power_down (hsotg);if (ret) {if (ret != -ENOTSUPP )
@@ -541,21 +542,22 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) __func__); goto skip_power_saving; } -udelay (100 );/* Ask phy to be suspended */ if (!IS_ERR_OR_NULL (hsotg->uphy))usb_phy_set_suspend (hsotg->uphy, true); - }else if (hsotg->hw_params.hibernation) { +break ; +case DWC2_POWER_DOWN_PARAM_HIBERNATION : ret =dwc2_enter_hibernation (hsotg,0 );if (ret && ret != -ENOTSUPP )dev_err (hsotg->dev,"%s: enter hibernation failed\n" , __func__); - }else { +break ; +case DWC2_POWER_DOWN_PARAM_NONE :/* -* If not hibernation nor partial power down are supported, +* If neither hibernation nor partial power down are supported, * clock gating is used to save power. */ dwc2_gadget_enter_clock_gating (hsotg);
Signature · 1 line
2.25.1
PATCH v2 15/15 usb: dwc2: Get rid of useless error checks in suspend interrupt
In reply to a message not in the archiveSquashed from Douglas Anderson's suggested commit
"usb: dwc2: Get rid of useless error checks for
hibernation/partial power down"
- After this commit there should never be any
case where dwc2_enter_partial_power_down() anddwc2_enter_hibernation() are called when
'params.power_down' is not correct. Get rid of
the pile of error checking.
- As part of this cleanup some of the error messages not to have __func__ in them. That's not needed for dev_err() calls since they already have the device name as part of the message.
--- drivers/usb/dwc2/core.c | 3 --- drivers/usb/dwc2/core_intr.c | 18 +++++++----------- 2 files changed, 7 insertions(+), 14 deletions(-)
drivers/usb/dwc2/core.c +0 -3
@@ -391,9 +391,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)*/ int dwc2_enter_hibernation (struct dwc2_hsotg *hsotg,int is_host) { -if (hsotg->params.power_down !=DWC2_POWER_DOWN_PARAM_HIBERNATION ) -return -ENOTSUPP ; -if (is_host)return dwc2_host_enter_hibernation (hsotg);else
drivers/usb/dwc2/core_intr.c +7 -11
@@ -535,13 +535,10 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)switch (hsotg->params.power_down) {case DWC2_POWER_DOWN_PARAM_PARTIAL : ret =dwc2_enter_partial_power_down (hsotg); -if (ret) { -if (ret != -ENOTSUPP ) -dev_err (hsotg->dev, -"%s: enter partial_power_down failed\n" , - __func__); - goto skip_power_saving; - } +if (ret) +dev_err (hsotg->dev, +"enter partial_power_down failed\n" ); +udelay (100 );/* Ask phy to be suspended */
@@ -550,10 +547,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : ret =dwc2_enter_hibernation (hsotg,0 ); -if (ret && ret != -ENOTSUPP ) +if (ret)dev_err (hsotg->dev, -"%s: enter hibernation failed\n" , - __func__); +"enter hibernation failed\n" );break ;case DWC2_POWER_DOWN_PARAM_NONE :/*
@@ -562,7 +558,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)*/ dwc2_gadget_enter_clock_gating (hsotg); } -skip_power_saving: +/* * Change to L2 (suspend) state before releasing * spinlock
Signature · 1 line
2.25.1
PATCH v2 15/15 usb: dwc2: Get rid of useless error checks in suspend interrupt
In reply to a message not in the archiveSquashed from Douglas Anderson's suggested commit
"usb: dwc2: Get rid of useless error checks for
hibernation/partial power down"
- After this commit there should never be any
case where dwc2_enter_partial_power_down() anddwc2_enter_hibernation() are called when
'params.power_down' is not correct. Get rid of
the pile of error checking.
- As part of this cleanup some of the error messages not to have __func__ in them. That's not needed for dev_err() calls since they already have the device name as part of the message.
---
Changes in v2:
- None
drivers/usb/dwc2/core.c | 3 --- drivers/usb/dwc2/core_intr.c | 18 +++++++----------- 2 files changed, 7 insertions(+), 14 deletions(-)
drivers/usb/dwc2/core.c +0 -3
@@ -391,9 +391,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)*/ int dwc2_enter_hibernation (struct dwc2_hsotg *hsotg,int is_host) { -if (hsotg->params.power_down !=DWC2_POWER_DOWN_PARAM_HIBERNATION ) -return -ENOTSUPP ; -if (is_host)return dwc2_host_enter_hibernation (hsotg);else
drivers/usb/dwc2/core_intr.c +7 -11
@@ -535,13 +535,10 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)switch (hsotg->params.power_down) {case DWC2_POWER_DOWN_PARAM_PARTIAL : ret =dwc2_enter_partial_power_down (hsotg); -if (ret) { -if (ret != -ENOTSUPP ) -dev_err (hsotg->dev, -"%s: enter partial_power_down failed\n" , - __func__); - goto skip_power_saving; - } +if (ret) +dev_err (hsotg->dev, +"enter partial_power_down failed\n" ); +udelay (100 );/* Ask phy to be suspended */
@@ -550,10 +547,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : ret =dwc2_enter_hibernation (hsotg,0 ); -if (ret && ret != -ENOTSUPP ) +if (ret)dev_err (hsotg->dev, -"%s: enter hibernation failed\n" , - __func__); +"enter hibernation failed\n" );break ;case DWC2_POWER_DOWN_PARAM_NONE :/*
@@ -562,7 +558,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)*/ dwc2_gadget_enter_clock_gating (hsotg); } -skip_power_saving: +/* * Change to L2 (suspend) state before releasing * spinlock
Signature · 1 line
2.25.1
Re: [PATCH v2 15/15] usb: dwc2: Get rid of useless error checks in suspend interrupt
Quoted 10 lines · Artur Petrosyan
Squashed from Douglas Anderson's suggested commit
"usb: dwc2: Get rid of useless error checks for
hibernation/partial power down"- After this commit there should never be any
case wheredwc2_enter_partial_power_down()anddwc2_enter_hibernation()are called when
'params.power_down' is not correct. Get rid of
the pile of error checking.
Quoted 7 lines
- As part of this cleanup some of the error messages not to have
__func__in them. That's not needed fordev_err()calls since they already have the device name as part of the message.Signed-off-by Artur Petrosyan <[email protected]>Signed-off-by Douglas Anderson <[email protected]>
Quoted 67 lines
---
Changes in v2:
- Nonedrivers/usb/dwc2/core.c | 3 --- drivers/usb/dwc2/core_intr.c | 18 +++++++----------- 2 files changed, 7 insertions(+), 14 deletions(-)drivers/usb/dwc2/core.c +0
-3@@ -391,9 +391,6 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)*/ int dwc2_enter_hibernation (struct dwc2_hsotg *hsotg,int is_host) { -if (hsotg->params.power_down !=DWC2_POWER_DOWN_PARAM_HIBERNATION ) -return -ENOTSUPP ; -if (is_host)return dwc2_host_enter_hibernation (hsotg);else drivers/usb/dwc2/core_intr.c +7
-11@@ -535,13 +535,10 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)switch (hsotg->params.power_down) {case DWC2_POWER_DOWN_PARAM_PARTIAL : ret =dwc2_enter_partial_power_down (hsotg); -if (ret) { -if (ret != -ENOTSUPP ) -dev_err (hsotg->dev, -"%s: enter partial_power_down failed\n" , - __func__); - goto skip_power_saving; - } +if (ret) +dev_err (hsotg->dev, +"enter partial_power_down failed\n" ); +udelay (100 );/* Ask phy to be suspended */ @@ -550,10 +547,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)break ;case DWC2_POWER_DOWN_PARAM_HIBERNATION : ret =dwc2_enter_hibernation (hsotg,0 ); -if (ret && ret != -ENOTSUPP ) +if (ret)dev_err (hsotg->dev, -"%s: enter hibernation failed\n" , - __func__); +"enter hibernation failed\n" );break ;case DWC2_POWER_DOWN_PARAM_NONE :/* @@ -562,7 +558,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)*/ dwc2_gadget_enter_clock_gating (hsotg); } -skip_power_saving: +/* * Change to L2 (suspend) state before releasing * spinlock