From patchwork Tue Aug 25 09:05:42 2015 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: 7069661 Return-Path: X-Original-To: patchwork-linux-mmc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 1EDD79F305 for ; Tue, 25 Aug 2015 09:07:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 20CF2203F4 for ; Tue, 25 Aug 2015 09:07:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id ED395203E6 for ; Tue, 25 Aug 2015 09:07:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932805AbbHYJGc (ORCPT ); Tue, 25 Aug 2015 05:06:32 -0400 Received: from comal.ext.ti.com ([198.47.26.152]:48953 "EHLO comal.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932899AbbHYJGY (ORCPT ); Tue, 25 Aug 2015 05:06:24 -0400 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id t7P96Kwm026679; Tue, 25 Aug 2015 04:06:20 -0500 Received: from DLEE70.ent.ti.com (dlemailx.itg.ti.com [157.170.170.113]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id t7P96Ksj009448; Tue, 25 Aug 2015 04:06:20 -0500 Received: from dflp33.itg.ti.com (10.64.6.16) by DLEE70.ent.ti.com (157.170.170.113) with Microsoft SMTP Server id 14.3.224.2; Tue, 25 Aug 2015 04:06:20 -0500 Received: from a0393678ub.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp33.itg.ti.com (8.14.3/8.13.8) with ESMTP id t7P95h4j031149; Tue, 25 Aug 2015 04:06:17 -0500 From: Kishon Vijay Abraham I To: , , , , , , CC: , Subject: [PATCH v2 11/11] mmc: host: omap_hsmmc: add software timer when timeout greater than hardware capablility Date: Tue, 25 Aug 2015 14:35:42 +0530 Message-ID: <1440493542-26150-12-git-send-email-kishon@ti.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1440493542-26150-1-git-send-email-kishon@ti.com> References: <1440493542-26150-1-git-send-email-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-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.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. Signed-off-by: Mugunthan V N Signed-off-by: Kishon Vijay Abraham I --- drivers/mmc/host/omap_hsmmc.c | 71 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bc59822..ec80de9 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -168,6 +168,7 @@ #define ACNE (1 << 0) #define MMC_AUTOSUSPEND_DELAY 100 +#define MMC_SOFT_TIMER_SLACK 1000000 /* ns */ #define MMC_TIMEOUT_MS 20 /* 20 mSec */ #define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */ #define OMAP_MMC_MIN_CLOCK 400000 @@ -246,6 +247,10 @@ struct omap_hsmmc_host { struct omap_hsmmc_next next_data; struct omap_hsmmc_platform_data *pdata; + struct timer_list timer; + unsigned long data_timeout; + unsigned int need_i834_errata:1; + u32 *tuning_data; int tuning_size; @@ -670,8 +675,8 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, 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->opcode == MMC_ERASE || host->need_i834_errata) irq_mask &= ~DTO_EN; spin_lock_irqsave(&host->irq_lock, flags); @@ -761,6 +766,22 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) OMAP_HSMMC_WRITE(host->base, HCTL, regval); } + /* + * 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 + */ + if (ios->clock == 192000000) + host->need_i834_errata = true; + else + host->need_i834_errata = false; + omap_hsmmc_start_clock(host); } @@ -1307,6 +1328,16 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) int status; status = OMAP_HSMMC_READ(host->base, STAT); + + /* + * 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->need_i834_errata && (status & (~CC_EN))) + del_timer(&host->timer); + while (status & (INT_EN_MASK | CIRQ_EN)) { if (host->req_in_progress) omap_hsmmc_do_irq(host, status); @@ -1321,6 +1352,13 @@ 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; + + hsmmc_command_incomplete(host, -ETIMEDOUT, 0); +} + static void set_sd_bus_power(struct omap_hsmmc_host *host) { unsigned long i; @@ -1522,6 +1560,22 @@ static void set_data_timeout(struct omap_hsmmc_host *host, if (clkd == 0) clkd = 1; + if (host->need_i834_errata) { + unsigned long delta; + + delta = (timeout_clks / (host->clk_rate / clkd)); + + /* + * We should really be using just timeout_ns + delta, + * however we have no control over when DMA will + * actually start transferring; due to that we will add + * an extra slack to make sure we don't expire too + * early. + */ + host->data_timeout = timeout_ns + delta + MMC_SOFT_TIMER_SLACK; + return; + } + cycle_ns = 1000000000 / (host->clk_rate / clkd); timeout = timeout_ns / cycle_ns; timeout += timeout_clks; @@ -1560,6 +1614,13 @@ static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host) req->data->timeout_clks); chan = omap_hsmmc_get_dma_chan(host, req->data); dma_async_issue_pending(chan); + + if (host->need_i834_errata) { + unsigned long timeout; + + timeout = jiffies + nsecs_to_jiffies(host->data_timeout); + mod_timer(&host->timer, timeout); + } } /* @@ -2426,6 +2487,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev) spin_lock_init(&host->irq_lock); init_completion(&host->buf_ready); + setup_timer(&host->timer, omap_hsmmc_soft_timeout, + (unsigned long)host); host->fclk = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { @@ -2624,6 +2687,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev) if (host->rx_chan) dma_release_channel(host->rx_chan); + del_timer_sync(&host->timer); + pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); device_init_wakeup(&pdev->dev, false); @@ -2656,6 +2721,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; }