diff mbox series

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

Message ID d01d23e2473407af37c42acb6ca4815ae5fd256e.1618464534.git.Arthur.Petrosyan@synopsys.com
State New
Headers show
Series [01/15] usb: dwc2: Update exit hibernation when port reset is asserted | expand

Commit Message

Artur Petrosyan April 15, 2021, 5:41 a.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>
---
 drivers/usb/dwc2/platform.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Sergei Shtylyov April 15, 2021, 9:24 a.m. UTC | #1
On 15.04.2021 8:41, 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>
> ---
>   drivers/usb/dwc2/platform.c | 16 ++++++++++++++++
>   1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
> index f8b819cfa80e..2ae4748ed5ec 100644
> --- a/drivers/usb/dwc2/platform.c
> +++ b/drivers/usb/dwc2/platform.c
> @@ -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");

    Again, why duplicate the innermost *if*?

>  +		}
> +	}
> +
>   	/* Exit Partial Power Down when driver is removed. */
>   	if (hsotg->in_ppd) {
>   		ret = dwc2_exit_partial_power_down(hsotg, 0, true);

MBR, Sergei
Dan Carpenter April 15, 2021, 1:40 p.m. UTC | #2
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
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>

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@lists.01.org
Artur Petrosyan April 16, 2021, 5:46 a.m. UTC | #3
Hi Sergei,

On 4/15/2021 13:24, Sergei Shtylyov wrote:
> On 15.04.2021 8:41, 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>

>> ---

>>    drivers/usb/dwc2/platform.c | 16 ++++++++++++++++

>>    1 file changed, 16 insertions(+)

>>

>> diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c

>> index f8b819cfa80e..2ae4748ed5ec 100644

>> --- a/drivers/usb/dwc2/platform.c

>> +++ b/drivers/usb/dwc2/platform.c

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

> 

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

> 

>>   +		}

>> +	}

>> +

>>    	/* 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
diff mbox series

Patch

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