All of lore.kernel.org
 help / color / mirror / Atom feed
From: Addy Ke <addy.ke@rock-chips.com>
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
Cc: devicetree@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-mmc@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-rockchip@lists.infradead.org, zhenfu.fang@rock-chips.com,
	cf@rock-chips.com, lintao@rock-chips.com, chenfen@rock-chips.com,
	zyf@rock-chips.com, xjq@rock-chips.com, huangtao@rock-chips.com,
	zyw@rock-chips.com, yzq@rock-chips.com, hj@rock-chips.com,
	kever.yang@rock-chips.com, zhangqing@rock-chips.com,
	hl@rock-chips.com, Addy Ke <addy.ke@rock-chips.com>
Subject: [PATCH v2] mmc: dw_mmc: add quirk for broken data transfer over scheme
Date: Tue, 25 Nov 2014 16:10:08 +0800	[thread overview]
Message-ID: <1416903008-4160-1-git-send-email-addy.ke@rock-chips.com> (raw)
In-Reply-To: <1415970338-2637-1-git-send-email-addy.ke@rock-chips.com>

This patch add a new quirk to add a s/w timer to notify the driver
to terminate current transfer and report a data timeout to the core,
if DTO interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
DTO interrupt. If DTO 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.

We got the reply from synopsys:
There are two counters but both use the same value of [31:8] bits.
Data timeout counter doesn't wait for stop clock and you should get
DRTO even when the clock is not stopped.
Host Starvation timeout counter is triggered with stop clock condition.

This means that host should get DRTO and DTO interrupt.

But we really don't get any data-related interrupt in RK3X SoCs.
And driver can't get data transfer state, it can do nothing but wait for.

Signed-off-by: Addy Ke <addy.ke@rock-chips.com>
---
- fix some typo.
- remove extra timeout value (250ms).
- remove dw_mci_dto_start_monitor func.
- use "broken-dto" for new quirk and change Subject for it.

 drivers/mmc/host/dw_mmc.c  | 44 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mmc/dw_mmc.h |  5 +++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b4c3044..bc09f50 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1457,6 +1457,8 @@ static void dw_mci_tasklet_func(unsigned long priv)
 	enum dw_mci_state state;
 	enum dw_mci_state prev_state;
 	unsigned int err;
+	unsigned int drto_clks;
+	unsigned int drto_ms;
 
 	spin_lock(&host->lock);
 
@@ -1522,8 +1524,17 @@ 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_BROKEN_DTO) {
+					drto_clks = mci_readl(host, TMOUT) >> 8;
+					drto_ms = DIV_ROUND_UP(drto_clks * 1000,
+							       host->bus_hz);
+
+					mod_timer(&host->dto_timer, jiffies +
+						msecs_to_jiffies(drto_ms));
+				}
 				break;
+			}
 
 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
 
@@ -2115,6 +2126,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 		}
 
 		if (pending & SDMMC_INT_DATA_OVER) {
+			if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
+				del_timer(&host->dto_timer);
+
 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
 			if (!host->data_status)
 				host->data_status = pending;
@@ -2502,6 +2516,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 DTO interrupt does NOT come in sending data state,
+		* we should notify the driver to terminate 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 +2549,9 @@ static struct dw_mci_of_quirks {
 	}, {
 		.quirk	= "disable-wp",
 		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
+	}, {
+		.quirk	= "broken-dto",
+		.id	= DW_MCI_QUIRK_BROKEN_DTO,
 	},
 };
 
@@ -2654,6 +2693,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_BROKEN_DTO)
+		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..ff9bd1e 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 broken data transfer over scheme.
  *
  * 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 broken data transfer over scheme */
+#define DW_MCI_QUIRK_BROKEN_DTO			BIT(5)
 
 /* Slot level quirks */
 /* This slot has no write protect */
-- 
1.8.3.2



WARNING: multiple messages have this Message-ID (diff)
From: addy.ke@rock-chips.com (Addy Ke)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2] mmc: dw_mmc: add quirk for broken data transfer over scheme
Date: Tue, 25 Nov 2014 16:10:08 +0800	[thread overview]
Message-ID: <1416903008-4160-1-git-send-email-addy.ke@rock-chips.com> (raw)
In-Reply-To: <1415970338-2637-1-git-send-email-addy.ke@rock-chips.com>

This patch add a new quirk to add a s/w timer to notify the driver
to terminate current transfer and report a data timeout to the core,
if DTO interrupt does NOT come within the given time.

dw_mmc call mmc_request_done func to finish transfer depends on
DTO interrupt. If DTO 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.

We got the reply from synopsys:
There are two counters but both use the same value of [31:8] bits.
Data timeout counter doesn't wait for stop clock and you should get
DRTO even when the clock is not stopped.
Host Starvation timeout counter is triggered with stop clock condition.

This means that host should get DRTO and DTO interrupt.

But we really don't get any data-related interrupt in RK3X SoCs.
And driver can't get data transfer state, it can do nothing but wait for.

Signed-off-by: Addy Ke <addy.ke@rock-chips.com>
---
- fix some typo.
- remove extra timeout value (250ms).
- remove dw_mci_dto_start_monitor func.
- use "broken-dto" for new quirk and change Subject for it.

 drivers/mmc/host/dw_mmc.c  | 44 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/mmc/dw_mmc.h |  5 +++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index b4c3044..bc09f50 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1457,6 +1457,8 @@ static void dw_mci_tasklet_func(unsigned long priv)
 	enum dw_mci_state state;
 	enum dw_mci_state prev_state;
 	unsigned int err;
