From patchwork Tue Oct 18 01:56:24 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Boyd X-Patchwork-Id: 9381141 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 29D9D6086B for ; Tue, 18 Oct 2016 02:03:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 123AF28CDF for ; Tue, 18 Oct 2016 02:03:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 05D3628CE5; Tue, 18 Oct 2016 02:03:10 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id CE41D28CDF for ; Tue, 18 Oct 2016 02:03:08 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bwJic-00048O-JP; Tue, 18 Oct 2016 02:01:30 +0000 Received: from mail-pf0-x22d.google.com ([2607:f8b0:400e:c00::22d]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bwJeS-0008LW-8h for linux-arm-kernel@lists.infradead.org; Tue, 18 Oct 2016 01:57:15 +0000 Received: by mail-pf0-x22d.google.com with SMTP id 128so86389145pfz.0 for ; Mon, 17 Oct 2016 18:56:51 -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:in-reply-to:references; bh=COOwwkgttUVRkwISLwiwFjbhzNM6eWbJrrHHJvgjTic=; b=EF92Dj2N5NqVa+tPWq4BQCQu6oKQqLAw4SeSfxg+X171zUVQZS78uWNMPXWf9Q/Wi0 0GInDRtpq+BMdFiMx8iOKwE0eRX80XfoeFv4BM24rqAKw1rpTxsMMVhlHNt/Yr7ISToC YGm4FZF7qiiMoq32rSTTIt+MS2wjUqdNt4qfY= 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:in-reply-to :references; bh=COOwwkgttUVRkwISLwiwFjbhzNM6eWbJrrHHJvgjTic=; b=lcubb76OGsOozPqLYXM0NtTafDkIRIgMSioj8JqMkXg3J0mqzdV7Hviho6V0ML9pr6 onEPDC0i8C3JH9X9D0VbiNA7Z9VCuIBI3uANvsEsq5UqC+/pX2PWDdbfE7SxNn6vsJT+ j+nH60NoTP4HvMuJY8XXSWz5MGAEfvmyWME7PSk0RDddjCFrYo9E88aMMJrKC0AC4TO7 6JKFOW4OzYV4R5uscCQEOJ3z5Aq5I4++PTSDZ/oFWuP6sTNxVc8w9EzaeJ7Zgw7tCA3T DicrICEUd/7+rFswWnieyTjCP1TWljNr0rEV19iBLcuDebHqOT6SBZF0XTLseHthGHrB HDFA== X-Gm-Message-State: AA6/9RmGjEnuGBDK6+94l18pFFQcCfOzkQrICOSHjFP8sWSjYk1Gp8WsCrNzBMMKWe0jDmMI X-Received: by 10.99.53.193 with SMTP id c184mr542420pga.169.1476755811469; Mon, 17 Oct 2016 18:56:51 -0700 (PDT) Received: from localhost.localdomain (i-global254.qualcomm.com. [199.106.103.254]) by smtp.gmail.com with ESMTPSA id j6sm51020430paa.44.2016.10.17.18.56.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 17 Oct 2016 18:56:50 -0700 (PDT) From: Stephen Boyd To: linux-usb@vger.kernel.org Subject: [PATCH v5 11/23] usb: chipidea: Emulate OTGSC interrupt enable path Date: Mon, 17 Oct 2016 18:56:24 -0700 Message-Id: <20161018015636.11701-12-stephen.boyd@linaro.org> X-Mailer: git-send-email 2.10.0.297.gf6727b0 In-Reply-To: <20161018015636.11701-1-stephen.boyd@linaro.org> References: <20161018015636.11701-1-stephen.boyd@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161017_185712_456326_EB494416 X-CRM114-Status: GOOD ( 21.99 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Felipe Balbi , Arnd Bergmann , Neil Armstrong , linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, Bjorn Andersson , Peter Chen , Greg Kroah-Hartman , Andy Gross , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP In the case of an extcon-usb-gpio device being used with the chipidea driver we'll sometimes miss the BSVIS event in the OTGSC register. Consider the case where we don't have a cable attached and the id pin is indicating "host" mode. When we plug in the usb cable for "device" mode a gpio goes high and indicates that we should do the role switch and that vbus is high. When we're in "host" mode the OTGSC register doesn't have BSVIE set. The following scenario can happen: CPU0 ---- ci_cable_notifier() update id cable state ci_irq() if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) { // true ci->id_event = true; ci_otg_queue_work() schedule() // same task as before ci_cable_notifier() update vbus cable state ci_irq() if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) // false return IRQ_NONE ci_otg_work() // switch task to the workqueue now if (ci->id_event) ci_handle_id_switch() ci_role_stop() host_stop() hw_wait_vbus_lower_bsv(ci); // this times out because vbus is already set ci_role_start() udc_id_switch_for_device() hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, OTGSC_BSVIS | OTGSC_BSVIE); At this point, we don't replay the vbus connect event because the vbus event has already happened. This causes things like gadget instances to never see vbus appear, and thus the gadget is never started. Furthermore, we see timeout messages like: timeout waiting for 0000800 in OTGSC Let's workaround this by skiping the wait for BSV when we're using an extcon for the vbus notification and let's properly emulate the BSVIS event that would happen when we enable the vbus interrupt while enabling "device" mode. Cc: Peter Chen Cc: Greg Kroah-Hartman Signed-off-by: Stephen Boyd --- drivers/usb/chipidea/ci.h | 2 ++ drivers/usb/chipidea/core.c | 23 +++++++++++++++++------ drivers/usb/chipidea/otg.c | 31 ++++++++++++++++++++++++------- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 59e22389c10b..e099b8bc79e2 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -437,6 +437,8 @@ static inline void ci_ulpi_exit(struct ci_hdrc *ci) { } static inline int ci_ulpi_resume(struct ci_hdrc *ci) { return 0; } #endif +irqreturn_t __ci_irq(int irq, struct ci_hdrc *ci); + u32 hw_read_intr_enable(struct ci_hdrc *ci); u32 hw_read_intr_status(struct ci_hdrc *ci); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 83bc2f2dd6a8..d1ae9a03e0fa 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -524,9 +524,8 @@ int hw_device_reset(struct ci_hdrc *ci) return 0; } -static irqreturn_t ci_irq(int irq, void *data) +irqreturn_t __ci_irq(int irq, struct ci_hdrc *ci) { - struct ci_hdrc *ci = data; irqreturn_t ret = IRQ_NONE; u32 otgsc = 0; @@ -570,9 +569,20 @@ static irqreturn_t ci_irq(int irq, void *data) return IRQ_HANDLED; } - /* Handle device/host interrupt */ - if (ci->role != CI_ROLE_END) - ret = ci_role(ci)->irq(ci); + return ret; +} + +static irqreturn_t ci_irq(int irq, void *data) +{ + irqreturn_t ret; + struct ci_hdrc *ci = data; + + ret = __ci_irq(irq, ci); + if (ret == IRQ_NONE) { + /* Handle device/host interrupt */ + if (ci->role != CI_ROLE_END) + ret = ci_role(ci)->irq(ci); + } return ret; } @@ -586,7 +596,8 @@ static int ci_cable_notifier(struct notifier_block *nb, unsigned long event, cbl->connected = event; cbl->changed = true; - ci_irq(ci->irq, ci); + __ci_irq(ci->irq, ci); + return NOTIFY_DONE; } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 695f3fe3ae21..f4a21ade1901 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -84,36 +84,44 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) { struct ci_hdrc_cable *cable; + bool raise_irq = false; cable = &ci->platdata->vbus_extcon; if (!IS_ERR(cable->edev)) { - if (data & mask & OTGSC_BSVIS) - cable->changed = false; - /* Don't enable vbus interrupt if using external notifier */ if (data & mask & OTGSC_BSVIE) { + if (cable->enabled == false && cable->changed == true) + raise_irq = true; cable->enabled = true; data &= ~OTGSC_BSVIE; } else if (mask & OTGSC_BSVIE) { cable->enabled = false; } + + if (data & mask & OTGSC_BSVIS && !raise_irq) + cable->changed = false; } cable = &ci->platdata->id_extcon; if (!IS_ERR(cable->edev)) { - if (data & mask & OTGSC_IDIS) - cable->changed = false; - /* Don't enable id interrupt if using external notifier */ if (data & mask & OTGSC_IDIE) { + if (cable->enabled == false && cable->changed == true) + raise_irq = true; cable->enabled = true; data &= ~OTGSC_IDIE; } else if (mask & OTGSC_IDIE) { cable->enabled = false; } + + if (data & mask & OTGSC_IDIS && !raise_irq) + cable->changed = false; } hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); + + if (raise_irq) + __ci_irq(ci->irq, ci); } /** @@ -175,7 +183,16 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) ci_role_stop(ci); - if (role == CI_ROLE_GADGET) + /* + * BSV could be set "immediately" if we're using extcon for + * VBUS because sometimes it's a single GPIO for ID and VBUS + * like in the case of extcon-usb-gpio. In that case we ignore + * waiting for a BSV transition. Really we can't tell when BSV + * is low and the cable is connected, all we know is that the + * BSV is high when we update BSV state. + */ + if (role == CI_ROLE_GADGET && + IS_ERR(ci->platdata->vbus_extcon.edev)) /* * wait vbus lower than OTGSC_BSV before connecting * to host