From patchwork Fri Oct 14 09:11:33 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: 77651 Delivered-To: patch@linaro.org Received: by 10.140.97.247 with SMTP id m110csp203221qge; Fri, 14 Oct 2016 02:12:18 -0700 (PDT) X-Received: by 10.66.54.107 with SMTP id i11mr14011998pap.168.1476436338076; Fri, 14 Oct 2016 02:12:18 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id x191si14341231pgd.120.2016.10.14.02.12.17; Fri, 14 Oct 2016 02:12:18 -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 S1752897AbcJNJMQ (ORCPT + 4 others); Fri, 14 Oct 2016 05:12:16 -0400 Received: from mail-pa0-f42.google.com ([209.85.220.42]:36177 "EHLO mail-pa0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751561AbcJNJMO (ORCPT ); Fri, 14 Oct 2016 05:12:14 -0400 Received: by mail-pa0-f42.google.com with SMTP id ry6so45977682pac.3 for ; Fri, 14 Oct 2016 02:12:14 -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=9lt4qMg9/GKrxxXo3iBDNKrQO7V87MAGQ0VYrnl1MPY=; b=NQvJOUKgVpuTJgXQCZ79okLzB9jvFCvRjsEYv709GH1/nvsJYDR9NQr+25GnOVd/L/ MaFDFv4sh9VzBDQo1y+Bd3XTVFEDfKG6jGuygWraaXNaJdaiudzlcwDWQFilAcDfyQLN kBNqG7nGvnbBKNWQH4fndliYwXbIUPSgaAARc= 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=9lt4qMg9/GKrxxXo3iBDNKrQO7V87MAGQ0VYrnl1MPY=; b=Q6JdHyibGMr3SE5YG3/jejoc+ozjKOg/6O1IIr2tTswm0QAxcHLz61B5NAiWkeCCST 1Y2yqjmUlVvM486cYF3tEpCENif9mj9ug5Cn8cLNfcFgShGxDAdgWb2HAdC6aRuUB4FI jdC2vNhzWYbMqrng1hOmt0NVqSPh/0Qx2uj/rtOulaVrZbkFjcBvjf4C154YLKzXbPBE ukMeWxVdYX+UFjG9Cdh/TAOgHRwY5pg3eQf+f/bFsKpq1It61gsDsJYClG07qVLg7VYN UmaWoC8cUJMIEOW980iGWMVI9thAiDaWQOwPtvJS7t3kWk08pLmv+CXuBp8WaWCqKdn9 NcVQ== X-Gm-Message-State: AA6/9RnszKXIIgxbxjmazot20tLLH/SFVykjFMZXdiiBn7mPNE5PPFsPyX0iC4OZSArhJVFr X-Received: by 10.66.78.193 with SMTP id d1mr14128633pax.4.1476436333970; Fri, 14 Oct 2016 02:12:13 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([175.111.195.49]) by smtp.gmail.com with ESMTPSA id y186sm25589240pfy.58.2016.10.14.02.12.11 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 14 Oct 2016 02:12: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 v4] usb: dwc3: Wait for control tranfer completed when stopping gadget Date: Fri, 14 Oct 2016 17:11:33 +0800 Message-Id: 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 When we change the USB function with configfs dynamically, we possibly met this situation: one core is doing the control transfer, another core is trying to unregister the USB gadget from userspace, we must wait for completing this control tranfer, or it will hang the controller to set the DEVCTRLHLT flag. Signed-off-by: Baolin Wang --- Changes since v3: - Remove the patch 1 which will cause start gadget failed. - Remove try_again and refactor the code. Changes since v2: - Move disconnect checking into dwc3_send_gadget_ep_cmd(). - Rename completion name and issue complete() at one place. - Move completion initialization into dwc3_gadget_init(). Changes since v1: - Split into 2 separate ptaches. - Choose complete mechanism instead of polling. --- drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/ep0.c | 2 ++ drivers/usb/dwc3/gadget.c | 28 +++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) -- 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 b2317e7..23765a1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -745,6 +745,7 @@ struct dwc3_scratchpad_array { * @ep0_usb_req: dummy req used while handling STD USB requests * @ep0_bounce_addr: dma address of ep0_bounce * @scratch_addr: dma address of scratchbuf + * @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing * @dev: pointer to our struct device * @xhci: pointer to our xHCI child @@ -843,6 +844,7 @@ struct dwc3 { dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; struct dwc3_request ep0_usb_req; + struct completion ep0_in_setup; /* device lock */ spinlock_t lock; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index fe79d77..06c167a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -311,6 +311,8 @@ void dwc3_ep0_out_start(struct dwc3 *dwc) ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8, DWC3_TRBCTL_CONTROL_SETUP, false); WARN_ON(ret < 0); + + complete(&dwc->ep0_in_setup); } static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1783406..3722c90 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1434,6 +1434,13 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (pm_runtime_suspended(dwc->dev)) return 0; + /* + * Per databook, when we want to stop the gadget, if a control transfer + * is still in process, complete it and get the core into setup phase. + */ + if (!is_on && dwc->ep0state != EP0_SETUP_PHASE) + return -EBUSY; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) { if (dwc->revision <= DWC3_REVISION_187A) { @@ -1480,11 +1487,28 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; - int ret; + int ret = 0; is_on = !!is_on; spin_lock_irqsave(&dwc->lock, flags); + if (!is_on && !pm_runtime_suspended(dwc->dev) && + dwc->ep0state != EP0_SETUP_PHASE) { + reinit_completion(&dwc->ep0_in_setup); + ret = -EBUSY; + } + spin_unlock_irqrestore(&dwc->lock, flags); + + if (ret == -EBUSY) { + ret = wait_for_completion_timeout(&dwc->ep0_in_setup, + msecs_to_jiffies(500)); + if (ret == 0) { + dev_err(dwc->dev, "timeout to wait for setup phase.\n"); + return -ETIMEDOUT; + } + } + + spin_lock_irqsave(&dwc->lock, flags); ret = dwc3_gadget_run_stop(dwc, is_on, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2911,6 +2935,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err4; } + init_completion(&dwc->ep0_in_setup); + dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true;