Skip to contentSkip to conversation

usb: dwc2: Update exit hibernation when port reset is asserted

PATCH In review Artur Petrosyan 5 participants 47 messages Apr 15, 2021 – Apr 19, 2021 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

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
index 04a1b53d65af..cda3f931195d 100644
@@ -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
#2 lore raw

PATCH v2 1/15 usb: dwc2: Update exit hibernation when port reset is asserted

In reply to a message not in the archive

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.

---
Changes in v2:
- None

 drivers/usb/dwc2/hcd.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +11 -6
index 04a1b53d65af..cda3f931195d 100644
@@ -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
Acked-by on v2 1/15
#3 lore raw
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.

Quoted 43 lines

---
Changes in v2:
- None

  drivers/usb/dwc2/hcd.c | 17 +++++++++++------
  1 file changed, 11 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +11 -6
index 04a1b53d65af..cda3f931195d 100644
@@ -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);
#4 lore raw

PATCH v2 2/15 usb: dwc2: Reset DEVADDR after exiting gadget hibernation.

In reply to a message not in the archive

Initially 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
index 2f50f3e62caa..e6bb1bdb2760 100644
@@ -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
#5 lore raw

PATCH v2 2/15 usb: dwc2: Reset DEVADDR after exiting gadget hibernation.

In reply to a message not in the archive

Initially 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
index 2f50f3e62caa..e6bb1bdb2760 100644
@@ -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
#6 lore raw

PATCH v2 3/15 usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.

In reply to a message not in the archive

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")
---
 drivers/usb/dwc2/hcd.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/usb/dwc2/hcd.c +9 -1
index cda3f931195d..ff945c40ef8a 100644
@@ -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
#7 lore raw

PATCH v2 3/15 usb: dwc2: Fix host mode hibernation exit with remote wakeup flow.

In reply to a message not in the archive

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")

---
Changes in v2:
- None

 drivers/usb/dwc2/hcd.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/usb/dwc2/hcd.c +9 -1
index cda3f931195d..ff945c40ef8a 100644
@@ -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
Acked-by on v2 3/15
#8 lore raw

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")
Quoted 29 lines

---
Changes in v2:
- None

  drivers/usb/dwc2/hcd.c | 10 +++++++++-
  1 file changed, 9 insertions(+), 1 deletion(-)
drivers/usb/dwc2/hcd.c +9 -1
index cda3f931195d..ff945c40ef8a 100644
@@ -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;
#9 lore raw

PATCH v2 4/15 usb: dwc2: Fix hibernation between host and device modes.

In reply to a message not in the archive

When 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.

Fixes 65c9c4c6b01f ("usb: dwc2: Add dwc2_handle_gpwrdn_intr() handler")
---
 drivers/usb/dwc2/core_intr.c | 154 +++++++++++++++++++----------------
 1 file changed, 83 insertions(+), 71 deletions(-)
drivers/usb/dwc2/core_intr.c +83 -71
index 550c52c1a0c7..27d729fad227 100644
@@ -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
#10 lore raw

PATCH v2 4/15 usb: dwc2: Fix hibernation between host and device modes.

In reply to a message not in the archive

When 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.

Fixes 65c9c4c6b01f ("usb: dwc2: Add dwc2_handle_gpwrdn_intr() handler")
---
 drivers/usb/dwc2/core_intr.c | 154 +++++++++++++++++++----------------
 1 file changed, 83 insertions(+), 71 deletions(-)
drivers/usb/dwc2/core_intr.c +83 -71
index 550c52c1a0c7..27d729fad227 100644
@@ -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
#11 lore raw

PATCH v2 5/15 usb: dwc2: Allow exiting hibernation from gpwrdn rst detect

In reply to a message not in the archive

When 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 from
GPWRDN_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
index 27d729fad227..f8963c0cf6af 100644
@@ -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
#12 lore raw

PATCH v2 5/15 usb: dwc2: Allow exiting hibernation from gpwrdn rst detect

In reply to a message not in the archive

When 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 from
GPWRDN_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
index 27d729fad227..f8963c0cf6af 100644
@@ -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
#13 lore raw

PATCH v2 6/15 usb: dwc2: Clear fifo_map when resetting core.

In reply to a message not in the archive

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.

- 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
index cb65f7f60573..eccd96fa164e 100644
@@ -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
index 8c12b3061f7f..e1f432095565 100644
@@ -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
#14 lore raw

PATCH v2 6/15 usb: dwc2: Clear fifo_map when resetting core.

In reply to a message not in the archive

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.

- 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
index cb65f7f60573..eccd96fa164e 100644
@@ -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
index 8c12b3061f7f..e1f432095565 100644
@@ -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
#15 lore raw

