Re: [PATCH 6/6] usb: dwc3: gadget: Delay issuing End Transfer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Wesley,

Wesley Cheng wrote:
> Hi Thinh,
> 
> On 4/21/2022 7:23 PM, Thinh Nguyen wrote:
>> If the controller hasn't DMA'ed the Setup data from its fifo, it won't
>> process the End Transfer command. Polling for the command completion may
>> block the driver from servicing the Setup phase and cause a timeout.
>> Previously we only check and delay issuing End Transfer in the case of
>> endpoint dequeue. Let's do that for all End Transfer scenarios.
>>
>> Signed-off-by: Thinh Nguyen <Thinh.Nguyen@xxxxxxxxxxxx>
>> ---
>>   drivers/usb/dwc3/gadget.c | 22 ++++++++++++----------
>>   1 file changed, 12 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
>> index 7c4d5f671687..f0fd7c32828b 100644
>> --- a/drivers/usb/dwc3/gadget.c
>> +++ b/drivers/usb/dwc3/gadget.c
>> @@ -2056,16 +2056,6 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep
>> *ep,
>>           if (r == req) {
>>               struct dwc3_request *t;
>>   -            /*
>> -             * If a Setup packet is received but yet to DMA out, the
>> controller will
>> -             * not process the End Transfer command of any endpoint.
>> Polling of its
>> -             * DEPCMD.CmdAct may block setting up TRB for Setup
>> packet, causing a
>> -             * timeout. Delay issuing the End Transfer command until
>> the Setup TRB is
>> -             * prepared.
>> -             */
>> -            if (dwc->ep0state != EP0_SETUP_PHASE &&
>> !dwc->delayed_status)
>> -                dep->flags |= DWC3_EP_DELAY_STOP;
>> -
>>               /* wait until it is processed */
>>               dwc3_stop_active_transfer(dep, true, true);
>>   @@ -3657,6 +3647,18 @@ void dwc3_stop_active_transfer(struct dwc3_ep
>> *dep, bool force,
>>           (dep->flags & DWC3_EP_END_TRANSFER_PENDING))
>>           return;
>>   +    /*
>> +     * If a Setup packet is received but yet to DMA out, the
>> controller will
>> +     * not process the End Transfer command of any endpoint. Polling
>> of its
>> +     * DEPCMD.CmdAct may block setting up TRB for Setup packet,
>> causing a
>> +     * timeout. Delay issuing the End Transfer command until the
>> Setup TRB is
>> +     * prepared.
>> +     */
>> +    if (dwc->ep0state != EP0_SETUP_PHASE && !dwc->delayed_status) {
>> +        dep->flags |= DWC3_EP_DELAY_STOP;
>> +        return;
>> +    }
>> +
> 
> Since we could be calling dwc3_stop_active_transfer() as part of the
> dwc3_gadget_pullup(0) case (due to dwc3_stop_active_transfers()), how do
> we ensure that all active EPs are stopped before calling run/stop clear?

It should be fine even the End Transfer completes after the run_stop bit
is clear. Clearing the run_stop would stop activity because the host is
disconnected. But the controller can still assert interrupt if there are
pending events even after the run_stop bit is cleared.

> 
> static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) {
> ...
>        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");
>        }
> 
> ---> We know that ep0state will be in SETUP phase now, but host can send
> the SETUP data shortly after here.  This may cause some endpoints in the
> below dwc3_stop_active_transfers() call to mark DWC3_EP_DELAY_STOP.
> (ep0state could advance as we call gadget giveback in between servicing
> each dep, and lock is released briefly)

No, it shouldn't advance. The patch "[PATCH 4/6] usb: dwc3: ep0: Don't
prepare beyond Setup stage" will cause the controller to respond a STALL
to any new control transfer and put it back and prepare a new TRB for a
new SETUP packet.

>     
>        /*
>         * In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a
>         * Section 4.1.8 Table 4-7, it states that for a device-initiated
>         * disconnect, the SW needs to ensure that it sends "a DEPENDXFER
>         * command for any active transfers" before clearing the RunStop
>         * bit.
>         */
>     dwc3_stop_active_transfers(dwc);
> 
> ---> Do we need to add some synchronization here to make sure that all
> EPs that had the DWC3_EP_DELAY_STOP had been serviced by the status
> phase complete handler?  Otherwise, we will continue to try to halt the
> controller, which will fail since there could still be EPs which are
> active.

Because we make sure ep0state won't advance beyond EP0_SETUP_PHASE, we
don't have to worry about DWC3_EP_DELAY_STOP.

> 
>     __dwc3_gadget_stop(dwc);
>     spin_unlock_irqrestore(&dwc->lock, flags);
> 
>     return dwc3_gadget_run_stop(dwc, false, false);
> }
> 
> I haven't run into this particular scenario yet, but thought I'd ask to
> see if there was some flow that I missed.
> 

Thanks for testing!

BR,
Thinh





[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux