linux-usb.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
To: Wesley Cheng <quic_wcheng@quicinc.com>,
	Thinh Nguyen <Thinh.Nguyen@synopsys.com>,
	Pavan Kondeti <quic_pkondeti@quicinc.com>
Cc: Felipe Balbi <balbi@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	"linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>,
	John Youn <John.Youn@synopsys.com>
Subject: Re: [PATCH 4/6] usb: dwc3: ep0: Don't prepare beyond Setup stage
Date: Tue, 24 May 2022 00:25:16 +0000	[thread overview]
Message-ID: <1a1a5485-790e-79ce-f5a6-1e96d9b49a47@synopsys.com> (raw)
In-Reply-To: <33e8af67-9893-848f-d81d-2d4430002e01@quicinc.com>

Wesley Cheng wrote:
> Hi Thinh,
> 
> On 5/23/2022 4:22 PM, Thinh Nguyen wrote:
>> Hi,
>>
>> Pavan Kondeti wrote:
>>> On Thu, Apr 21, 2022 at 07:22:50PM -0700, Thinh Nguyen wrote:
>>>> Since we can't guarantee that the host won't send new Setup packet
>>>> before going through the device-initiated disconnect, don't prepare
>>>> beyond the Setup stage and keep the device in EP0_SETUP_PHASE. This
>>>> ensures that the device-initated disconnect sequence can go through
>>>> gracefully. Note that the controller won't service the End Transfer
>>>> command if it can't DMA out the Setup packet.
>>>>
>>>> Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
>>>> ---
>>>>   drivers/usb/dwc3/ep0.c    |  2 +-
>>>>   drivers/usb/dwc3/gadget.c | 29 +++++++++++++++++------------
>>>>   2 files changed, 18 insertions(+), 13 deletions(-)
>>>>
>>>> diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
>>>> index 1064be5518f6..c47c696316dd 100644
>>>> --- a/drivers/usb/dwc3/ep0.c
>>>> +++ b/drivers/usb/dwc3/ep0.c
>>>> @@ -813,7 +813,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3
>>>> *dwc,
>>>>       int ret = -EINVAL;
>>>>       u32 len;
>>>>   -    if (!dwc->gadget_driver)
>>>> +    if (!dwc->gadget_driver || !dwc->connected)
>>>>           goto out;
>>>>         trace_dwc3_ctrl_req(ctrl);
>>>> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
>>>> index a86225dbaa2c..e5f07c0e8ad9 100644
>>>> --- a/drivers/usb/dwc3/gadget.c
>>>> +++ b/drivers/usb/dwc3/gadget.c
>>>> @@ -2505,6 +2505,23 @@ static int dwc3_gadget_soft_disconnect(struct
>>>> dwc3 *dwc)
>>>>       spin_lock_irqsave(&dwc->lock, flags);
>>>>       dwc->connected = false;
>>>>   +    /*
>>>> +     * Per databook, when we want to stop the gadget, if a control
>>>> transfer
>>>> +     * is still in process, complete it and get the core into setup
>>>> phase.
>>>> +     */
>>>> +    if (dwc->ep0state != EP0_SETUP_PHASE) {
>>>> +        int ret;
>>>> +
>>>> +        reinit_completion(&dwc->ep0_in_setup);
>>>> +
>>>> +        spin_unlock_irqrestore(&dwc->lock, flags);
>>>> +        ret = wait_for_completion_timeout(&dwc->ep0_in_setup,
>>>> +                msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT));
>>>> +        spin_lock_irqsave(&dwc->lock, flags);
>>>> +        if (ret == 0)
>>>> +            dev_warn(dwc->dev, "timed out waiting for SETUP phase\n");
>>>
>>> DWC3_PULL_UP_TIMEOUT is 500 msec. If the ongoing control transfer is
>>> delayed
>>> (dwc3::delayed_status), for whatever reason, would there be a problem?
>>>
>>
>> Sorry for the delayed response. I was away.
>>
>> If the control transfer takes longer than 500ms, then we'd get this
>> timed out warning. However, it should be fine because
>>
>> 1) If the function driver hasn't sent the status, then the host won't be
>> sending a new SETUP packet.
>>
>> 2) If the delayed status was sent and completed immediately after the
>> timeout but before the dwc3_gadget_soft_disconnect holding the
>> spin_lock, then we may see End Transfer command timeout. It may not look
>> like the cleanup was done gracefully, but that should be fine. The
>> command should be able to complete once the spin_lock is released and
>> Setup packet handled. The controller should halt within the polling
>> period.
>>
>> 3) If the host misbehaves and ignores the status stage/abort the control
>> transfer to send a new setup packet, I don't think the current dwc3
>> driver handles that case properly. But that should be for a separate
>> patch fix.
>>
> 
> In the trace that I sent you where the controller halt fails, it is due
> to the above condition that Pavan mentioned.  We're in a situation where
> if the function driver dequeues an USB request, and we are not in the
> proper ep0state to handle, we'll set the DWC3_EP_DELAY_STOP flag.
> 
> Soon after, if a soft disconnect occurs, and we're in a situation where
> delayed_status == 1, then most likely, we'll see the SETUP packet
> timeout (depending on when the function queues the status phase) and
> proceed w/ stop active xfers and gadget.  Since we do not wait for the
> delayed stop condition to be handled before attempting to halt the
> controller, we'll run into a timeout when clearing Run/Stop.  In this
> situation, this is why you don't see the endxfer command being send for
> endpoints.
> 

