This is a note to let you know that I've just added the patch titled usb: dwc3: gadget: Submit endxfer command if delayed during disconnect to the 5.15-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: usb-dwc3-gadget-submit-endxfer-command-if-delayed-du.patch and it can be found in the queue-5.15 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. commit bdce6e89daa1411beecbe033786d22487f003c9a Author: Wesley Cheng <quic_wcheng@xxxxxxxxxxx> Date: Thu Sep 1 12:36:25 2022 -0700 usb: dwc3: gadget: Submit endxfer command if delayed during disconnect [ Upstream commit 8422b769fa46bd429dc0f324012629a4691f0dd9 ] During a cable disconnect sequence, if ep0state is not in the SETUP phase, then nothing will trigger any pending end transfer commands. Force stopping of any pending SETUP transaction, and move back to the SETUP phase. Reviewed-by: Thinh Nguyen <Thinh.Nguyen@xxxxxxxxxxxx> Signed-off-by: Wesley Cheng <quic_wcheng@xxxxxxxxxxx> Link: https://lore.kernel.org/r/20220901193625.8727-6-quic_wcheng@xxxxxxxxxxx Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Stable-dep-of: 730e12fbec53 ("usb: dwc3: gadget: Handle EP0 request dequeuing properly") Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index ba1b2e70b351..c61b6f49701a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3739,13 +3739,24 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_INITU2ENA; dwc3_gadget_dctl_write_safe(dwc, reg); + dwc->connected = false; + dwc3_disconnect_gadget(dwc); dwc->gadget->speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); - dwc->connected = false; + if (dwc->ep0state != EP0_SETUP_PHASE) { + unsigned int dir; + + dir = !!dwc->ep0_expect_in; + if (dwc->ep0state == EP0_DATA_PHASE) + dwc3_ep0_end_control_data(dwc, dwc->eps[dir]); + else + dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]); + dwc3_ep0_stall_and_restart(dwc); + } } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)