diff mbox series

usb: dwc3: gadget: Avoid runtime resume if disabling pullup

Message ID 1627691374-15711-1-git-send-email-wcheng@codeaurora.org
State Superseded
Headers show
Series usb: dwc3: gadget: Avoid runtime resume if disabling pullup | expand

Commit Message

Wesley Cheng July 31, 2021, 12:29 a.m. UTC
If the device is already in the runtime suspended state, any call to
the pullup routine will issue a runtime resume on the DWC3 core
device.  If the USB gadget is disabling the pullup, then avoid having
to issue a runtime resume, as DWC3 gadget has already been
halted/stopped.

This fixes an issue where the following condition occurs:

usb_gadget_remove_driver()
-->usb_gadget_disconnect()
 -->dwc3_gadget_pullup(0)
  -->pm_runtime_get_sync() -> ret = 0
  -->pm_runtime_put() [async]
-->usb_gadget_udc_stop()
 -->dwc3_gadget_stop()
  -->dwc->gadget_driver = NULL
...

dwc3_suspend_common()
-->dwc3_gadget_suspend()
 -->DWC3 halt/stop routine skipped, driver_data == NULL

This leads to a situation where the DWC3 gadget is not properly
stopped, as the runtime resume would have re-enabled EP0 and event
interrupts, and since we avoided the DWC3 gadget suspend, these
resources were never disabled.

Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
---
 drivers/usb/dwc3/gadget.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

Comments

Jack Pham Aug. 2, 2021, 9:33 p.m. UTC | #1
Hi Wesley,

On Fri, Jul 30, 2021 at 05:29:34PM -0700, Wesley Cheng wrote:
> If the device is already in the runtime suspended state, any call to

> the pullup routine will issue a runtime resume on the DWC3 core

> device.  If the USB gadget is disabling the pullup, then avoid having

> to issue a runtime resume, as DWC3 gadget has already been

> halted/stopped.

> 

> This fixes an issue where the following condition occurs:

> 

> usb_gadget_remove_driver()

> -->usb_gadget_disconnect()

>  -->dwc3_gadget_pullup(0)

>   -->pm_runtime_get_sync() -> ret = 0

>   -->pm_runtime_put() [async]

> -->usb_gadget_udc_stop()

>  -->dwc3_gadget_stop()

>   -->dwc->gadget_driver = NULL

> ...

> 

> dwc3_suspend_common()

> -->dwc3_gadget_suspend()

>  -->DWC3 halt/stop routine skipped, driver_data == NULL

> 

> This leads to a situation where the DWC3 gadget is not properly

> stopped, as the runtime resume would have re-enabled EP0 and event

> interrupts, and since we avoided the DWC3 gadget suspend, these

> resources were never disabled.

> 

> Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>

> ---

>  drivers/usb/dwc3/gadget.c | 11 +++++++++++

>  1 file changed, 11 insertions(+)

> 

> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c

> index a29a4ca..5d08454 100644

> --- a/drivers/usb/dwc3/gadget.c

> +++ b/drivers/usb/dwc3/gadget.c

> @@ -2435,6 +2435,17 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)

>  	}

>  

>  	/*

> +	 * Avoid issuing a runtime resume if the device is already in the

> +	 * suspended state during gadget disconnect.  DWC3 gadget was already

> +	 * halted/stopped during runtime suspend.

> +	 */

> +	if (!is_on) {

> +		pm_runtime_barrier(dwc->dev);

> +		if (pm_runtime_suspended(dwc->dev))

> +			return 0;

> +	}

> +

> +	/*

>  	 * Check the return value for successful resume, or error.  For a

>  	 * successful resume, the DWC3 runtime PM resume routine will handle

>  	 * the run stop sequence, so avoid duplicate operations here.


Should this also go to stable with Fixes: 77adb8bdf422 ("usb: dwc3:
gadget: Allow runtime suspend if UDC unbinded") ?

Jack
Felipe Balbi Aug. 3, 2021, 7:58 a.m. UTC | #2
Jack Pham <jackp@codeaurora.org> writes:

> Hi Wesley,

>

> On Fri, Jul 30, 2021 at 05:29:34PM -0700, Wesley Cheng wrote:

>> If the device is already in the runtime suspended state, any call to

>> the pullup routine will issue a runtime resume on the DWC3 core

>> device.  If the USB gadget is disabling the pullup, then avoid having

>> to issue a runtime resume, as DWC3 gadget has already been

>> halted/stopped.

>> 

>> This fixes an issue where the following condition occurs:

>> 

>> usb_gadget_remove_driver()

>> -->usb_gadget_disconnect()

>>  -->dwc3_gadget_pullup(0)

>>   -->pm_runtime_get_sync() -> ret = 0

>>   -->pm_runtime_put() [async]

>> -->usb_gadget_udc_stop()

>>  -->dwc3_gadget_stop()

>>   -->dwc->gadget_driver = NULL

>> ...

>> 

>> dwc3_suspend_common()

>> -->dwc3_gadget_suspend()

>>  -->DWC3 halt/stop routine skipped, driver_data == NULL

>> 

>> This leads to a situation where the DWC3 gadget is not properly

>> stopped, as the runtime resume would have re-enabled EP0 and event

>> interrupts, and since we avoided the DWC3 gadget suspend, these

>> resources were never disabled.

>> 

>> Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>

>> ---

>>  drivers/usb/dwc3/gadget.c | 11 +++++++++++

>>  1 file changed, 11 insertions(+)

>> 

>> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c

>> index a29a4ca..5d08454 100644

>> --- a/drivers/usb/dwc3/gadget.c

>> +++ b/drivers/usb/dwc3/gadget.c

>> @@ -2435,6 +2435,17 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)

>>  	}

>>  

>>  	/*

>> +	 * Avoid issuing a runtime resume if the device is already in the

>> +	 * suspended state during gadget disconnect.  DWC3 gadget was already

>> +	 * halted/stopped during runtime suspend.

>> +	 */

