usb: dwc3: Properly handle delayed status in ep_halt context
There are two ways of clearing the halt condition.
(1) host initiated through control transfer CLEAR_FEATURE(endpoint)
(2) device requesting UDC to clear the halt endpoint.
In (1), we stop the active transfer and wait for it before sending the
status response for the control transfer. So it involves delayed_response
i.e USB_GADGET_DELAYED_STATUS. In (2) there is no delayed response involved
since it is not a control transfer. However the current code does not
distinguish the part of handling delayed response upon ENDPONT command
completion. In both cases, we try to send the delayed response. This can
result into unexpected behavior when the delayed status is imposed for a
different reason which gets cleared by the case (2) like explained in
the below scenario.
1. Vendor specific control transfer returns USB_GADGET_DELAYED_STATUS.
2. DWC3 gadget sets dwc->delayed_status to '1'.
3. Another function driver issues a usb_ep_clear_halt() call.
4. DWC3 gadget issues dwc3_stop_active_transfer() and sets
DWC3_EP_PENDING_CLEAR_STALL.
5. EP command complete interrupt triggers for the end transfer, and
dwc3_ep0_send_delayed_status() is allowed to run, as delayed_status
is '1' due to step#1.
6. STATUS phase is sent, and delayed_status is cleared.
7. Vendor specific control transfer is finished being handled, and issues
usb_composite_setup_continue(). This results in queuing of a data
phase.
The dwc3_gadget_ep_set_halt() API invoked by the two cases above is
distinguished by the protocol flag. Cache this protocol flag so that
DWC3 gadget is aware of when the clear halt is due to a SETUP request
from the host versus when it is sourced from a function driver. This
allows for the EP command complete interrupt to know if it needs to
issue a delayed status phase.
Change-Id: I3b07bbda674103191a793319e3e2e09059eb2a25
Signed-off-by:
Elson Roy Serrao <quic_eserrao@quicinc.com>
Loading
Please register or sign in to comment