From a5cc1057747a5aad255b61ad07784ab8b2590e65 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Wed, 11 Mar 2020 12:43:06 +0530 Subject: [PATCH 1/2] usb: dwc3: gadget: Issue soft reset as part of composition switch As part of composition switch, the device initiates disconnect from the host by clearing the run/stop bit of DCTL and initiates a connect by setting the run/stop bit. But during this entire scenario the core is not reset and there is a possibility of core caching the SETUP packets from the previous session and giving this to the driver once the run/stop bit is set leading to unintnented SETUP packets further leading to stall on endpoint 0. This caused the endpoint 0 to go into a bad state leading to enumeration failures. Also, the databook clearly mentions that the soft reset has to be issued before setting the run/stop bit to initialize a conenct after a disconnect. So, issue soft reset as part of composition switch to fix this issue. Change-Id: Id93bef710e7cdb67a6820cb4c9defecc5ad2a34e Signed-off-by: Sriharsha Allenki --- drivers/usb/dwc3/gadget.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c9e4bd51d802..37ad064b178c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2044,6 +2044,12 @@ done: /* phy sync delay as per data book */ msleep(50); + /* + * Soft reset clears the block on the doorbell, + * set it back to prevent unwanted writes to the doorbell. + */ + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, 0); + return 0; } @@ -2196,6 +2202,9 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) /* prevent pending bh to run later */ flush_work(&dwc->bh_work); + if (is_on) + dwc3_device_core_soft_reset(dwc); + spin_lock_irqsave(&dwc->lock, flags); if (dwc->ep0state != EP0_SETUP_PHASE) dbg_event(0xFF, "EP0 is not in SETUP phase\n", dwc->ep0state); From 92f0211c73dbde4f2d3b5437d1eadfbf273e6764 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Tue, 3 Mar 2020 14:14:01 +0530 Subject: [PATCH 2/2] usb: dwc3: gadget: Let GSI ep ops allocate TRBs for GSI eps The TRBs for GSI endpoints are allocated by the GSI ep ops. The TRB pool allocated in the alloc_trb_pool is never used and never freed leading to a dangling mapping in the IOMMU. Fix this by freeing up the allocated TRB pool as part of endpoint initialization. Change-Id: Ia0f7b8725f5206c3c52db8017770b855361b0751 Signed-off-by: Sriharsha Allenki --- drivers/usb/dwc3/gadget.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 37ad064b178c..20340ab2363a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2623,7 +2623,6 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { #define NUM_GSI_OUT_EPS 1 #define NUM_GSI_IN_EPS 2 - static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; @@ -2727,12 +2726,16 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total) /* Reserve EPs at the end for GSI */ if (!dep->direction && num > out_count - NUM_GSI_OUT_EPS - 1) { + /* Allocation of TRBs are handled by GSI EP ops. */ + dwc3_free_trb_pool(dep); idx = num - (out_count - NUM_GSI_OUT_EPS - 1); snprintf(dep->name, sizeof(dep->name), "gsi-epout%d", idx); dep->gsi = true; } else if (dep->direction && num > in_count - NUM_GSI_IN_EPS - 1) { + /* Allocation of TRBs are handled by GSI EP ops. */ + dwc3_free_trb_pool(dep); idx = num - (in_count - NUM_GSI_IN_EPS - 1); snprintf(dep->name, sizeof(dep->name), "gsi-epin%d", idx);