I see. If that's the case, then the End Transfer command won't be sent.

Can you try this:

diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 793c4aaf85a2..a10e0cb11385 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -292,7 +292,6 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
                if (!(dwc3_ep->flags & DWC3_EP_DELAY_STOP))
                        continue;

-               dwc3_ep->flags &= ~DWC3_EP_DELAY_STOP;
                dwc3_stop_active_transfer(dwc3_ep, true, true);
        }
 }
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index ee8e8974302d..ff7aa7402b5b 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1984,6 +1984,7 @@ static int __dwc3_stop_active_transfer(struct
dwc3_ep *dep, bool force, bool int
        else if (!ret)
                dep->flags |= DWC3_EP_END_TRANSFER_PENDING;

+       dep->flags &= ~DWC3_EP_DELAY_STOP;
        return ret;
 }

@@ -4232,8 +4233,10 @@ void dwc3_stop_active_transfer(struct dwc3_ep
*dep, bool force,
        if (dep->number <= 1 && dwc->ep0state != EP0_DATA_PHASE)
                return;

+       if (interrupt && (dep->flags & DWC3_EP_DELAY_STOP))
+               return;
+
        if (!(dep->flags & DWC3_EP_TRANSFER_STARTED) ||
-           (dep->flags & DWC3_EP_DELAY_STOP) ||
            (dep->flags & DWC3_EP_END_TRANSFER_PENDING))
                return;


This makes sure that we issue End Transfer command to active endpoints.
There's a small chance that the End Transfer command gets timed out if
somehow the status was sent and new setup packet was immediately
received, but the command should go through once the Setup packet is
handled during the polling.

Please help test.

Thanks,
Thinh

  reply	other threads:[~2022-05-24  0:25 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-22  2:22 [PATCH 0/6] usb: dwc3: gadget: Rework pullup Thinh Nguyen
2022-04-22  2:22 ` [PATCH 1/6] usb: dwc3: gadget: Prevent repeat pullup() Thinh Nguyen
2022-04-22  2:22 ` [PATCH 2/6] usb: dwc3: gadget: Refactor pullup() Thinh Nguyen
2022-04-22  2:22 ` [PATCH 3/6] usb: dwc3: gadget: Don't modify GEVNTCOUNT in pullup() Thinh Nguyen
2022-04-22  2:22 ` [PATCH 4/6] usb: dwc3: ep0: Don't prepare beyond Setup stage Thinh Nguyen
2022-05-03 11:01   ` Pavan Kondeti
2022-05-23 23:22     ` Thinh Nguyen
2022-05-23 23:33       ` Wesley Cheng
2022-05-24  0:25         ` Thinh Nguyen [this message]
2022-04-22  2:22 ` [PATCH 5/6] usb: dwc3: gadget: Only End Transfer for ep0 data phase Thinh Nguyen
2022-04-22  2:23 ` [PATCH 6/6] usb: dwc3: gadget: Delay issuing End Transfer Thinh Nguyen
2022-04-28  0:59   ` Wesley Cheng
2022-04-28  1:31     ` Thinh Nguyen
2022-05-03 11:12   ` Pavan Kondeti
2022-05-23 23:23     ` Thinh Nguyen
2022-04-26 21:05 ` [PATCH 0/6] usb: dwc3: gadget: Rework pullup Wesley Cheng
2022-05-20  1:02   ` Wesley Cheng
2022-05-24  0:30     ` Thinh Nguyen
2022-05-24  1:34       ` Wesley Cheng
2022-05-25 17:50         ` Wesley Cheng
2022-05-26  0:25           ` Thinh Nguyen
2022-06-01 21:18             ` Wesley Cheng
2022-06-01 22:07               ` Thinh Nguyen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1a1a5485-790e-79ce-f5a6-1e96d9b49a47@synopsys.com \
    --to=thinh.nguyen@synopsys.com \
    --cc=John.Youn@synopsys.com \
    --cc=balbi@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=quic_pkondeti@quicinc.com \
    --cc=quic_wcheng@quicinc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).