linux-mmc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease
@ 2013-09-24  8:12 Haijun Zhang
  2013-09-24  8:12 ` [PATCH 2/5] mmc:sdhc: Calculate timeout_clk from actual sd clock Haijun Zhang
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Haijun Zhang @ 2013-09-24  8:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: cbouatmailru, cjb, scottwood, X.Xie, ulf.hansson, Haijun Zhang,
	Haijun Zhang

At 50 Mhz SD_CLK period,
the max timeout value = 2^27 * SD_CLK period ~= 2.69 sec.

If max_discard_to was not designed, for mmc card preferred erase
size should be used, for sd card just return UINT_MAX. Also add
limit for data transfer, Use max_discard_to as max data timeout value
to avoid timeout error in case data timeout was larger than
2.69 sec.

For some crappy cards, the timeout value calculate from card was
larger than UINT_MAX, in this case the timeout value write into
register was not expected.

This patch can reduce I/O error due to large timeout value for
erase(CMD38) and write(CMD25) for some crappy cards.

Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com>
---
 drivers/mmc/core/core.c | 45 ++++++++++++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index bf18b6b..b429baa 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -757,6 +757,7 @@ EXPORT_SYMBOL(mmc_read_bkops_status);
  */
 void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 {
+	struct mmc_host *host = card->host;
 	unsigned int mult;
 
 	/*
@@ -780,7 +781,12 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 	if (data->flags & MMC_DATA_WRITE)
 		mult <<= card->csd.r2w_factor;
 
-	data->timeout_ns = card->csd.tacc_ns * mult;
+	/* Avoid over flow for some crappy cards. */
+	if ((UINT_MAX / mult) < card->csd.tacc_ns)
+		data->timeout_ns = UINT_MAX;
+	else
+		data->timeout_ns = card->csd.tacc_ns * mult;
+
 	data->timeout_clks = card->csd.tacc_clks * mult;
 
 	/*
@@ -842,6 +848,11 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 				data->timeout_ns =  100000000;	/* 100ms */
 		}
 	}
+
+	if (host->max_discard_to &&
+			(host->max_discard_to <
+			 (data->timeout_ns / 1000000)))
+		data->timeout_ns = host->max_discard_to * 1000000;
 }
 EXPORT_SYMBOL(mmc_set_data_timeout);
 
@@ -1816,11 +1827,14 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
 		unsigned int timeout_clks = card->csd.tacc_clks * mult;
 		unsigned int timeout_us;
 
-		/* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
-		if (card->csd.tacc_ns < 1000000)
-			timeout_us = (card->csd.tacc_ns * mult) / 1000;
-		else
+		/*
+		 * Avoid over flow for some crappy cards.
+		 * e.g. tacc_ns=80000000 mult=1280
+		 */
+		if ((UINT_MAX / mult) < card->csd.tacc_ns)
 			timeout_us = (card->csd.tacc_ns / 1000) * mult;
+		else
+			timeout_us = (card->csd.tacc_ns * mult) / 1000;
 
 		/*
 		 * ios.clock is only a target.  The real clock rate might be
@@ -2185,16 +2199,17 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	unsigned int max_discard, max_trim;
 
-	if (!host->max_discard_to)
-		return UINT_MAX;
-
-	/*
-	 * Without erase_group_def set, MMC erase timeout depends on clock
-	 * frequence which can change.  In that case, the best choice is
-	 * just the preferred erase size.
-	 */
-	if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
-		return card->pref_erase;
+	if (!host->max_discard_to) {
+		/*
+		 * Without erase_group_def set, MMC erase timeout depends
+		 * on clock frequence which can change.  In that case, the
+		 * best choice is just the preferred erase size.
+		 */
+		if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
+			return card->pref_erase;
+		else
+			return UINT_MAX;
+	}
 
 	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
 	if (mmc_can_trim(card)) {
-- 
1.8.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] mmc:sdhc: Calculate timeout_clk from actual sd clock
  2013-09-24  8:12 [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Haijun Zhang
@ 2013-09-24  8:12 ` Haijun Zhang
  2013-09-24  8:12 ` [PATCH 3/5] mmc:esdhc: Update timeout clock according to actual clock Haijun Zhang
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Haijun Zhang @ 2013-09-24  8:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: cbouatmailru, cjb, scottwood, X.Xie, ulf.hansson, Haijun Zhang,
	Haijun Zhang

At 50 Mhz SD_CLK period,
the max timeout value = 2^27 * SD_CLK period ~= 2.69 sec.

When we has quirk SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, the timeout_clk
should be calculate according to the real clock run by card. Which is
less than 50 MHz. So update the timeout clock when the clock was actually
enabled and used.

Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com>
---
 drivers/mmc/host/sdhci.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 7a7fb4f..c614c31 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1238,6 +1238,10 @@ clock_set:
 	clk |= SDHCI_CLOCK_CARD_EN;
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
+	if (real_div && (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+		host->timeout_clk = host->mmc->actual_clock / 1000;
+		host->mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+	}
 out:
 	host->clock = clock;
 }
-- 
1.8.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] mmc:esdhc: Update timeout clock according to actual clock
  2013-09-24  8:12 [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Haijun Zhang
  2013-09-24  8:12 ` [PATCH 2/5] mmc:sdhc: Calculate timeout_clk from actual sd clock Haijun Zhang