PATCH v2 7/15 usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.

In reply to a message not in the archive

When 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
index eccd96fa164e..576c262dba55 100644
@@ -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
#16 lore raw

PATCH v2 7/15 usb: dwc2: Clear GINTSTS_RESTOREDONE bit after restore is generated.

In reply to a message not in the archive

When 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
index eccd96fa164e..576c262dba55 100644
@@ -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
#17 lore raw

PATCH v2 8/15 usb: dwc2: Move enter hibernation to dwc2_port_suspend() function

In reply to a message not in the archive

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.

---
 drivers/usb/dwc2/hcd.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/usb/dwc2/hcd.c +14 -4
index ff945c40ef8a..43a2298b7d42 100644
@@ -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
#18 lore raw

v2 cover usb: dwc2: Fix Hibernation issues.

In reply to a message not in the archive

This 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
#19 lore raw

PATCH v2 8/15 usb: dwc2: Move enter hibernation to dwc2_port_suspend() function

In reply to a message not in the archive

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.

---
Changes in v2:
- None

 drivers/usb/dwc2/hcd.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/usb/dwc2/hcd.c +14 -4
index ff945c40ef8a..43a2298b7d42 100644
@@ -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
Acked-by on v2 8/15
#20 lore raw

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.

Quoted 44 lines

---
Changes in v2:
- None

  drivers/usb/dwc2/hcd.c | 18 ++++++++++++++----
  1 file changed, 14 insertions(+), 4 deletions(-)
drivers/usb/dwc2/hcd.c +14 -4
index ff945c40ef8a..43a2298b7d42 100644
@@ -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:
#21 lore raw

PATCH v2 9/15 usb: dwc2: Move exit hibernation to dwc2_port_resume() function

In reply to a message not in the archive

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.

---
 drivers/usb/dwc2/hcd.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +7 -6
index 43a2298b7d42..cc9ad6cf02d9 100644
@@ -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
#22 lore raw

PATCH v2 9/15 usb: dwc2: Move exit hibernation to dwc2_port_resume() function

In reply to a message not in the archive

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.

---
Changes in v2:
- None

 drivers/usb/dwc2/hcd.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +7 -6
index 43a2298b7d42..cc9ad6cf02d9 100644
@@ -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
Acked-by on v2 9/15
#23 lore raw

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.

Quoted 39 lines

---
Changes in v2:
- None

  drivers/usb/dwc2/hcd.c | 13 +++++++------
  1 file changed, 7 insertions(+), 6 deletions(-)
drivers/usb/dwc2/hcd.c +7 -6
index 43a2298b7d42..cc9ad6cf02d9 100644
@@ -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:
#24 lore raw

PATCH v2 10/15 usb: dwc2: Allow exit hibernation in urb enqueue

In reply to a message not in the archive

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.

---
 drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
drivers/usb/dwc2/hcd.c +17 -0
index cc9ad6cf02d9..3b03b2d73aaa 100644
@@ -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
#25 lore raw

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.

---
  drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++
  1 file changed, 17 insertions(+)
drivers/usb/dwc2/hcd.c +4 -0
index cc9ad6cf02d9..3b03b2d73aaa 100644
@@ -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

#26 lore raw

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.

---
   drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++
   1 file changed, 17 insertions(+)
drivers/usb/dwc2/hcd.c +3 -0
index cc9ad6cf02d9..3b03b2d73aaa 100644
@@ -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

#27 lore raw

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.

---
    drivers/usb/dwc2/hcd.c | 17 +++++++++++++++++
    1 file changed, 17 insertions(+)
drivers/usb/dwc2/hcd.c +3 -0
index cc9ad6cf02d9..3b03b2d73aaa 100644
@@ -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

#28 lore raw

PATCH v2 10/15 usb: dwc2: Allow exit hibernation in urb enqueue

In reply to a message not in the archive

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.

---
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
index cc9ad6cf02d9..093b1717df01 100644
@@ -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
Acked-by on v2 10/15
#29 lore raw

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.

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
index cc9ad6cf02d9..093b1717df01 100644
@@ -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)
#30 lore raw

PATCH v2 11/15 usb: dwc2: Add hibernation entering flow by system suspend

In reply to a message not in the archive

Adds 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
index 3b03b2d73aaa..db8eb1940d17 100644
@@ -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
#31 lore raw

PATCH v2 11/15 usb: dwc2: Add hibernation entering flow by system suspend

In reply to a message not in the archive

Adds 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
index 093b1717df01..92848629cc61 100644
@@ -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
Acked-by on v2 11/15
#32 lore raw

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.

Quoted 29 lines

