From patchwork Fri May 19 08:15:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kishon Vijay Abraham I X-Patchwork-Id: 9736429 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 4917F6020B for ; Fri, 19 May 2017 08:30:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 21E1428712 for ; Fri, 19 May 2017 08:30:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 13B77288AD; Fri, 19 May 2017 08:30:04 +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 6781628712 for ; Fri, 19 May 2017 08:30:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752010AbdESIRV (ORCPT ); Fri, 19 May 2017 04:17:21 -0400 Received: from fllnx210.ext.ti.com ([198.47.19.17]:50224 "EHLO fllnx210.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750818AbdESIRP (ORCPT ); Fri, 19 May 2017 04:17:15 -0400 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by fllnx210.ext.ti.com (8.15.1/8.15.1) with ESMTP id v4J8GRPV024315; Fri, 19 May 2017 03:16:27 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ti.com; s=ti-com-17Q1; t=1495181787; bh=8TSaAYVhWlE2E0Otpm0d1D30FasN/JRHzUWQVkNuK40=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=WhgJaDzDsFyjFTdRQ1C7QTeiRNtb/mrtaN6FVxpm9n1OqW2HG4QHb8dWR1g4D1cFS lIHY+rzwYKQ76wCDSlDLCOH3ubC9gJzfJcfg4t9F7MZM3+LGbQFV7fRFRqpu3SYicJ kHbyvLWVznmLtYldXZmT8Pmk2J2fLVvsnYgXUaec= Received: from DFLE72.ent.ti.com (dfle72.ent.ti.com [128.247.5.109]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id v4J8GRFJ013394; Fri, 19 May 2017 03:16:27 -0500 Received: from dlep33.itg.ti.com (157.170.170.75) by DFLE72.ent.ti.com (128.247.5.109) with Microsoft SMTP Server id 14.3.294.0; Fri, 19 May 2017 03:16:26 -0500 Received: from a0393678ub.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep33.itg.ti.com (8.14.3/8.13.8) with ESMTP id v4J8FfQG009185; Fri, 19 May 2017 03:16:22 -0500 From: Kishon Vijay Abraham I To: Ulf Hansson , Rob Herring , Tony Lindgren CC: , , , , , , Jonathan Corbet , Mark Rutland , Russell King , , Subject: [PATCH 09/41] mmc: host: omap_hsmmc: Add software timer when timeout greater than hardware capablility Date: Fri, 19 May 2017 13:45:09 +0530 Message-ID: <20170519081541.26753-10-kishon@ti.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170519081541.26753-1-kishon@ti.com> References: <20170519081541.26753-1-kishon@ti.com> MIME-Version: 1.0 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: Mugunthan V N DRA7 Errata No i834: When using high speed HS200 and SDR104 cards, the functional clock for MMC module will be 192MHz. At this frequency, the maximum obtainable timeout (DTO =0xE) in hardware is (1/192MHz)*2^27 = 700ms. Commands taking longer than 700ms will be affected by this small window frame and will be timing out frequently even without a genune timeout from the card. Workarround for this errata is use a software timer instead of hardware timer to provide the delay requested by the upper layer So adding a software timer as a work around for the errata. Instead of using software timeout only for larger delays requested when using HS200/SDR104 cards which results in hardware and software timer race conditions, so move all the timeout request to use software timer when HS200/SDR104 card is connected and use hardware timer when other type cards are connected. Also start the software timer after queueing to DMA to ensure we are more likely to expire within correct limits. To be ever more sure that we won't expire this soft timer too early, we're adding a 1000000ns slack to the data timeout requested by the upper layer. [rk@ti.com: fix compiler warning in sw timeout function and use sw timeout for busy timeout] Signed-off-by: Ravikumar Kattekola Signed-off-by: Mugunthan V N [kishon@ti.com: Fix the timeout value to account for the entire transfer to complete here.] Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Sekhar Nori --- drivers/mmc/host/omap_hsmmc.c | 126 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 30cd2be7141c..9ac18521e097 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -185,6 +185,11 @@ #define PSTATE_DLEV (0xF << 20) #define PSTATE_DLEV_DAT0 (0x1 << 20) +#define MMC_BLOCK_TRANSFER_TIME_NS(blksz, bus_width, freq) \ + ((unsigned long long) \ + (2 * (((blksz) * NSEC_PER_SEC * \ + (8 / (bus_width))) / (freq)))) + /* * One controller can have multiple slots, like on some omap boards using * omap.c controller driver. Luckily this is not currently done on any known @@ -250,6 +255,8 @@ struct omap_hsmmc_host { struct omap_hsmmc_platform_data *pdata; bool is_tuning; + struct timer_list timer; + unsigned long long data_timeout; /* return MMC cover switch state, can be NULL if not supported. * @@ -642,8 +649,8 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, if (host->use_dma) irq_mask &= ~(BRR_EN | BWR_EN); - /* Disable timeout for erases */ - if (cmd->opcode == MMC_ERASE) + /* Disable timeout for erases or when using software timeout */ + if (cmd && (cmd->opcode == MMC_ERASE || host->data_timeout)) irq_mask &= ~DTO_EN; if (host->flags & CLKEXTFREE_ENABLED) @@ -1250,8 +1257,16 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) } OMAP_HSMMC_WRITE(host->base, STAT, status); - if (end_cmd || ((status & CC_EN) && host->cmd)) + if (end_cmd || ((status & CC_EN) && host->cmd)) { omap_hsmmc_cmd_done(host, host->cmd); + if (host->data_timeout) { + unsigned long timeout; + + timeout = jiffies + + nsecs_to_jiffies(host->data_timeout); + mod_timer(&host->timer, timeout); + } + } if ((end_trans || (status & TC_EN)) && host->mrq) omap_hsmmc_xfer_done(host, data); } @@ -1265,7 +1280,19 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) int status; status = OMAP_HSMMC_READ(host->base, STAT); + while (status & (INT_EN_MASK | CIRQ_EN)) { + /* + * During a successful bulk data transfer command-completion + * interrupt and transfer-completion interrupt will be + * generated, but software-timeout timer should be deleted + * only on non-cc interrupts (transfer complete or error) + */ + if (host->data_timeout && (status & (~CC_EN))) { + del_timer(&host->timer); + host->data_timeout = 0; + } + if (host->req_in_progress) omap_hsmmc_do_irq(host, status); @@ -1279,6 +1306,25 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void omap_hsmmc_soft_timeout(unsigned long data) +{ + struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)data; + bool end_trans = false; + + omap_hsmmc_disable_irq(host); + if (host->data || host->response_busy) { + host->response_busy = 0; + end_trans = true; + } + + hsmmc_command_incomplete(host, -ETIMEDOUT, 0); + if (end_trans && host->mrq) + omap_hsmmc_xfer_done(host, host->data); + else if (host->cmd) + omap_hsmmc_cmd_done(host, host->cmd); + host->data_timeout = 0; +} + static void set_sd_bus_power(struct omap_hsmmc_host *host) { unsigned long i; @@ -1473,6 +1519,9 @@ static void set_data_timeout(struct omap_hsmmc_host *host, unsigned long long timeout = timeout_ns; unsigned int cycle_ns; uint32_t reg, clkd, dto = 0; + struct mmc_ios *ios = &host->mmc->ios; + struct mmc_data *data = host->mrq->data; + struct mmc_command *cmd = host->mrq->cmd; reg = OMAP_HSMMC_READ(host->base, SYSCTL); clkd = (reg & CLKD_MASK) >> CLKD_SHIFT; @@ -1482,23 +1531,60 @@ static void set_data_timeout(struct omap_hsmmc_host *host, cycle_ns = 1000000000 / (host->clk_rate / clkd); do_div(timeout, cycle_ns); timeout += timeout_clks; - if (timeout) { - while ((timeout & 0x80000000) == 0) { - dto += 1; - timeout <<= 1; - } - dto = 31 - dto; + + if (!timeout) + goto out; + + while ((timeout & 0x80000000) == 0) { + dto += 1; timeout <<= 1; - if (timeout && dto) - dto += 1; - if (dto >= 13) - dto -= 13; - else - dto = 0; - if (dto > 14) - dto = 14; + } + dto = 31 - dto; + timeout <<= 1; + if (timeout && dto) + dto += 1; + if (dto >= 13) + dto -= 13; + else + dto = 0; + if (dto > 14) { + /* + * DRA7 Errata No i834: When using high speed HS200 and + * SDR104 cards, the functional clock for MMC module + * will be 192MHz. At this frequency, the maximum + * obtainable timeout (DTO =0xE) in hardware is + * (1/192MHz)*2^27 = 700ms. Commands taking longer than + * 700ms will be affected by this small window frame + * and will be timing out frequently even without a + * genuine timeout from the card. Workaround for + * this errata is use a software timer instead of + * hardware timer to provide the timeout requested + * by the upper layer. + * + * The timeout from the upper layer denotes the delay + * between the end bit of the read command and the + * start bit of the data block and in the case of + * multiple-read operation, they also define the + * typical delay between the end bit of a data + * block and the start bit of next data block. + * + * Calculate the total timeout value for the entire + * transfer to complete from the timeout value given + * by the upper layer. + */ + if (data) + host->data_timeout = (data->blocks * + (timeout_ns + + MMC_BLOCK_TRANSFER_TIME_NS( + data->blksz, ios->bus_width, + ios->clock))); + else if (cmd->flags & MMC_RSP_BUSY) + host->data_timeout = timeout_ns; + + dto = 14; } +out: reg &= ~DTO_MASK; reg |= dto << DTO_SHIFT; OMAP_HSMMC_WRITE(host->base, SYSCTL, reg); @@ -2359,6 +2445,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc->ops = &omap_hsmmc_ops; spin_lock_init(&host->irq_lock); + setup_timer(&host->timer, omap_hsmmc_soft_timeout, + (unsigned long)host); host->fclk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { @@ -2522,6 +2610,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev) dma_release_channel(host->tx_chan); dma_release_channel(host->rx_chan); + del_timer_sync(&host->timer); + pm_runtime_dont_use_autosuspend(host->dev); pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); @@ -2555,6 +2645,8 @@ static int omap_hsmmc_suspend(struct device *dev) if (host->dbclk) clk_disable_unprepare(host->dbclk); + del_timer_sync(&host->timer); + pm_runtime_put_sync(host->dev); return 0; }