In MFLD platform, sdhci host controller cannot handle so many sectors at one time since controller may generate a timeout interrupt before it finishes the erase. It is an architecture issue.
So MFLD sdhci host controller can set the timeout control register with the maximum value before starting each erase command by using this quirk. This quirk also can let MFLD sdhci host controller erase only one erase block at one time. Signed-off-by: Chuanxiao Dong <[email protected]> --- drivers/mmc/core/core.c | 4 ++++ drivers/mmc/host/sdhci-pci.c | 2 ++ drivers/mmc/host/sdhci.c | 10 ++++++++++ include/linux/mmc/sdhci.h | 2 ++ 4 files changed, 18 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f28ae28..c77d455 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -168,6 +168,9 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->cmd->error = 0; mrq->cmd->mrq = mrq; + if (mrq->cmd->opcode != MMC_ERASE) + mrq->cmd->erase_timeout = 0; + if (mrq->data) { BUG_ON(mrq->data->blksz > host->max_blk_size); BUG_ON(mrq->data->blocks > host->max_blk_count); @@ -188,6 +191,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->data->stop = mrq->stop; mrq->stop->error = 0; mrq->stop->mrq = mrq; + mrq->stop->erase_timeout = 0; } } host->ops->request(host, mrq); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 7bdbd9c..845e134 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -180,11 +180,13 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = { static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { .quirks = SDHCI_QUIRK_MFD_SD_RESTRICTION | + SDHCI_QUIRK_FORCE_ERASE_SINGLE | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = { .quirks = SDHCI_QUIRK_MFD_EMMC_SDIO_RESTRICTION | + SDHCI_QUIRK_FORCE_ERASE_SINGLE | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, }; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index f6a2b8a..c3989d5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -997,6 +997,12 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if (host->quirks & SDHCI_QUIRK_SERIALIZE) sdhci_clock_reset(host); + if (host->quirks & SDHCI_QUIRK_FORCE_ERASE_SINGLE) { + /* Set the timeout to be the maximum value */ + if (cmd->erase_timeout) + sdhci_writeb(host, 0xE, SDHCI_TIMEOUT_CONTROL); + } + sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } @@ -1943,6 +1949,10 @@ int sdhci_add_host(struct sdhci_host *host) mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; mmc->f_max = host->max_clk; mmc->caps |= MMC_CAP_SDIO_IRQ; + mmc->caps |= MMC_CAP_ERASE; + + if (host->quirks & SDHCI_QUIRK_FORCE_ERASE_SINGLE) + mmc->caps |= MMC_CAP_ERASE_SINGLE; if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index dc712bb..6a4fa1f 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -91,6 +91,8 @@ struct sdhci_host { /* Controller of Medfield specific restriction */ #define SDHCI_QUIRK_MFD_SD_RESTRICTION (1ULL<<33) #define SDHCI_QUIRK_MFD_EMMC_SDIO_RESTRICTION (1ULL<<34) +/* Controller has an issue with erase/trim the whole device at one time */ +#define SDHCI_QUIRK_FORCE_ERASE_SINGLE (1ULL<<35) int irq; /* Device IRQ */ -- 1.6.6.1 _______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
