From patchwork Thu Sep 8 11:36:12 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: 75772 Delivered-To: patch@linaro.org Received: by 10.140.106.11 with SMTP id d11csp794561qgf; Thu, 8 Sep 2016 04:37:06 -0700 (PDT) X-Received: by 10.98.52.71 with SMTP id b68mr70576838pfa.147.1473334623655; Thu, 08 Sep 2016 04:37:03 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m6si5571479pay.162.2016.09.08.04.37.03; Thu, 08 Sep 2016 04:37: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 S932223AbcIHLhB (ORCPT + 4 others); Thu, 8 Sep 2016 07:37:01 -0400 Received: from mail-pf0-f170.google.com ([209.85.192.170]:35262 "EHLO mail-pf0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757940AbcIHLhA (ORCPT ); Thu, 8 Sep 2016 07:37:00 -0400 Received: by mail-pf0-f170.google.com with SMTP id w87so17491340pfk.2 for ; Thu, 08 Sep 2016 04:37:00 -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=th9yfsQ4IE7Y5x4ocgPjF2tcxdU5Z/FbLRd5HgR0gyI=; b=Pc5riWOxhLl3bh16LUH7lbvr3LuqPAQ9vskvix/Hi5gJTtKykSt0QtobCj6Upf6wXa 3SGJrJy2+e18LEH9GRB8/4BKMY4FdaM6JKfSWZkt0Z0EGuWOGQ8iU2PRwyPnmAeIISdT 0JnDPbMyraOmFe5BAnQjRfbtnY6iidXPBQSps= 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=th9yfsQ4IE7Y5x4ocgPjF2tcxdU5Z/FbLRd5HgR0gyI=; b=IIavxDlCv8sQ2SxYlVTp6VlptOz2Xb3JaMmTyiN35K/GO8UOk7ESlIvlzVP99h5HO5 rEC0tSeZreCJXQmSernMQf41yph4aJ9I5TuhviSNkKGQ9ZeqLVrydfK5RQMoX5J3+5BO JoQcETkYE1bz6VbRX6N8kwwaQNXLmRnJIrIGfNIdCCKYpizFvgoD8jNCLIiCDbKZgrld j9q3jgrLnvGgbcsjOzcI/suqCL5pYjBdnT7lGBK+493T0Wx2yzItppUMpCz9lOQOFRqL oYXiDTzdCBaeCd9YNHTIhXVCiM+PCfnstATn8nTjAWsxpu9A98qCW8zKaT30wIZzXenq wWKw== X-Gm-Message-State: AE9vXwNlpOcYTG7k3hdxsx4zgfs0lMtt9cY+wTsZeLMYanLfCC0KLfByE24Xd+YVz+kLu2Tk X-Received: by 10.98.192.21 with SMTP id x21mr28410565pff.32.1473334619678; Thu, 08 Sep 2016 04:36:59 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([175.111.195.49]) by smtp.gmail.com with ESMTPSA id o80sm19902558pfi.32.2016.09.08.04.36.56 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 08 Sep 2016 04:36:58 -0700 (PDT) From: Baolin Wang To: balbi@kernel.org, gregkh@linuxfoundation.org Cc: peter@hurleysoftware.com, broonie@kernel.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, baolin.wang@linaro.org Subject: [PATCH] usb: dwc3: gadget: Add disconnect checking when changing function dynamically Date: Thu, 8 Sep 2016 19:36:12 +0800 Message-Id: <2cb239ba53679a6fae1f4e1f14968e63fcd59e6b.1473334354.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 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. Also adding some disconnect checking to avoid queuing any requests when the gadget is stopped. Signed-off-by: Baolin Wang --- drivers/usb/dwc3/ep0.c | 8 ++++++++ drivers/usb/dwc3/gadget.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 5 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/ep0.c b/drivers/usb/dwc3/ep0.c index fe79d77..11519d7 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -228,6 +228,14 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int ret; spin_lock_irqsave(&dwc->lock, flags); + if (dwc->pullups_connected == false) { + dwc3_trace(trace_dwc3_ep0, + "queuing request %p to %s when gadget is disconnected", + request, dep->name); + ret = -ESHUTDOWN; + goto out; + } + if (!dep->endpoint.desc) { dwc3_trace(trace_dwc3_ep0, "trying to queue request %p to disabled %s", diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1783406..bbac8f5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1040,6 +1040,13 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) struct dwc3 *dwc = dep->dwc; int ret; + if (dwc->pullups_connected == false) { + dwc3_trace(trace_dwc3_gadget, + "queuing request %p to %s when gadget is disconnected", + &req->request, dep->endpoint.name); + return -ESHUTDOWN; + } + if (!dep->endpoint.desc) { dwc3_trace(trace_dwc3_gadget, "trying to queue request %p to disabled %s", @@ -1434,6 +1441,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) { @@ -1481,12 +1495,20 @@ 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 timeout = 500; is_on = !!is_on; - spin_lock_irqsave(&dwc->lock, flags); - ret = dwc3_gadget_run_stop(dwc, is_on, false); - spin_unlock_irqrestore(&dwc->lock, flags); + do { + spin_lock_irqsave(&dwc->lock, flags); + ret = dwc3_gadget_run_stop(dwc, is_on, false); + spin_unlock_irqrestore(&dwc->lock, flags); + + if (ret != -EBUSY) + break; + + udelay(10); + } while (--timeout); return ret; } @@ -1990,7 +2012,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, * dwc3_gadget_giveback(). If that happens, we're just gonna return 1 * early on so DWC3_EP_BUSY flag gets cleared */ - if (!dep->endpoint.desc) + if (!dep->endpoint.desc || dwc->pullups_connected == false) return 1; if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && @@ -2064,7 +2086,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, * dwc3_gadget_giveback(). If that happens, we're just gonna return 1 * early on so DWC3_EP_BUSY flag gets cleared */ - if (!dep->endpoint.desc) + if (!dep->endpoint.desc || dwc->pullups_connected == false) return; if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {