summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorHaijun Zhang <haijun.zhang@freescale.com>2013-03-19 09:53:28 (GMT)
committerFleming Andrew-AFLEMING <AFLEMING@freescale.com>2013-03-27 23:30:11 (GMT)
commita11daefdf9408f331cff193a98400b36dad56ba0 (patch)
tree09b7df2ca98c8b507f5f82daddf0b27cf90c0e14 /drivers/mmc
parent5ec0b35b09e7e5748d473fbba6169ab5bc92e61d (diff)
downloadlinux-fsl-qoriq-a11daefdf9408f331cff193a98400b36dad56ba0.tar.xz
mmc:core: Add restrictions for data transfer and card erase
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 data timeout value to avoid timeout error in case data timeout was larger than max_discard_to. This patch can fix 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> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com> Change-Id: Ib34a7bdb10714b9ab8be0c2b9c2e21bd396edd0f Reviewed-on: http://git.am.freescale.net:8181/405 Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com> Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c45
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h7
2 files changed, 38 insertions, 14 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 89b793e..e74504e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -639,6 +639,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;
/*
@@ -662,7 +663,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;
/*
@@ -724,6 +730,12 @@ 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);
@@ -1550,11 +1562,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
@@ -1919,16 +1934,18 @@ 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;
+ 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;
+ /*
+ * 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)) {
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index c2c2739..34b64f4 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -48,6 +48,7 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
int pre_div = 2;
int div = 1;
u32 temp;
+ u32 actual_clk;
if (clock == 0)
goto out;
@@ -66,6 +67,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->max_clk / pre_div / div);
+ actual_clk = host->max_clk / pre_div / div;
pre_div >>= 1;
div--;
@@ -75,6 +77,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 = actual_clk / 1000;
+ host->mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+ }
out:
host->clock = clock;
}