From patchwork Tue Nov 1 05:51:56 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: 80308 Delivered-To: patch@linaro.org Received: by 10.140.97.247 with SMTP id m110csp470204qge; Mon, 31 Oct 2016 22:52:23 -0700 (PDT) X-Received: by 10.99.120.75 with SMTP id t72mr2592503pgc.17.1477979543648; Mon, 31 Oct 2016 22:52:23 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t5si2278514pgj.143.2016.10.31.22.52.23; Mon, 31 Oct 2016 22:52:23 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1163053AbcKAFwS (ORCPT + 27 others); Tue, 1 Nov 2016 01:52:18 -0400 Received: from mail-pf0-f182.google.com ([209.85.192.182]:35555 "EHLO mail-pf0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161187AbcKAFwP (ORCPT ); Tue, 1 Nov 2016 01:52:15 -0400 Received: by mail-pf0-f182.google.com with SMTP id s8so89393828pfj.2 for ; Mon, 31 Oct 2016 22:52:15 -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=XiXVqhJ2h5c/EhMelLZBe3CjwiStpmzY+iBZ0Iwji04=; b=MQjfxDBUWj6co45/Mm3dZHkJxgwe3Xap+KogmOA3U2++O4YqYIWZXc1UA9IlmyYQgi yBybPfD4tBWHkLnXK0sIZfsPO9XBLkFTTmPtVKbZU2I8HmYBQ6tAynLX1CGcDSboRGwD XrqWHVUJpfrfTmeRtcNE00WIOZd8R0Av8bR9w= 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=XiXVqhJ2h5c/EhMelLZBe3CjwiStpmzY+iBZ0Iwji04=; b=Btb4B7DJ8t6rQV19ksq0HveA+7oi7kUT2QobY0gASxcqPeoicBvc6TXEbab0YuKVay NtqyBnCXrhGAH2W5Pen8I/m5slWmMxFb1D3qaEqykp6Ck3wlngQppULNDcRQBIHiLuNZ 5ZbuwczAJDX6XXOnuKB+bv2SbhrfXy5K1AOQfsqTH/8/MOoCW1n1LqxKNTGIpQ9edWOK wUUnJX52LNhxtKJfgIWgXJytOh25G4apmUmKxAQCJJBtklcsEiJ4PiDR4NDE971k9tBm brI7Ttq2D4PVUY1KR92uhTeD9Hr0lLrMfUKthrnI0YwQoprcoWudE7MJ40vk4Hi19Xzr 3CQw== X-Gm-Message-State: ABUngvfVjEUGHr4jHUzKIK/FmzjFLWf9q3XkPPFIiRYdZXKrB+uUtqF9dPQ/u7NrhEgAa42l X-Received: by 10.99.246.17 with SMTP id m17mr15947050pgh.134.1477979534538; Mon, 31 Oct 2016 22:52:14 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([175.111.195.49]) by smtp.gmail.com with ESMTPSA id u127sm39318207pfu.21.2016.10.31.22.52.11 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 31 Oct 2016 22:52:13 -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 v2] usb: dwc3: gadget: wait for End Transfer to complete Date: Tue, 1 Nov 2016 13:51:56 +0800 Message-Id: X-Mailer: git-send-email 1.7.9.5 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@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 --- Changes since v1: - Move the suspend checking to right place to avoid checking twice. --- drivers/usb/dwc3/core.h | 8 ++++++++ drivers/usb/dwc3/gadget.c | 49 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 4 deletions(-) -- 1.7.9.5 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..e248bd3 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,12 +1739,38 @@ 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; + + /* + * 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)) { + spin_unlock_irqrestore(&dwc->lock, flags); + goto out; + } + + for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { + struct dwc3_ep *dep = dwc->eps[epnum]; + + 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); +out: free_irq(dwc->irq_gadget, dwc->ev_buf); return 0; @@ -2105,10 +2134,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 +2211,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 +2271,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 +2316,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)