From patchwork Thu Oct 12 20:11:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 10002771 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 D121C60216 for ; Thu, 12 Oct 2017 20:12:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C40B428E98 for ; Thu, 12 Oct 2017 20:12:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B8A6628EA0; Thu, 12 Oct 2017 20:12:33 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4EBB928E98 for ; Thu, 12 Oct 2017 20:12:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756152AbdJLUMH (ORCPT ); Thu, 12 Oct 2017 16:12:07 -0400 Received: from mail-pf0-f180.google.com ([209.85.192.180]:57084 "EHLO mail-pf0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755754AbdJLULq (ORCPT ); Thu, 12 Oct 2017 16:11:46 -0400 Received: by mail-pf0-f180.google.com with SMTP id b85so6428405pfj.13 for ; Thu, 12 Oct 2017 13:11:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mOg+tjMIGdtyxfe97OfZairUNZ/ygZrHu1ZczlsOWE8=; b=XdD6Cjddt6/688hFbJDUQ/g/TsGRPnrFA15Q7MXivRHm/shMpefNchYKR4rMqO+MlT pzaZEDyaJ84Dc/9quLiFcKtcu3uVG+hTL9V1p+h6EF+KfkmK24L+Szs/JZEgUyDSOGF2 cpWGfuK3Eax93DkVxlYPB41UCpiXkcyy/z68M= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mOg+tjMIGdtyxfe97OfZairUNZ/ygZrHu1ZczlsOWE8=; b=iUCGUJsqhv72kqjbkrbhnJiYnw9YEmUutFz2RtTTlGNEgQukqCgJw/i5Jez+Gkwr1T 1KBkelLaETtzimhLiw/m2qwMXJW7g8RJrexz5C5UhwMfLd9Uqyc0YtiV9INLsRUHprxJ 2kuORunU53ayQKHzK4xBooR3UY2loh14aUtqLXjdeQgO8hGQLT+EBhUpZp9DE/cnJpfg 0wa8UyI8WDBSYs197KfzCG35Kbkt4wkEXfPPlgW/Z5PBkRCRT6qQZNIJll+tBWt3ejUO FmakoG4oHj3wdmHRSIsrZxdjQtwf7g+F2DWxtn/cTV0SSz/VidJ5zXx6g6coZ2EpnR6p 0DUQ== X-Gm-Message-State: AMCzsaWhaPuP1Nuxw6A2jjFRIsCcAW2vRyBdTJIDrqgd0oBGtGgLa2Wg jWVB3bYG3rX0H/kgmFJQBPgpZg== X-Google-Smtp-Source: AOwi7QCMxX+a2es/K2LnuKbEVptrPJrtexbMXp73UMIVBOjG5uCNGY4kLsEYkfAtwnQsy9xMeIzYnQ== X-Received: by 10.98.17.202 with SMTP id 71mr3155074pfr.142.1507839105621; Thu, 12 Oct 2017 13:11:45 -0700 (PDT) Received: from tictac.mtv.corp.google.com ([172.22.112.154]) by smtp.gmail.com with ESMTPSA id l3sm29749635pgn.36.2017.10.12.13.11.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 12 Oct 2017 13:11:44 -0700 (PDT) From: Douglas Anderson To: jh80.chung@samsung.com, ulf.hansson@linaro.org, shawn.lin@rock-chips.com Cc: xzy.xu@rock-chips.com, amstan@chromium.org, linux-rockchip@lists.infradead.org, briannorris@chromium.org, linux-samsung-soc@vger.kernel.org, kernel@esmil.dk, Douglas Anderson , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 5/5] mmc: dw_mmc: Cleanup the DTO timer like the CTO one Date: Thu, 12 Oct 2017 13:11:18 -0700 Message-Id: <20171012201118.23570-6-dianders@chromium.org> X-Mailer: git-send-email 2.15.0.rc0.271.g36b669edcc-goog In-Reply-To: <20171012201118.23570-1-dianders@chromium.org> References: <20171012201118.23570-1-dianders@chromium.org> Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The recent CTO timer introduced in commit 03de19212ea3 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme") was causing observable problems due to race conditions. Previous patches have fixed those race conditions. It can be observed that these same race conditions ought to be theoretically possible with the DTO timer too though they are massively less likely to happen because the data timeout is always set to 0xffffff right now. That means even at a 200 MHz card clock we were arming the DTO timer for 94 ms: >>> (0xffffff * 1000. / 200000000) + 10 93.886075 We always also were setting the DTO timer _after_ starting the transfer, unlike how the old code was seting the CTO timer. In any case, even though the DTO timer is much less likely to have races, it still makes sense to add code to handle it _just in case_. Signed-off-by: Douglas Anderson Reviewed-by: Shawn Lin --- Changes in v2: - Cleanup the DTO timer new for v2 drivers/mmc/host/dw_mmc.c | 54 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 6bc87b1385a9..bc0808615431 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1950,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host) /* add a bit spare time */ drto_ms += 10; - mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms)); + spin_lock_irqsave(&host->irq_lock, irqflags); + if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events)) + mod_timer(&host->dto_timer, + jiffies + msecs_to_jiffies(drto_ms)); + spin_unlock_irqrestore(&host->irq_lock, irqflags); } static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host) @@ -1971,6 +1975,18 @@ static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host) return true; } +static bool dw_mci_clear_pending_data_complete(struct dw_mci *host) +{ + if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events)) + return false; + + /* Extra paranoia just like dw_mci_clear_pending_cmd_complete() */ + WARN_ON(del_timer_sync(&host->dto_timer)); + clear_bit(EVENT_DATA_COMPLETE, &host->pending_events); + + return true; +} + static void dw_mci_tasklet_func(unsigned long priv) { struct dw_mci *host = (struct dw_mci *)priv; @@ -2112,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv) /* fall through */ case STATE_DATA_BUSY: - if (!test_and_clear_bit(EVENT_DATA_COMPLETE, - &host->pending_events)) { + if (!dw_mci_clear_pending_data_complete(host)) { /* * If data error interrupt comes but data over * interrupt doesn't come within the given time. @@ -2683,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } if (pending & SDMMC_INT_DATA_OVER) { + spin_lock_irqsave(&host->irq_lock, irqflags); + del_timer(&host->dto_timer); mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); @@ -2695,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } set_bit(EVENT_DATA_COMPLETE, &host->pending_events); tasklet_schedule(&host->tasklet); + + spin_unlock_irqrestore(&host->irq_lock, irqflags); } if (pending & SDMMC_INT_RXDR) { @@ -3044,7 +3063,31 @@ static void dw_mci_cto_timer(unsigned long arg) static void dw_mci_dto_timer(unsigned long arg) { struct dw_mci *host = (struct dw_mci *)arg; + unsigned long irqflags; + u32 pending; + + spin_lock_irqsave(&host->irq_lock, irqflags); + /* + * The DTO timer is much longer than the CTO timer, so it's even less + * likely that we'll these cases, but it pays to be paranoid. + */ + pending = mci_readl(host, MINTSTS); /* read-only mask reg */ + if (pending & SDMMC_INT_DATA_OVER) { + /* The interrupt should fire; no need to act but we can warn */ + dev_warn(host->dev, "Unexpected data interrupt latency\n"); + goto exit; + } + if (test_bit(EVENT_DATA_COMPLETE, &host->pending_events)) { + /* Presumably interrupt handler couldn't delete the timer */ + dev_warn(host->dev, "DTO timeout when already completed\n"); + goto exit; + } + + /* + * Continued paranoia to make sure we're in the state we expect. + * This paranoia isn't really justified but it seems good to be safe. + */ switch (host->state) { case STATE_SENDING_DATA: case STATE_DATA_BUSY: @@ -3059,8 +3102,13 @@ static void dw_mci_dto_timer(unsigned long arg) tasklet_schedule(&host->tasklet); break; default: + dev_warn(host->dev, "Unexpected data timeout, state %d\n", + host->state); break; } + +exit: + spin_unlock_irqrestore(&host->irq_lock, irqflags); } #ifdef CONFIG_OF