From patchwork Mon Oct 31 10:49:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felipe Balbi X-Patchwork-Id: 80156 Delivered-To: patch@linaro.org Received: by 10.80.142.83 with SMTP id 19csp66090edx; Mon, 31 Oct 2016 03:52:28 -0700 (PDT) X-Received: by 10.98.220.10 with SMTP id t10mr10954198pfg.47.1477911148670; Mon, 31 Oct 2016 03:52:28 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c22si8064156pfk.219.2016.10.31.03.52.28; Mon, 31 Oct 2016 03:52:28 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-usb-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-usb-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-usb-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S936454AbcJaKw0 (ORCPT + 4 others); Mon, 31 Oct 2016 06:52:26 -0400 Received: from mga07.intel.com ([134.134.136.100]:45308 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S936447AbcJaKw0 (ORCPT ); Mon, 31 Oct 2016 06:52:26 -0400 Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga105.jf.intel.com with ESMTP; 31 Oct 2016 03:52:25 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,426,1473145200"; d="scan'208";a="26014358" Received: from pipin.fi.intel.com (HELO localhost) ([10.237.68.37]) by orsmga004.jf.intel.com with ESMTP; 31 Oct 2016 03:52:23 -0700 From: Felipe Balbi To: Linux USB Cc: Baolin Wang , Felipe Balbi Subject: [PATCH 75/82] usb: dwc3: gadget: wait for End Transfer to complete Date: Mon, 31 Oct 2016 12:49:07 +0200 Message-Id: <20161031104914.1990-76-felipe.balbi@linux.intel.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20161031104914.1990-1-felipe.balbi@linux.intel.com> References: <20161031104914.1990-1-felipe.balbi@linux.intel.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Baolin Wang Instead of just delaying for 100us, we should actually wait for End Transfer Command Complete interrupt before moving on. Note that this should only be done if we're dealing with one of the core revisions that actually require the interrupt before moving on. [ felipe.balbi@linux.intel.com: minor improvements ] NYET-Signed-off-by: Baolin Wang Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 8 ++++++++ drivers/usb/dwc3/gadget.c | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 3 deletions(-) -- 2.10.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5fc437021ac7..0cb3b78d28b7 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -505,6 +506,7 @@ struct dwc3_event_buffer { * @endpoint: usb endpoint * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint + * @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete * @lock: spinlock for endpoint request queue traversal * @regs: pointer to first endpoint register * @trb_pool: array of transaction buffers @@ -530,6 +532,8 @@ struct dwc3_ep { struct list_head pending_list; struct list_head started_list; + wait_queue_head_t wait_end_transfer; + spinlock_t lock; void __iomem *regs; @@ -546,6 +550,7 @@ struct dwc3_ep { #define DWC3_EP_BUSY (1 << 4) #define DWC3_EP_PENDING_REQUEST (1 << 5) #define DWC3_EP_MISSED_ISOC (1 << 6) +#define DWC3_EP_END_TRANSFER_PENDING (1 << 7) /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN (1 << 31) @@ -1050,6 +1055,9 @@ struct dwc3_event_depevt { #define DEPEVT_TRANSFER_BUS_EXPIRY 2 u32 parameters:16; + +/* For Command Complete Events */ +#define DEPEVT_PARAMETER_CMD(n) (((n) & (0xf << 8)) >> 8) } __packed; /** diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3b53a5714df4..bc985f8571c6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -598,6 +598,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, reg |= DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); + init_waitqueue_head(&dep->wait_end_transfer); + if (usb_endpoint_xfer_control(desc)) return 0; @@ -772,6 +774,10 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) dep->name)) return 0; + if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) + wait_event(dep->wait_end_transfer, + !(dep->flags & DWC3_EP_END_TRANSFER_PENDING)); + spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_disable(dep); spin_unlock_irqrestore(&dwc->lock, flags); @@ -1782,13 +1788,30 @@ static int dwc3_gadget_start(struct usb_gadget *g, } static void __dwc3_gadget_stop(struct dwc3 *dwc) +__releases(&dwc->lock) __acquires(&dwc->lock) { + int epnum; + if (pm_runtime_suspended(dwc->dev)) return; dwc3_gadget_disable_irq(dwc); __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); + + for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { + struct dwc3_ep *dep = dwc->eps[epnum]; + + if (!(dep->flags & DWC3_EP_ENABLED)) + continue; + + if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + continue; + + wait_event_lock_irq(dep->wait_end_transfer, + !(dep->flags & DWC3_EP_END_TRANSFER_PENDING), + dwc->lock); + } } static int dwc3_gadget_stop(struct usb_gadget *g) @@ -2171,6 +2194,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, { struct dwc3_ep *dep; u8 epnum = event->endpoint_number; + u8 cmd; dep = dwc->eps[epnum]; @@ -2215,8 +2239,15 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, return; } break; - case DWC3_DEPEVT_RXTXFIFOEVT: case DWC3_DEPEVT_EPCMDCMPLT: + cmd = DEPEVT_PARAMETER_CMD(event->parameters); + + if (cmd == DWC3_DEPCMD_ENDTRANSFER) { + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; + wake_up_all(&dep->wait_end_transfer); + } + break; + case DWC3_DEPEVT_RXTXFIFOEVT: break; } } @@ -2269,7 +2300,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) dep = dwc->eps[epnum]; - if (!dep->resource_index) + if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) || + !dep->resource_index) return; /* @@ -2313,8 +2345,10 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) dep->resource_index = 0; dep->flags &= ~DWC3_EP_BUSY; - if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) { + dep->flags |= DWC3_EP_END_TRANSFER_PENDING; udelay(100); + } } static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)