[v2,13/15] usb: dwc2: Add exit hibernation mode before removing drive
diff mbox series

Message ID 20210416124827.9BB59A005D@mailhost.synopsys.com
State New
Headers show
Series
  • Untitled series #495536
Related show

Commit Message

Artur Petrosyan April 16, 2021, 12:48 p.m. UTC
When dwc2 core is in hibernation mode loading
driver again causes driver fail. Because in
that mode registers are not accessible.

In order to exit from hibernation checking
dwc2 core power saving state in "dwc2_driver_remove()"
function. If core is in hibernation, then checking the
operational mode of the driver. To check whether dwc2 core
is operating in host mode or device mode there is one way
which is retrieving the backup value of "gotgctl" and compare
the "CurMod" value. If previously core entered hibernation
in host mode then the exit is performed for host if not then
exit is performed for device mode. The introduced checking
is because in hibernation state all registers are not
accessible.

Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
---
 drivers/usb/dwc2/platform.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

Comments

Minas Harutyunyan April 19, 2021, 7:32 a.m. UTC | #1
On 4/16/2021 4:48 PM, Artur Petrosyan wrote:
> When dwc2 core is in hibernation mode loading
> driver again causes driver fail. Because in
> that mode registers are not accessible.
> 
> In order to exit from hibernation checking
> dwc2 core power saving state in "dwc2_driver_remove()"
> function. If core is in hibernation, then checking the
> operational mode of the driver. To check whether dwc2 core
> is operating in host mode or device mode there is one way
> which is retrieving the backup value of "gotgctl" and compare
> the "CurMod" value. If previously core entered hibernation
> in host mode then the exit is performed for host if not then
> exit is performed for device mode. The introduced checking
> is because in hibernation state all registers are not
> accessible.
> 
> Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
> Reported-by: kernel test robot <lkp@intel.com>
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>

> ---
>   drivers/usb/dwc2/platform.c | 15 +++++++++++++++
>   1 file changed, 15 insertions(+)
> 
> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
> index f8b819cfa80e..8ad33e042a14 100644
> --- a/drivers/usb/dwc2/platform.c
> +++ b/drivers/usb/dwc2/platform.c
> @@ -316,8 +316,23 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
>   static int dwc2_driver_remove(struct platform_device *dev)
>   {
>   	struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
> +	struct dwc2_gregs_backup *gr;
>   	int ret = 0;
>   
> +	gr = &hsotg->gr_backup;
> +
> +	/* Exit Hibernation when driver is removed. */
> +	if (hsotg->hibernated) {
> +		if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
> +			ret = dwc2_exit_hibernation(hsotg, 0, 0, 1);
> +		else
> +			ret = dwc2_exit_hibernation(hsotg, 0, 0, 0);
> +
> +		if (ret)
> +			dev_err(hsotg->dev,
> +				"exit hibernation failed.\n");
> +	}
> +
>   	/* Exit Partial Power Down when driver is removed. */
>   	if (hsotg->in_ppd) {
>   		ret = dwc2_exit_partial_power_down(hsotg, 0, true);
>

Patch
diff mbox series

diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index f8b819cfa80e..8ad33e042a14 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -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);