From d0acc50c6695d6b00e55c9fddb38be1e8c8452b8 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Tue, 13 Mar 2018 15:01:14 +0530 Subject: [PATCH] dwc3: gadget: Stop active transfer pending on ep0 out/in during reset if USB bus reset is received from Host in middle of control transfer request, SW needs to complete pending control transfer and setup core for next setup stage as per data book. Hence check ep0 state during reset interrupt handling and make sure active transfers on ep0 out/in endpoint are stopped by queuing ENDXFER command for that endpoint and restart ep0 out again to receive next setup packet. Change-Id: Idf8adf3c2416e7945d879bf88c321e1eea3c31d4 Signed-off-by: Vijayavardhan Vennapusa Signed-off-by: Hemant Kumar Signed-off-by: Jack Pham --- drivers/usb/dwc3/ep0.c | 9 +++++++-- drivers/usb/dwc3/gadget.c | 11 ++++++++++- drivers/usb/dwc3/gadget.h | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index a1fedc87d4a9..d9c5280f6548 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -1099,13 +1099,18 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, __dwc3_ep0_do_control_status(dwc, dep); } -static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) +void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; u32 cmd; int ret; - if (!dep->resource_index) + /* + * For status/DATA OUT stage, TRB will be queued on ep0 out + * endpoint for which resource index is zero. Hence allow + * queuing ENDXFER command for ep0 out endpoint. + */ + if (!dep->resource_index && dep->number) return; cmd = DWC3_DEPCMD_ENDTRANSFER; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8a68a0849136..60dd48ae88b9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3143,8 +3143,17 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) * that EP0 is in setup phase by issuing a stall * and restart if EP0 is not in setup phase. */ - if (dwc->ep0state != EP0_SETUP_PHASE) + if (dwc->ep0state != EP0_SETUP_PHASE) { + unsigned int dir; + + dbg_event(0xFF, "CONTRPEND", dwc->ep0state); + 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); + } dwc3_stop_active_transfers(dwc); dwc3_clear_stall_all_ep(dwc); diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 3cb1855dd844..828e0f71a5be 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -109,6 +109,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event); void dwc3_ep0_out_start(struct dwc3 *dwc); +void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep); void dwc3_ep0_stall_and_restart(struct dwc3 *dwc); int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);