+	unsigned int drto_clks;
+	unsigned int drto_ms;
 
 	spin_lock(&host->lock);
 
@@ -1522,8 +1524,17 @@ 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_BROKEN_DTO) {
+					drto_clks = mci_readl(host, TMOUT) >> 8;
+					drto_ms = DIV_ROUND_UP(drto_clks * 1000,
+							       host->bus_hz);
+
+					mod_timer(&host->dto_timer, jiffies +
+						msecs_to_jiffies(drto_ms));
+				}
 				break;
+			}
 
 			set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
 
@@ -2115,6 +2126,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 		}
 
 		if (pending & SDMMC_INT_DATA_OVER) {
+			if (host->quirks & DW_MCI_QUIRK_BROKEN_DTO)
+				del_timer(&host->dto_timer);
+
 			mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
 			if (!host->data_status)
 				host->data_status = pending;
@@ -2502,6 +2516,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 DTO interrupt does NOT come in sending data state,
+		* we should notify the driver to terminate 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 +2549,9 @@ static struct dw_mci_of_quirks {
 	}, {
 		.quirk	= "disable-wp",
 		.id	= DW_MCI_QUIRK_NO_WRITE_PROTECT,
+	}, {
+		.quirk	= "broken-dto",
+		.id	= DW_MCI_QUIRK_BROKEN_DTO,
 	},
 };
 
@@ -2654,6 +2693,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_BROKEN_DTO)
+		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..ff9bd1e 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 broken data transfer over scheme.
  *
  * 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 broken data transfer over scheme */
+#define DW_MCI_QUIRK_BROKEN_DTO			BIT(5)
 
 /* Slot level quirks */
 /* This slot has no write protect */
-- 
1.8.3.2

  parent reply	other threads:[~2014-11-25  8:10 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-14 13:05 [PATCH] mmc: dw_mmc: add quirk for data over interrupt timeout Addy Ke
2014-11-14 13:05 ` Addy Ke
2014-11-14 13:18 ` Jaehoon Chung
2014-11-14 13:18   ` Jaehoon Chung
2014-11-18  0:32   ` Addy
2014-11-18  0:32     ` Addy
2014-11-19  1:22     ` Jaehoon Chung
2014-11-19  1:22       ` Jaehoon Chung
2014-11-19  5:56       ` addy ke
2014-11-19  5:56         ` addy ke
2014-11-19  5:56         ` addy ke
2014-11-20  9:33         ` addy ke
2014-11-20  9:33           ` addy ke
2014-11-20  9:33           ` addy ke
2014-11-20 10:01           ` Jaehoon Chung
2014-11-20 10:01             ` Jaehoon Chung
2014-11-25  6:30             ` Addy
2014-11-25  6:30               ` Addy
2014-11-25  8:10 ` Addy Ke [this message]
2014-11-25  8:10   ` [PATCH v2] mmc: dw_mmc: add quirk for broken data transfer over scheme Addy Ke
2014-11-26 22:46   ` Doug Anderson
2014-11-26 22:46     ` Doug Anderson
2014-11-26 22:46     ` Doug Anderson
2014-12-02  7:50     ` addy ke
2014-12-02  7:50       ` addy ke
2014-12-02 17:47       ` Doug Anderson
2014-12-02 17:47         ` Doug Anderson
2014-12-02 17:47         ` Doug Anderson
2014-12-03  3:16 ` [PATCH v3] " Addy Ke
2014-12-03  3:16   ` Addy Ke
2014-12-03  5:08   ` Doug Anderson
2014-12-03  5:08     ` Doug Anderson
2014-12-03  5:08     ` Doug Anderson
2014-12-05 23:56     ` Alexandru Stan
2014-12-05 23:56       ` Alexandru Stan
2014-12-05 23:56       ` Alexandru Stan
2014-12-26  9:13   ` [PATCH v4] " Addy Ke
2015-01-05  8:21     ` [PATCH v5] " Addy Ke
2015-01-08  1:58       ` Jaehoon Chung
2015-01-08  1:58         ` Jaehoon Chung

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1416903008-4160-1-git-send-email-addy.ke@rock-chips.com \
    --to=addy.ke@rock-chips.com \
    --cc=amstan@chromium.org \
    --cc=cf@rock-chips.com \
    --cc=chenfen@rock-chips.com \
    --cc=chris@printf.net \
    --cc=devicetree@vger.kernel.org \
    --cc=dianders@chromium.org \
    --cc=dinguyen@altera.com \
    --cc=galak@codeaurora.org \
    --cc=heiko@sntech.de \
    --cc=hj@rock-chips.com \
    --cc=hl@rock-chips.com \
    --cc=huangtao@rock-chips.com \
    --cc=ijc+devicetree@hellion.org.uk \
    --cc=jh80.chung@samsung.com \
    --cc=kever.yang@rock-chips.com \
    --cc=lintao@rock-chips.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=mark.rutland@arm.com \
    --cc=olof@lixom.net \
    --cc=pawel.moll@arm.com \
    --cc=rdunlap@infradead.org \
    --cc=robh+dt@kernel.org \
    --cc=sonnyrao@chromium.org \
    --cc=tgih.jun@samsung.com \
    --cc=ulf.hansson@linaro.org \
    --cc=xjq@rock-chips.com \
    --cc=yzq@rock-chips.com \
    --cc=zhangqing@rock-chips.com \
    --cc=zhenfu.fang@rock-chips.com \
    --cc=zyf@rock-chips.com \
    --cc=zyw@rock-chips.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.