---
Changes in v2:
- None

  drivers/usb/dwc2/hcd.c | 10 ++++++++++
  1 file changed, 10 insertions(+)
drivers/usb/dwc2/hcd.c +10 -0
index 093b1717df01..92848629cc61 100644
@@ -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,
#33 lore raw

PATCH v2 12/15 usb: dwc2: Add hibernation exiting flow by system resume

In reply to a message not in the archive

Adds 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
index db8eb1940d17..c92307775863 100644
@@ -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
#34 lore raw

PATCH v2 12/15 usb: dwc2: Add hibernation exiting flow by system resume

In reply to a message not in the archive

Adds 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
index 92848629cc61..035d4911a3c3 100644
@@ -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
Acked-by on v2 12/15
#35 lore raw

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.

Quoted 29 lines

---
Changes in v2:
- None

  drivers/usb/dwc2/hcd.c | 10 ++++++++++
  1 file changed, 10 insertions(+)
drivers/usb/dwc2/hcd.c +10 -0
index 92848629cc61..035d4911a3c3 100644
@@ -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,
#36 lore raw

PATCH v2 13/15 usb: dwc2: Add exit hibernation mode before removing drive

In reply to a message not in the archive

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.

---
 drivers/usb/dwc2/platform.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
drivers/usb/dwc2/platform.c +16 -0
index f8b819cfa80e..2ae4748ed5ec 100644
@@ -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
#37 lore raw

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.

---
  drivers/usb/dwc2/platform.c | 16 ++++++++++++++++
  1 file changed, 16 insertions(+)
drivers/usb/dwc2/platform.c +3 -0
index f8b819cfa80e..2ae4748ed5ec 100644
@@ -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

#38 lore raw

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.

---
   drivers/usb/dwc2/platform.c | 16 ++++++++++++++++
   1 file changed, 16 insertions(+)
drivers/usb/dwc2/platform.c +1 -0
index f8b819cfa80e..2ae4748ed5ec 100644
@@ -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

#39 lore raw

Re: [PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive

In reply to Artur Petrosyan
Thank 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;
                                       ^
                                        = NULL

1 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

#40 lore raw

[kbuild] Re: [PATCH 13/15] usb: dwc2: Add exit hibernation mode before removing drive

In reply to Artur Petrosyan

Hi 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

#41 lore raw

PATCH v2 13/15 usb: dwc2: Add exit hibernation mode before removing drive

In reply to a message not in the archive

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.

---
 drivers/usb/dwc2/platform.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
drivers/usb/dwc2/platform.c +15 -0
index f8b819cfa80e..8ad33e042a14 100644
@@ -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
Acked-by on v2 13/15
#42 lore raw

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
Quoted 33 lines
---
  drivers/usb/dwc2/platform.c | 15 +++++++++++++++
  1 file changed, 15 insertions(+)
drivers/usb/dwc2/platform.c +15 -0
index f8b819cfa80e..8ad33e042a14 100644
@@ -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);
#43 lore raw

PATCH v2 14/15 usb: dwc2: Update dwc2_handle_usb_suspend_intr function.

In reply to a message not in the archive

To 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 on
OTG_EN_PWROPT.

---
 drivers/usb/dwc2/core_intr.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/usb/dwc2/core_intr.c +7 -5
index f8963c0cf6af..470458ac664b 100644
@@ -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
#44 lore raw

PATCH v2 14/15 usb: dwc2: Update dwc2_handle_usb_suspend_intr function.

In reply to a message not in the archive

To 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 on
OTG_EN_PWROPT.

---
 drivers/usb/dwc2/core_intr.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/usb/dwc2/core_intr.c +7 -5
index f8963c0cf6af..470458ac664b 100644
@@ -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
#45 lore raw

PATCH v2 15/15 usb: dwc2: Get rid of useless error checks in suspend interrupt

In reply to a message not in the archive

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 where dwc2_enter_partial_power_down() and
dwc2_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
index 576c262dba55..6f70ab9577b4 100644
@@ -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
index 470458ac664b..a5ab03808da6 100644
@@ -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
#46 lore raw

PATCH v2 15/15 usb: dwc2: Get rid of useless error checks in suspend interrupt

In reply to a message not in the archive

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 where dwc2_enter_partial_power_down() and
dwc2_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
index 576c262dba55..6f70ab9577b4 100644
@@ -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
index 470458ac664b..a5ab03808da6 100644
@@ -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
Acked-by on v2 15/15
#47 lore raw

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 where dwc2_enter_partial_power_down() and
dwc2_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 for dev_err() calls since they already have the device name as part of the message.

Quoted 67 lines

---
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
index 576c262dba55..6f70ab9577b4 100644
@@ -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
index 470458ac664b..a5ab03808da6 100644
@@ -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