From patchwork Mon Oct 31 11:38:36 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 80164 Delivered-To: patch@linaro.org Received: by 10.140.97.247 with SMTP id m110csp67235qge; Mon, 31 Oct 2016 04:39:03 -0700 (PDT) X-Received: by 10.98.68.218 with SMTP id m87mr48640788pfi.20.1477913943072; Mon, 31 Oct 2016 04:39:03 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id vt3si19375083pab.236.2016.10.31.04.39.02; Mon, 31 Oct 2016 04:39:03 -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; dkim=neutral (body hash did not verify) header.i=@linaro.org; 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; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S941124AbcJaLjA (ORCPT + 4 others); Mon, 31 Oct 2016 07:39:00 -0400 Received: from mail-pf0-f170.google.com ([209.85.192.170]:35016 "EHLO mail-pf0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1765863AbcJaLi7 (ORCPT ); Mon, 31 Oct 2016 07:38:59 -0400 Received: by mail-pf0-f170.google.com with SMTP id s8so75624671pfj.2 for ; Mon, 31 Oct 2016 04:38:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=JHUgYWR08YL5UG//V0yBe5lNIMUne5fhysNYSYKuKAI=; b=kgeFpW8aK4SH5SE+F8aFuIbAqk8Ual1AfrtV9cAqnucDkqZS5MkFO9773reGhXYVfv 6jvBK6ZrcZklyAacAO+tVKJ93UBXe8+yBxZAfaS2uD1c86T9Naq3L/cz3sxuatLfnNCe lkMcgw6sqxBe9e3/JUKY+M5w3GNiU0gk6FS0o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=JHUgYWR08YL5UG//V0yBe5lNIMUne5fhysNYSYKuKAI=; b=Bbgn1JT0lKDtt6c3nP3farv1/PepX1+TmvzOMvUDUUc/YjRloiuWeZWdUU7KuoxOua vkid5ciYYfXwbTpkj4lR92lS1XsyhLLnDe1F/yYqujSLwUSVkUPlxywqvvjtVfEO5Acg 7HK7eLJARiP84f1dD/I77NfWu52bXjUeQXL2HKM7CG6sGWTyQGMF0V7Z6QPGISIsyErB d6QOaZrBxT2sGWvRyjul6ry0A4PWpJQ4HBEiLHgZSAIe+NJSb+clwF+MEnWCae/Byj/V J+wGSJeD6Thfi4h17r6NaalxxoWbGjIEhk4Qnxl5V5a+EZMv3DryX7pUmYLsnKVdUtwl I1jg== X-Gm-Message-State: ABUngvcp/EEhNH6Ybi1ENqZVD9MBasjgZjjqAvIRxYRt2om5+0Uc5jNP6BgmyUiKOoZRUNmY X-Received: by 10.99.113.14 with SMTP id m14mr39608977pgc.57.1477913938236; Mon, 31 Oct 2016 04:38:58 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([175.111.195.49]) by smtp.gmail.com with ESMTPSA id w85sm23368192pfk.57.2016.10.31.04.38.55 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 31 Oct 2016 04:38:57 -0700 (PDT) From: Baolin Wang To: balbi@kernel.org Cc: gregkh@linuxfoundation.org, broonie@kernel.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, baolin.wang@linaro.org Subject: [PATCH v1] usb: dwc3: gadget: wait for End Transfer to complete Date: Mon, 31 Oct 2016 19:38:36 +0800 Message-Id: <6fdb5cd4216755f07bb1a1e5d081e269046c60c6.1476949020.git.baolin.wang@linaro.org> X-Mailer: git-send-email 1.7.9.5 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org 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 ] Signed-off-by: Baolin Wang --- drivers/usb/dwc3/core.h | 8 ++++++++ drivers/usb/dwc3/gadget.c | 47 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 4 deletions(-) -- 1.7.9.5 -- 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 23765a1..c5fd862 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -496,6 +497,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 @@ -521,6 +523,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; @@ -537,6 +541,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) @@ -1044,6 +1049,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 3722c90..018611d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -570,11 +570,14 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, dep->comp_desc = comp_desc; dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); 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; @@ -647,7 +650,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->endpoint.desc = NULL; dep->comp_desc = NULL; dep->type = 0; - dep->flags = 0; + dep->flags &= DWC3_EP_END_TRANSFER_PENDING; return 0; } @@ -1736,10 +1739,34 @@ static int dwc3_gadget_stop(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; + int epnum; spin_lock_irqsave(&dwc->lock, flags); __dwc3_gadget_stop(dwc); dwc->gadget_driver = NULL; + + for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { + struct dwc3_ep *dep = dwc->eps[epnum]; + + /* + * If the dwc3 core has been in suspend state, we will never get + * the command complete event, thus ignore. + */ + if (pm_runtime_suspended(dwc->dev)) + break; + + if (!dep) + 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); + } + spin_unlock_irqrestore(&dwc->lock, flags); free_irq(dwc->irq_gadget, dwc->ev_buf); @@ -2105,10 +2132,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, { struct dwc3_ep *dep; u8 epnum = event->endpoint_number; + u8 cmd; dep = dwc->eps[epnum]; - if (!(dep->flags & DWC3_EP_ENABLED)) + if (!(dep->flags & DWC3_EP_ENABLED) && + !(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) return; if (epnum == 0 || epnum == 1) { @@ -2180,6 +2209,13 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun", dep->name); break; case DWC3_DEPEVT_EPCMDCMPLT: + cmd = DEPEVT_PARAMETER_CMD(event->parameters); + + if (cmd == DWC3_DEPCMD_ENDTRANSFER) { + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; + wake_up(&dep->wait_end_transfer); + } + dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete"); break; } @@ -2233,7 +2269,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; /* @@ -2277,8 +2314,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_stop_active_transfers(struct dwc3 *dwc)