From patchwork Fri Nov 14 13:05:38 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: addy ke X-Patchwork-Id: 5305881 Return-Path: X-Original-To: patchwork-linux-rockchip@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 3B512C11AC for ; Fri, 14 Nov 2014 13:08:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0FE302013D for ; Fri, 14 Nov 2014 13:08:30 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 199FB2015D for ; Fri, 14 Nov 2014 13:08:29 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XpGc0-0001DI-M8; Fri, 14 Nov 2014 13:08:28 +0000 Received: from va-smtp01.263.net ([54.88.144.211]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XpGbp-0000yg-3e; Fri, 14 Nov 2014 13:08:19 +0000 Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by va-smtp01.263.net (Postfix) with ESMTP id 8A5297F947; Fri, 14 Nov 2014 13:06:46 +0000 (UTC) X-RL-SENDER: addy.ke@rock-chips.com X-FST-TO: robh+dt@kernel.org X-SENDER-IP: 127.0.0.1 X-LOGIN-NAME: addy.ke@rock-chips.com X-UNIQUE-TAG: <8b746ddb5ebdcdca8f66070ec3c1d909> X-ATTACHMENT-NUM: 0 X-SENDER: kfx@rock-chips.com X-DNS-TYPE: 1 Received: from localhost.localdomain (localhost [127.0.0.1]) by va-smtp01.263.net (Postfix) whith ESMTP id 31100OFO8PZ; Fri, 14 Nov 2014 13:06:46 +0000 (UTC) From: Addy Ke To: robh+dt@kernel.org, pawel.moll@arm.com, mark.rutland@arm.com, ijc+devicetree@hellion.org.uk, galak@codeaurora.org, rdunlap@infradead.org, tgih.jun@samsung.com, jh80.chung@samsung.com, chris@printf.net, ulf.hansson@linaro.org, dinguyen@altera.com, heiko@sntech.de, olof@lixom.net, dianders@chromium.org, sonnyrao@chromium.org, amstan@chromium.org Subject: [PATCH] mmc: dw_mmc: add quirk for data over interrupt timeout Date: Fri, 14 Nov 2014 21:05:38 +0800 Message-Id: <1415970338-2637-1-git-send-email-addy.ke@rock-chips.com> X-Mailer: git-send-email 1.8.3.2 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20141114_050817_298551_BF7D43DD X-CRM114-Status: GOOD ( 17.00 ) X-Spam-Score: -0.0 (/) Cc: huangtao@rock-chips.com, devicetree@vger.kernel.org, Addy , hl@rock-chips.com, linux-doc@vger.kernel.org, yzq@rock-chips.com, zyw@rock-chips.com, zhangqing@rock-chips.com, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, kever.yang@rock-chips.com, lintao@rock-chips.com, linux-rockchip@lists.infradead.org, xjq@rock-chips.com, zhenfu.fang@rock-chips.com, chenfen@rock-chips.com, cf@rock-chips.com, hj@rock-chips.com, linux-arm-kernel@lists.infradead.org, zyf@rock-chips.com X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, T_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: Addy This patch add a new quirk to notify the driver to teminate current transfer and report a data timeout to the core, if data over interrupt does NOT come within the given time. dw_mmc call mmc_request_done func to finish transfer depends on data over interrupt. If data over interrupt does not come in sending data state, the current transfer will be blocked. But this case really exists, when driver reads tuning data from card on rk3288-pink2 board. I measured waveforms by oscilloscope and found that card clock was always on and data lines were always holded high level in sending data state. This is the cause that card does NOT send data to host. According to synopsys designware databook, the timeout counter is started only after the card clock is stopped. So if card clock is always on, data read timeout interrupt will NOT come, and if data lines are always holded high level, all data-related interrupt such as start-bit error, data crc error, data over interrupt, end-bit error, and so on, will NOT come too. So driver can't get the current state, it can do nothing but wait for. This patch is based on https://patchwork.kernel.org/patch/5227941/ Signed-off-by: Addy --- drivers/mmc/host/dw_mmc.c | 47 +++++++++++++++++++++++++++++++++++++++++++++- include/linux/mmc/dw_mmc.h | 5 +++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index b4c3044..3960fc3 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1448,6 +1448,17 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) return data->error; } +static inline void dw_mci_dto_start_monitor(struct dw_mci *host) +{ + unsigned int data_tmout_clks; + unsigned int data_tmout_ms; + + data_tmout_clks = (mci_readl(host, TMOUT) >> 8); + data_tmout_ms = (data_tmout_clks * 1000 / host->bus_hz) + 250; + + mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(data_tmout_ms)); +} + static void dw_mci_tasklet_func(unsigned long priv) { struct dw_mci *host = (struct dw_mci *)priv; @@ -1522,8 +1533,11 @@ static void dw_mci_tasklet_func(unsigned long priv) } if (!test_and_clear_bit(EVENT_XFER_COMPLETE, - &host->pending_events)) + &host->pending_events)) { + if (host->quirks & DW_MCI_QUIRK_DTO_TIMER) + dw_mci_dto_start_monitor(host); break; + } set_bit(EVENT_XFER_COMPLETE, &host->completed_events); @@ -2115,6 +2129,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } if (pending & SDMMC_INT_DATA_OVER) { + if (host->quirks & DW_MCI_QUIRK_DTO_TIMER) + del_timer(&host->dto_timer); + mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); if (!host->data_status) host->data_status = pending; @@ -2502,6 +2519,28 @@ ciu_out: return ret; } +static void dw_mci_dto_timer(unsigned long arg) +{ + struct dw_mci *host = (struct dw_mci *)arg; + + switch (host->state) { + case STATE_SENDING_DATA: + case STATE_DATA_BUSY: + /* + * If data over interrupt does NOT come in sending data state, + * we should notify the driver to teminate current transfer + * and report a data timeout to the core. + */ + host->data_status = SDMMC_INT_DRTO; + set_bit(EVENT_DATA_ERROR, &host->pending_events); + set_bit(EVENT_DATA_COMPLETE, &host->pending_events); + tasklet_schedule(&host->tasklet); + break; + default: + break; + } +} + #ifdef CONFIG_OF static struct dw_mci_of_quirks { char *quirk; @@ -2513,6 +2552,9 @@ static struct dw_mci_of_quirks { }, { .quirk = "disable-wp", .id = DW_MCI_QUIRK_NO_WRITE_PROTECT, + }, { + .quirk = "dto-timer", + .id = DW_MCI_QUIRK_DTO_TIMER, }, }; @@ -2654,6 +2696,9 @@ int dw_mci_probe(struct dw_mci *host) spin_lock_init(&host->lock); INIT_LIST_HEAD(&host->queue); + if (host->quirks & DW_MCI_QUIRK_DTO_TIMER) + setup_timer(&host->dto_timer, + dw_mci_dto_timer, (unsigned long)host); /* * Get the host data width - this assumes that HCON has been set with diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 42b724e..2477813 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -98,6 +98,7 @@ struct mmc_data; * @irq_flags: The flags to be passed to request_irq. * @irq: The irq value to be passed to request_irq. * @sdio_id0: Number of slot0 in the SDIO interrupt registers. + * @dto_timer: Timer for data over interrupt timeout. * * Locking * ======= @@ -196,6 +197,8 @@ struct dw_mci { int irq; int sdio_id0; + + struct timer_list dto_timer; }; /* DMA ops for Internal/External DMAC interface */ @@ -220,6 +223,8 @@ struct dw_mci_dma_ops { #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3) /* No write protect */ #define DW_MCI_QUIRK_NO_WRITE_PROTECT BIT(4) +/* Timer for data over interrupt timeout */ +#define DW_MCI_QUIRK_DTO_TIMER BIT(5) /* Slot level quirks */ /* This slot has no write protect */