>> +	if (!is_on) {

>> +		pm_runtime_barrier(dwc->dev);

>> +		if (pm_runtime_suspended(dwc->dev))

>> +			return 0;

>> +	}

>> +

>> +	/*

>>  	 * Check the return value for successful resume, or error.  For a

>>  	 * successful resume, the DWC3 runtime PM resume routine will handle

>>  	 * the run stop sequence, so avoid duplicate operations here.

>

> Should this also go to stable with Fixes: 77adb8bdf422 ("usb: dwc3:

> gadget: Allow runtime suspend if UDC unbinded") ?


sounds like a good idea.

-- 
balbi
Wesley Cheng Aug. 4, 2021, 6:19 a.m. UTC | #3
On 8/3/2021 12:58 AM, Felipe Balbi wrote:
> 

> Jack Pham <jackp@codeaurora.org> writes:

> 

>> Hi Wesley,

>>

>> On Fri, Jul 30, 2021 at 05:29:34PM -0700, Wesley Cheng wrote:

>>> If the device is already in the runtime suspended state, any call to

>>> the pullup routine will issue a runtime resume on the DWC3 core

>>> device.  If the USB gadget is disabling the pullup, then avoid having

>>> to issue a runtime resume, as DWC3 gadget has already been

>>> halted/stopped.

>>>

>>> This fixes an issue where the following condition occurs:

>>>

>>> usb_gadget_remove_driver()

>>> -->usb_gadget_disconnect()

>>>  -->dwc3_gadget_pullup(0)

>>>   -->pm_runtime_get_sync() -> ret = 0

>>>   -->pm_runtime_put() [async]

>>> -->usb_gadget_udc_stop()

>>>  -->dwc3_gadget_stop()

>>>   -->dwc->gadget_driver = NULL

>>> ...

>>>

>>> dwc3_suspend_common()

>>> -->dwc3_gadget_suspend()

>>>  -->DWC3 halt/stop routine skipped, driver_data == NULL

>>>

>>> This leads to a situation where the DWC3 gadget is not properly

>>> stopped, as the runtime resume would have re-enabled EP0 and event

>>> interrupts, and since we avoided the DWC3 gadget suspend, these

>>> resources were never disabled.

>>>

>>> Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>

>>> ---

>>>  drivers/usb/dwc3/gadget.c | 11 +++++++++++

>>>  1 file changed, 11 insertions(+)

>>>

>>> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c

>>> index a29a4ca..5d08454 100644

>>> --- a/drivers/usb/dwc3/gadget.c

>>> +++ b/drivers/usb/dwc3/gadget.c

>>> @@ -2435,6 +2435,17 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)

>>>  	}

>>>  

>>>  	/*

>>> +	 * Avoid issuing a runtime resume if the device is already in the

>>> +	 * suspended state during gadget disconnect.  DWC3 gadget was already

>>> +	 * halted/stopped during runtime suspend.

>>> +	 */

>>> +	if (!is_on) {

>>> +		pm_runtime_barrier(dwc->dev);

>>> +		if (pm_runtime_suspended(dwc->dev))

>>> +			return 0;

>>> +	}

>>> +

>>> +	/*

>>>  	 * Check the return value for successful resume, or error.  For a

>>>  	 * successful resume, the DWC3 runtime PM resume routine will handle

>>>  	 * the run stop sequence, so avoid duplicate operations here.


Hi Jack/Felipe,

>>

>> Should this also go to stable with Fixes: 77adb8bdf422 ("usb: dwc3:

>> gadget: Allow runtime suspend if UDC unbinded") ?

> 

> sounds like a good idea.

> 


Sure, will update the commit text with the fixes tag.  Thanks!

Regards,
Wesley Cheng

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
diff mbox series

Patch

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a29a4ca..5d08454 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2435,6 +2435,17 @@  static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
 	}
 
 	/*
+	 * Avoid issuing a runtime resume if the device is already in the
+	 * suspended state during gadget disconnect.  DWC3 gadget was already
+	 * halted/stopped during runtime suspend.
+	 */
+	if (!is_on) {
+		pm_runtime_barrier(dwc->dev);
+		if (pm_runtime_suspended(dwc->dev))
+			return 0;
+	}
+
+	/*
 	 * Check the return value for successful resume, or error.  For a
 	 * successful resume, the DWC3 runtime PM resume routine will handle
 	 * the run stop sequence, so avoid duplicate operations here.