diff options
author | Haijun Zhang <haijun.zhang@freescale.com> | 2013-03-19 09:53:28 (GMT) |
---|---|---|
committer | Fleming Andrew-AFLEMING <AFLEMING@freescale.com> | 2013-03-27 23:30:11 (GMT) |
commit | a11daefdf9408f331cff193a98400b36dad56ba0 (patch) | |
tree | 09b7df2ca98c8b507f5f82daddf0b27cf90c0e14 /drivers/mmc | |
parent | 5ec0b35b09e7e5748d473fbba6169ab5bc92e61d (diff) | |
download | linux-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.c | 45 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc.h | 7 |
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; } |