From patchwork Tue Jul 11 09:38:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Lin X-Patchwork-Id: 9834329 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 174B960325 for ; Tue, 11 Jul 2017 09:39:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 07F0C2766D for ; Tue, 11 Jul 2017 09:39:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EF935282EC; Tue, 11 Jul 2017 09:39:37 +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, RCVD_IN_DNSWL_HI, RCVD_IN_SBL autolearn=ham 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 26E202766D for ; Tue, 11 Jul 2017 09:39:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753195AbdGKJjg (ORCPT ); Tue, 11 Jul 2017 05:39:36 -0400 Received: from lucky1.263xmail.com ([211.157.147.132]:46532 "EHLO lucky1.263xmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751124AbdGKJjf (ORCPT ); Tue, 11 Jul 2017 05:39:35 -0400 Received: from shawn.lin?rock-chips.com (unknown [192.168.167.153]) by lucky1.263xmail.com (Postfix) with ESMTP id 2D39B6440D; Tue, 11 Jul 2017 17:39:09 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 1 X-MAIL-DELIVERY: 0 X-KSVirus-check: 0 X-ABS-CHECKED: 4 Received: from localhost.localdomain (localhost [127.0.0.1]) by smtp.263.net (Postfix) with ESMTPA id EF85F3D0; Tue, 11 Jul 2017 17:39:02 +0800 (CST) X-RL-SENDER: shawn.lin@rock-chips.com X-FST-TO: jh80.chung@samsung.com X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: shawn.lin@rock-chips.com X-UNIQUE-TAG: X-ATTACHMENT-NUM: 0 X-SENDER: lintao@rock-chips.com X-DNS-TYPE: 0 Received: from localhost.localdomain (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith ESMTP id 15128VYCK1R; Tue, 11 Jul 2017 17:39:07 +0800 (CST) From: Shawn Lin To: Jaehoon Chung , Ulf Hansson Cc: linux-mmc@vger.kernel.org, Ziyuan Xu , Heiko Stuebner , linux-rockchip@lists.infradead.org, Addy Ke , Shawn Lin Subject: [PATCH] mmc: dw_mmc: introduce timer for broken command transfer over scheme Date: Tue, 11 Jul 2017 17:38:37 +0800 Message-Id: <1499765917-228806-1-git-send-email-shawn.lin@rock-chips.com> X-Mailer: git-send-email 1.9.1 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 From: Addy Ke Per the databook of designware mmc controller 2.70a, table 3-2, cmd done interrupt should be fired as soon as the the cmd is sent via cmd line. And the response timeout interrupt should be generated unconditioinally as well if the controller doesn't receive the resp. However that doesn't seem to meet the fact of rockchip specified Soc platforms using dwmmc. We have continuously found the the cmd done or response timeout interrupt missed somehow which took us a long time to understand what was happening. Finally we narrow down the root to the reconstruction of sample circuit for dwmmc IP introduced by rockchip and the buggy design sweeps over all the existing rockchip Socs using dwmmc disastrously. It seems no way to work around this bug without the proper break-out mechanism so that we seek for a parallel pair the same as the handling for missing data response timeout, namely dto timer. Adding this cto timer seems easily to handle this bug but it's hard to restrict the code under the rockchip specified context. So after merging this patch, it sets up the cto timer for all the platforms using dwmmc IP which isn't ideal but at least we don't advertise new quirk here. Fortunately, no obvious performance regression was found by test and the pre-existing similar catch-all timer for sdhci has proved it's an acceptant way to make the code as robust as possible. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196321 Signed-off-by: Addy Ke Signed-off-by: Ziyuan Xu [shawn.lin: rewrite the code and the commit msg throughout] Signed-off-by: Shawn Lin --- drivers/mmc/host/dw_mmc.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/host/dw_mmc.h | 2 ++ 2 files changed, 50 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index a9dfb26..2f6121e 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -398,6 +398,21 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) return cmdr; } +static inline void dw_mci_set_cto(struct dw_mci *host) +{ + unsigned int cto_clks; + unsigned int cto_ms; + + cto_clks = mci_readl(host, TMOUT) & 0xff; + cto_ms = DIV_ROUND_UP(cto_clks, host->bus_hz / 1000); + + /* add a bit spare time */ + cto_ms += 10; + + mod_timer(&host->cto_timer, + jiffies + msecs_to_jiffies(cto_ms) + 1); +} + static void dw_mci_start_command(struct dw_mci *host, struct mmc_command *cmd, u32 cmd_flags) { @@ -410,6 +425,10 @@ static void dw_mci_start_command(struct dw_mci *host, wmb(); /* drain writebuffer */ dw_mci_wait_while_busy(host, cmd_flags); + /* response expected command only */ + if (cmd_flags & SDMMC_CMD_RESP_EXP) + dw_mci_set_cto(host); + mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); } @@ -2599,6 +2618,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } if (pending & DW_MCI_CMD_ERROR_FLAGS) { + del_timer(&host->cto_timer); mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); host->cmd_status = pending; smp_wmb(); /* drain writebuffer */ @@ -2642,6 +2662,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } if (pending & SDMMC_INT_CMD_DONE) { + del_timer(&host->cto_timer); mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); dw_mci_cmd_interrupt(host, pending); } @@ -2914,6 +2935,30 @@ static void dw_mci_cmd11_timer(unsigned long arg) tasklet_schedule(&host->tasklet); } +static void dw_mci_cto_timer(unsigned long arg) +{ + struct dw_mci *host = (struct dw_mci *)arg; + + switch (host->state) { + case STATE_SENDING_CMD11: + case STATE_SENDING_CMD: + case STATE_SENDING_STOP: + /* + * If CMD_DONE interrupt does NOT come in sending command + * state, we should notify the driver to terminate current + * transfer and report a command timeout to the core. + */ + host->cmd_status = SDMMC_INT_RTO; + set_bit(EVENT_CMD_COMPLETE, &host->pending_events); + tasklet_schedule(&host->tasklet); + break; + default: + dev_warn(host->dev, "Unexpected command timeout, state %d\n", + host->state); + break; + } +} + static void dw_mci_dto_timer(unsigned long arg) { struct dw_mci *host = (struct dw_mci *)arg; @@ -3085,6 +3130,9 @@ int dw_mci_probe(struct dw_mci *host) setup_timer(&host->cmd11_timer, dw_mci_cmd11_timer, (unsigned long)host); + setup_timer(&host->cto_timer, + dw_mci_cto_timer, (unsigned long)host); + setup_timer(&host->dto_timer, dw_mci_dto_timer, (unsigned long)host); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 75da375..4210927 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -126,6 +126,7 @@ struct dw_mci_dma_slave { * @irq: The irq value to be passed to request_irq. * @sdio_id0: Number of slot0 in the SDIO interrupt registers. * @cmd11_timer: Timer for SD3.0 voltage switch over scheme. + * @cto_timer: Timer for broken command transfer over scheme. * @dto_timer: Timer for broken data transfer over scheme. * * Locking @@ -232,6 +233,7 @@ struct dw_mci { int sdio_id0; struct timer_list cmd11_timer; + struct timer_list cto_timer; struct timer_list dto_timer; };