@ 2013-09-24  8:12 ` Haijun Zhang
  2013-09-24  8:12 ` [PATCH 4/5] mmc:esdhc: Workaround about clock glitch issue on eSDHC host Haijun Zhang
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Haijun Zhang @ 2013-09-24  8:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: cbouatmailru, cjb, scottwood, X.Xie, ulf.hansson, Haijun Zhang,
	Haijun Zhang

At 50 Mhz SD_CLK period,
the max timeout value = 2^27 * SD_CLK period ~= 2.69 sec.

When we has quirk SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, the timeout_clk
should be calculate according to the real clock run by card. Which is
less than 50 MHz. So update the timeout clock when the clock was actually
enabled and used.

Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com>
---
 drivers/mmc/host/sdhci-esdhc.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index a2a0642..e70c4e6 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -73,6 +73,7 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
 	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
 		clock, host_clock / pre_div / div);
 
+	host->mmc->actual_clock = host->max_clk / pre_div / div;
 	pre_div >>= 1;
 	div--;
 
@@ -82,6 +83,11 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 	mdelay(1);
+
+	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) {
+		host->timeout_clk = host->mmc->actual_clock / 1000;
+		host->mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+	}
 out:
 	host->clock = clock;
 }
-- 
1.8.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] mmc:esdhc: Workaround about clock glitch issue on eSDHC host
  2013-09-24  8:12 [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Haijun Zhang
  2013-09-24  8:12 ` [PATCH 2/5] mmc:sdhc: Calculate timeout_clk from actual sd clock Haijun Zhang
  2013-09-24  8:12 ` [PATCH 3/5] mmc:esdhc: Update timeout clock according to actual clock Haijun Zhang
@ 2013-09-24  8:12 ` Haijun Zhang
  2013-09-24  8:12 ` [PATCH 5/5] mmc:esdhc: Avoid writting to power register Haijun Zhang
  2013-10-21  9:18 ` [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Zhang Haijun
  4 siblings, 0 replies; 6+ messages in thread
From: Haijun Zhang @ 2013-09-24  8:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: cbouatmailru, cjb, scottwood, X.Xie, ulf.hansson, Haijun Zhang,
	Haijun Zhang

A-003980: SDHC: Glitch is generated on the card clock with software reset or
clock divider change
Description: A glitch may occur on the SDHC card clock when the software sets
the RSTA bit (software reset) in the system control register. It can also be
generated by setting the clock divider value. The glitch produced can cause
the external card to switch to an unknown state. The occurrence is not
deterministic.
Workaround:
A simple workaround is to disable the SD card clock before the software reset,
and enable it when the module resumes normal operation.
The Host and the SD card are in a master-slave relationship. The Host provides
clock and control transfer across the interface. Therefore, any existing
operation is discarded when the Host controller is reset.
The recommended flow is as follows:
1. Software disable bit[3], SDCLKEN, of the System Control Register
2. Trigger software reset and/or set clock divider
3. Check bit[3], SDSTB, of the Present State Register for stable clock
4. Enable bit[3], SDCLKEN, of the System Control Register
Using the above method, the eSDHC cannot send command or transfer data when
there is a glitch in the clock line, and the glitch does not cause any issue.

Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com>
---
 drivers/mmc/host/sdhci-esdhc.h    | 25 ++++++++++++++---
 drivers/mmc/host/sdhci-of-esdhc.c | 56 +++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/sdhci.h         |  2 ++
 3 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index e70c4e6..432f9da 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -29,10 +29,14 @@
 #define ESDHC_CLOCK_MASK	0x0000fff0
 #define ESDHC_PREDIV_SHIFT	8
 #define ESDHC_DIVIDER_SHIFT	4
+#define ESDHC_CLOCK_CRDEN	0x00000008
 #define ESDHC_CLOCK_PEREN	0x00000004
 #define ESDHC_CLOCK_HCKEN	0x00000002
 #define ESDHC_CLOCK_IPGEN	0x00000001
 
+#define ESDHCI_PRESENT_STATE	0x24
+#define ESDHC_CLK_STABLE	0x00000008
+
 /* pltfm-specific */
 #define ESDHC_HOST_CONTROL_LE	0x20
 
@@ -47,7 +51,7 @@
 #define ESDHC_DMA_SYSCTL	0x40c
 #define ESDHC_DMA_SNOOP		0x00000040
 
-#define ESDHC_HOST_CONTROL_RES	0x05
+#define ESDHC_HOST_CONTROL_RES	0x01
 
 static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
 				   unsigned int host_clock)
@@ -55,13 +59,14 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
 	int pre_div = 2;
 	int div = 1;
 	u32 temp;
+	u32 timeout;
 
 	if (clock == 0)
 		goto out;
 
 	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
 	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
-		| ESDHC_CLOCK_MASK);
+		| ESDHC_CLOCK_MASK | ESDHC_CLOCK_CRDEN);
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
 	while (host_clock / pre_div / 16 > clock && pre_div < 256)
@@ -82,7 +87,21 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
 		| (div << ESDHC_DIVIDER_SHIFT)
 		| (pre_div << ESDHC_PREDIV_SHIFT));
 	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-	mdelay(1);
+
+	/* Wait max 20 ms */
+	timeout = 20;
+	while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & ESDHC_CLK_STABLE)) {
+		if (timeout == 0) {
+			pr_err("%s: Internal clock never stabilised.\n",
+					mmc_hostname(host->mmc));
+			return;
+		}
+		timeout--;
+		mdelay(1);
+	}
+
+	temp |= ESDHC_CLOCK_CRDEN;
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
 	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) {
 		host->timeout_clk = host->mmc->actual_clock / 1000;
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index e328252..f5de1e5 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -21,9 +21,11 @@
 #include <linux/mmc/host.h>
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
+#include <asm/mpc85xx.h>
 
 #define VENDOR_V_22	0x12
 #define VENDOR_V_23	0x13
+static u32 svr;
 static u32 esdhc_readl(struct sdhci_host *host, int reg)
 {
 	u32 ret;
@@ -225,6 +227,30 @@ static void esdhc_of_resume(struct sdhci_host *host)
 }
 #endif
 
+static void esdhc_platform_reset_enter(struct sdhci_host *host, u8 mask)
+{
+	if ((host->quirks2 & SDHCI_QUIRK2_DISABLE_CLOCK_BEFORE_RESET) &&
+			(mask & SDHCI_RESET_ALL)) {
+		u16 clk;
+
+		clk = esdhc_readw(host, SDHCI_CLOCK_CONTROL);
+		clk &= ~ESDHC_CLOCK_CRDEN;
+		esdhc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+	}
+}
+
+static void esdhc_platform_reset_exit(struct sdhci_host *host, u8 mask)
+{
+	if ((host->quirks2 & SDHCI_QUIRK2_DISABLE_CLOCK_BEFORE_RESET) &&
+			(mask & SDHCI_RESET_ALL)) {
+		u16 clk;
+
+		clk = esdhc_readw(host, SDHCI_CLOCK_CONTROL);
+		clk |= ESDHC_CLOCK_CRDEN;
+		esdhc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+	}
+}
+
 static void esdhc_of_platform_init(struct sdhci_host *host)
 {
 	u32 vvn;
@@ -236,6 +262,33 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
 
 	if (vvn > VENDOR_V_22)
 		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
+
+	/*
+	 * Check for A-005055: A glitch is generated on the card clock
+	 * due to software reset or a clock change
+	 * Impact list:
+	 * T4240-4160-R1.0 B4860-4420-R1.0-R2.0 P3041-R1.0-R1.1-R2.0
+	 * P2041-2040-R1.0-R1.1-R2.0 P1010-1014-R1.0 P5020-5010-R1.0-R2.0
+	 * P5040-5021-R1.0-R2.0-R2.1
+	 */
+	if (((SVR_SOC_VER(svr) == SVR_T4240) && (SVR_REV(svr) == 0x10)) ||
+		((SVR_SOC_VER(svr) == SVR_T4240) && (SVR_REV(svr) == 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_T4160) && (SVR_REV(svr) == 0x10)) ||
+		((SVR_SOC_VER(svr) == SVR_T4160) && (SVR_REV(svr) == 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_REV(svr) == 0x10)) ||
+		((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_REV(svr) == 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_B4420) && (SVR_REV(svr) == 0x10)) ||
+		((SVR_SOC_VER(svr) == SVR_B4420) && (SVR_REV(svr) == 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_P1010) && (SVR_REV(svr) == 0x10)) ||
+		((SVR_SOC_VER(svr) == SVR_P1014) && (SVR_REV(svr) == 0x10)) ||
+		((SVR_SOC_VER(svr) == SVR_P3041) && (SVR_REV(svr) <= 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_P5020) && (SVR_REV(svr) <= 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_P5010) && (SVR_REV(svr) <= 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_P5040) && (SVR_REV(svr) <= 0x21)) ||
+		((SVR_SOC_VER(svr) == SVR_P5021) && (SVR_REV(svr) <= 0x21)) ||
+		((SVR_SOC_VER(svr) == SVR_P2040) && (SVR_REV(svr) <= 0x20)) ||
+		((SVR_SOC_VER(svr) == SVR_P2041) && (SVR_REV(svr) <= 0x20)))
+		host->quirks2 |= SDHCI_QUIRK2_DISABLE_CLOCK_BEFORE_RESET;
 }
 
 static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
@@ -274,6 +327,8 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
 	.get_max_clock = esdhc_of_get_max_clock,
 	.get_min_clock = esdhc_of_get_min_clock,
 	.platform_init = esdhc_of_platform_init,
+	.platform_reset_enter = esdhc_platform_reset_enter,
+	.platform_reset_exit = esdhc_platform_reset_exit,
 #ifdef CONFIG_PM
 	.platform_suspend = esdhc_of_suspend,
 	.platform_resume = esdhc_of_resume,
@@ -299,6 +354,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
 	struct device_node *np;
 	int ret;
 
+	svr = mfspr(SPRN_SVR);
 	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
 	if (IS_ERR(host))
 		return PTR_ERR(host);
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 3e781b8..1f1e2fa 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -98,6 +98,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON		(1<<4)
 /* Controller has a non-standard host control register */
 #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL		(1<<5)
+/* Controller need to disable clock before reset all */
+#define SDHCI_QUIRK2_DISABLE_CLOCK_BEFORE_RESET		(1<<6)
 
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
-- 
1.8.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] mmc:esdhc: Avoid writting to power register
  2013-09-24  8:12 [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Haijun Zhang
                   ` (2 preceding siblings ...)
  2013-09-24  8:12 ` [PATCH 4/5] mmc:esdhc: Workaround about clock glitch issue on eSDHC host Haijun Zhang
@ 2013-09-24  8:12 ` Haijun Zhang
  2013-10-21  9:18 ` [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Zhang Haijun
  4 siblings, 0 replies; 6+ messages in thread
From: Haijun Zhang @ 2013-09-24  8:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: cbouatmailru, cjb, scottwood, X.Xie, ulf.hansson, Haijun Zhang,
	Haijun Zhang

eSDHC host don't have a standand power control register.
Also eSDHC host which support spec 1.0 and spec 2.0 don't
support voltage switch. So add this change avoid writing other
bit of this register by mistake.

Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com>
---
 drivers/mmc/host/sdhci-of-esdhc.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index f5de1e5..bc7de5e 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -141,6 +141,11 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
 	/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
 	if (reg == SDHCI_HOST_CONTROL)
 		val &= ~ESDHC_HOST_CONTROL_RES;
+
+	/* ESDHC host spec version 1.0 and 2.0 don't support voltage switch */
+	if ((reg == SDHCI_POWER_CONTROL) && (host->version < SDHCI_SPEC_300))
+		return;
+
 	sdhci_be32bs_writeb(host, val, reg);
 }
 
-- 
1.8.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease
  2013-09-24  8:12 [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Haijun Zhang
                   ` (3 preceding siblings ...)
  2013-09-24  8:12 ` [PATCH 5/5] mmc:esdhc: Avoid writting to power register Haijun Zhang
@ 2013-10-21  9:18 ` Zhang Haijun
  4 siblings, 0 replies; 6+ messages in thread
From: Zhang Haijun @ 2013-10-21  9:18 UTC (permalink / raw)
  To: Haijun Zhang, linux-mmc; +Cc: cbouatmailru, cjb, scottwood, X.Xie, ulf.hansson

Hi, all

Could any one help review this patch set for me?

Thanks in advance.

于 2013/9/24 16:12, Haijun Zhang 写道:
> At 50 Mhz SD_CLK period,
> the max timeout value = 2^27 * SD_CLK period ~= 2.69 sec.
>
> If max_discard_to was not designed, for mmc card preferred erase
> size should be used, for sd card just return UINT_MAX. Also add
> limit for data transfer, Use max_discard_to as max data timeout value
> to avoid timeout error in case data timeout was larger than
> 2.69 sec.
>
> For some crappy cards, the timeout value calculate from card was
> larger than UINT_MAX, in this case the timeout value write into
> register was not expected.
>
> This patch can reduce I/O error due to large timeout value for
> erase(CMD38) and write(CMD25) for some crappy cards.
>
> Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com>
> ---
>  drivers/mmc/core/core.c | 45 ++++++++++++++++++++++++++++++---------------
>  1 file changed, 30 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index bf18b6b..b429baa 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -757,6 +757,7 @@ EXPORT_SYMBOL(mmc_read_bkops_status);
>   */
>  void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
>  {
> +	struct mmc_host *host = card->host;
>  	unsigned int mult;
>  
>  	/*
> @@ -780,7 +781,12 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
>  	if (data->flags & MMC_DATA_WRITE)
>  		mult <<= card->csd.r2w_factor;
>  
> -	data->timeout_ns = card->csd.tacc_ns * mult;
> +	/* Avoid over flow for some crappy cards. */
> +	if ((UINT_MAX / mult) < card->csd.tacc_ns)
> +		data->timeout_ns = UINT_MAX;
> +	else
> +		data->timeout_ns = card->csd.tacc_ns * mult;
> +
>  	data->timeout_clks = card->csd.tacc_clks * mult;
>  
>  	/*
> @@ -842,6 +848,11 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
>  				data->timeout_ns =  100000000;	/* 100ms */
>  		}
>  	}
> +
> +	if (host->max_discard_to &&
> +			(host->max_discard_to <
> +			 (data->timeout_ns / 1000000)))
> +		data->timeout_ns = host->max_discard_to * 1000000;
>  }
>  EXPORT_SYMBOL(mmc_set_data_timeout);
>  
> @@ -1816,11 +1827,14 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
>  		unsigned int timeout_clks = card->csd.tacc_clks * mult;
>  		unsigned int timeout_us;
>  
> -		/* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
> -		if (card->csd.tacc_ns < 1000000)
> -			timeout_us = (card->csd.tacc_ns * mult) / 1000;
> -		else
> +		/*
> +		 * Avoid over flow for some crappy cards.
> +		 * e.g. tacc_ns=80000000 mult=1280
> +		 */
> +		if ((UINT_MAX / mult) < card->csd.tacc_ns)
>  			timeout_us = (card->csd.tacc_ns / 1000) * mult;
> +		else
> +			timeout_us = (card->csd.tacc_ns * mult) / 1000;
>  
>  		/*
>  		 * ios.clock is only a target.  The real clock rate might be
> @@ -2185,16 +2199,17 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
>  	struct mmc_host *host = card->host;
>  	unsigned int max_discard, max_trim;
>  
> -	if (!host->max_discard_to)
> -		return UINT_MAX;
> -
> -	/*
> -	 * Without erase_group_def set, MMC erase timeout depends on clock
> -	 * frequence which can change.  In that case, the best choice is
> -	 * just the preferred erase size.
> -	 */
> -	if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
> -		return card->pref_erase;
> +	if (!host->max_discard_to) {
> +		/*
> +		 * Without erase_group_def set, MMC erase timeout depends
> +		 * on clock frequence which can change.  In that case, the
> +		 * best choice is just the preferred erase size.
> +		 */
> +		if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1))
> +			return card->pref_erase;
> +		else
> +			return UINT_MAX;
> +	}
>  
>  	max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
>  	if (mmc_can_trim(card)) {

-- 
Thanks & Regards
Haijun.



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-10-21  9:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-24  8:12 [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Haijun Zhang
2013-09-24  8:12 ` [PATCH 2/5] mmc:sdhc: Calculate timeout_clk from actual sd clock Haijun Zhang
2013-09-24  8:12 ` [PATCH 3/5] mmc:esdhc: Update timeout clock according to actual clock Haijun Zhang
2013-09-24  8:12 ` [PATCH 4/5] mmc:esdhc: Workaround about clock glitch issue on eSDHC host Haijun Zhang
2013-09-24  8:12 ` [PATCH 5/5] mmc:esdhc: Avoid writting to power register Haijun Zhang
2013-10-21  9:18 ` [PATCH 1/5] mmc:core: Add restrictions for data transfer and card ease Zhang Haijun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).