From e7747475b61fdc2a4a412475a9d64d8c309916e3 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 1 Mar 2012 13:18:05 +0100 Subject: mmc: core: Fixup suspend/resume issues for UHS-I cards Even if cards supports 1.8V I/O voltage those should anyway be initialized at 3.3V I/O according to (e)MMC, SD and SDIO specs. Some eMMC and embedded SDIO devices are able to be initialized at 1.8V as well, but it is better to be safe. Do note that initialization in this context means that the card has been completely powered off, otherwise the card will remain at the last I/O voltage level that were negotitiated. Due to the above being taken care of the suspend/resume issues for UHS-I SD-cards has been fixed. Signed-off-by: Ulf Hansson Acked-by: Philip Rakity Acked-by: Linus Walleij Tested-by: Subhash Jadavani Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 690255c7d4dc..132378b89d76 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2068,6 +2068,9 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) */ mmc_hw_reset_for_init(host); + /* Initialization should be done at 3.3 V I/O voltage. */ + mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0); + /* * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 -- cgit v1.2.3-59-g8ed1b From 7b2fd4f23f72c13a78c0892d330dde305ef2fb80 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Tue, 7 Feb 2012 14:13:10 +0900 Subject: mmc: core: add a debug message for SET_BLOCK_COUNT This patch is added just debug message. Almost features need to use the CMD23. But we didn't see the debug message for sbc. If sbc's message can see, should be help for debugging. (We can check whether use the cmd23 or not.) Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 132378b89d76..faa0af10d334 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -188,6 +188,12 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) struct scatterlist *sg; #endif + if (mrq->sbc) { + pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", + mmc_hostname(host), mrq->sbc->opcode, + mrq->sbc->arg, mrq->sbc->flags); + } + pr_debug("%s: starting CMD%u arg %08x flags %08x\n", mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); -- cgit v1.2.3-59-g8ed1b From f0cc9cf99326926fd76f77645c48d16d647802eb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Feb 2012 10:42:39 +0100 Subject: mmc: core: Detect card removal on I/O error To prevent I/O as soon as possible at card removal, a new detect work is re-scheduled without a delay to let a rescan remove the card device as soon as possible. Additionally, MMC_CAP2_DETECT_ON_ERR can now be used to handle "slowly" removed cards that a scheduled detect work did not detect as removed. To prevent further I/O requests for these lingering removed cards, check if card has been removed and then schedule a detect work to properly remove it. Signed-off-by: Ulf Hansson Reviewed-by: Namjae Jeon Acked-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 24 +++++++++++++++++++++--- include/linux/mmc/host.h | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index faa0af10d334..436409f7f7bd 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2121,18 +2121,36 @@ int _mmc_detect_card_removed(struct mmc_host *host) int mmc_detect_card_removed(struct mmc_host *host) { struct mmc_card *card = host->card; + int ret; WARN_ON(!host->claimed); + + if (!card) + return 1; + + ret = mmc_card_removed(card); /* * The card will be considered unchanged unless we have been asked to * detect a change or host requires polling to provide card detection. */ - if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL)) - return mmc_card_removed(card); + if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) && + !(host->caps2 & MMC_CAP2_DETECT_ON_ERR)) + return ret; host->detect_change = 0; + if (!ret) { + ret = _mmc_detect_card_removed(host); + if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) { + /* + * Schedule a detect work as soon as possible to let a + * rescan handle the card removal. + */ + cancel_delayed_work(&host->detect); + mmc_detect_change(host, 0); + } + } - return _mmc_detect_card_removed(host); + return ret; } EXPORT_SYMBOL(mmc_detect_card_removed); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index ee2b0363c040..d1d3743fde90 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -258,6 +258,7 @@ struct mmc_host { #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ MMC_CAP2_HS200_1_2V_SDR) #define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ +#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */ mmc_pm_flag_t pm_caps; /* supported pm features */ unsigned int power_notify_type; -- cgit v1.2.3-59-g8ed1b From 907d2e7cc7ebba4ab398422a7f0435e1802be65b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 29 Feb 2012 09:17:21 +0200 Subject: mmc: start removing enable / disable API Most parts of the enable / disable API are no longer used and can be removed. Signed-off-by: Adrian Hunter Tested-by: Venkatraman S Tested-by: Jaehoon Chung Signed-off-by: Chris Ball --- arch/arm/mach-exynos/mach-nuri.c | 5 +- arch/arm/mach-exynos/mach-universal_c210.c | 9 +- drivers/mmc/core/core.c | 187 +++-------------------------- drivers/mmc/core/host.c | 1 - drivers/mmc/core/host.h | 1 - drivers/mmc/host/davinci_mmc.c | 4 - drivers/mmc/host/omap_hsmmc.c | 15 +-- include/linux/mmc/core.h | 1 - include/linux/mmc/host.h | 46 +------ 9 files changed, 27 insertions(+), 242 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index aa37179d776c..3cdabd39f97c 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -109,7 +109,7 @@ static struct s3c_sdhci_platdata nuri_hsmmc0_data __initdata = { .max_width = 8, .host_caps = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_DISABLE | MMC_CAP_ERASE), + MMC_CAP_ERASE), .cd_type = S3C_SDHCI_CD_PERMANENT, .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, }; @@ -148,8 +148,7 @@ static struct platform_device emmc_fixed_voltage = { static struct s3c_sdhci_platdata nuri_hsmmc2_data __initdata = { .max_width = 4, .host_caps = MMC_CAP_4_BIT_DATA | - MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_DISABLE, + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, .ext_cd_gpio = EXYNOS4_GPX3(3), /* XEINT_27 */ .ext_cd_gpio_invert = 1, .cd_type = S3C_SDHCI_CD_GPIO, diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index b2d495b31094..87e3dcf714b5 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -736,8 +736,7 @@ static struct platform_device universal_gpio_keys = { static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = { .max_width = 8, .host_caps = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA | - MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_DISABLE), + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), .cd_type = S3C_SDHCI_CD_PERMANENT, .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, }; @@ -775,8 +774,7 @@ static struct platform_device mmc0_fixed_voltage = { static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = { .max_width = 4, .host_caps = MMC_CAP_4_BIT_DATA | - MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_DISABLE, + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, .ext_cd_gpio = EXYNOS4_GPX3(4), /* XEINT_28 */ .ext_cd_gpio_invert = 1, .cd_type = S3C_SDHCI_CD_GPIO, @@ -787,8 +785,7 @@ static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = { static struct s3c_sdhci_platdata universal_hsmmc3_data __initdata = { .max_width = 4, .host_caps = MMC_CAP_4_BIT_DATA | - MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_DISABLE, + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, .cd_type = S3C_SDHCI_CD_EXTERNAL, }; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 436409f7f7bd..9b56674ddc2a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -604,105 +604,6 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz) } EXPORT_SYMBOL(mmc_align_data_size); -/** - * mmc_host_enable - enable a host. - * @host: mmc host to enable - * - * Hosts that support power saving can use the 'enable' and 'disable' - * methods to exit and enter power saving states. For more information - * see comments for struct mmc_host_ops. - */ -int mmc_host_enable(struct mmc_host *host) -{ - if (!(host->caps & MMC_CAP_DISABLE)) - return 0; - - if (host->en_dis_recurs) - return 0; - - if (host->nesting_cnt++) - return 0; - - cancel_delayed_work_sync(&host->disable); - - if (host->enabled) - return 0; - - if (host->ops->enable) { - int err; - - host->en_dis_recurs = 1; - mmc_host_clk_hold(host); - err = host->ops->enable(host); - mmc_host_clk_release(host); - host->en_dis_recurs = 0; - - if (err) { - pr_debug("%s: enable error %d\n", - mmc_hostname(host), err); - return err; - } - } - host->enabled = 1; - return 0; -} -EXPORT_SYMBOL(mmc_host_enable); - -static int mmc_host_do_disable(struct mmc_host *host, int lazy) -{ - if (host->ops->disable) { - int err; - - host->en_dis_recurs = 1; - mmc_host_clk_hold(host); - err = host->ops->disable(host, lazy); - mmc_host_clk_release(host); - host->en_dis_recurs = 0; - - if (err < 0) { - pr_debug("%s: disable error %d\n", - mmc_hostname(host), err); - return err; - } - if (err > 0) { - unsigned long delay = msecs_to_jiffies(err); - - mmc_schedule_delayed_work(&host->disable, delay); - } - } - host->enabled = 0; - return 0; -} - -/** - * mmc_host_disable - disable a host. - * @host: mmc host to disable - * - * Hosts that support power saving can use the 'enable' and 'disable' - * methods to exit and enter power saving states. For more information - * see comments for struct mmc_host_ops. - */ -int mmc_host_disable(struct mmc_host *host) -{ - int err; - - if (!(host->caps & MMC_CAP_DISABLE)) - return 0; - - if (host->en_dis_recurs) - return 0; - - if (--host->nesting_cnt) - return 0; - - if (!host->enabled) - return 0; - - err = mmc_host_do_disable(host, 0); - return err; -} -EXPORT_SYMBOL(mmc_host_disable); - /** * __mmc_claim_host - exclusively claim a host * @host: mmc host to claim @@ -741,8 +642,8 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) wake_up(&host->wq); spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); - if (!stop) - mmc_host_enable(host); + if (host->ops->enable && !stop && host->claim_cnt == 1) + host->ops->enable(host); return stop; } @@ -767,21 +668,28 @@ int mmc_try_claim_host(struct mmc_host *host) claimed_host = 1; } spin_unlock_irqrestore(&host->lock, flags); + if (host->ops->enable && claimed_host && host->claim_cnt == 1) + host->ops->enable(host); return claimed_host; } EXPORT_SYMBOL(mmc_try_claim_host); /** - * mmc_do_release_host - release a claimed host + * mmc_release_host - release a host * @host: mmc host to release * - * If you successfully claimed a host, this function will - * release it again. + * Release a MMC host, allowing others to claim the host + * for their operations. */ -void mmc_do_release_host(struct mmc_host *host) +void mmc_release_host(struct mmc_host *host) { unsigned long flags; + WARN_ON(!host->claimed); + + if (host->ops->disable && host->claim_cnt == 1) + host->ops->disable(host); + spin_lock_irqsave(&host->lock, flags); if (--host->claim_cnt) { /* Release for nested claim */ @@ -793,67 +701,6 @@ void mmc_do_release_host(struct mmc_host *host) wake_up(&host->wq); } } -EXPORT_SYMBOL(mmc_do_release_host); - -void mmc_host_deeper_disable(struct work_struct *work) -{ - struct mmc_host *host = - container_of(work, struct mmc_host, disable.work); - - /* If the host is claimed then we do not want to disable it anymore */ - if (!mmc_try_claim_host(host)) - return; - mmc_host_do_disable(host, 1); - mmc_do_release_host(host); -} - -/** - * mmc_host_lazy_disable - lazily disable a host. - * @host: mmc host to disable - * - * Hosts that support power saving can use the 'enable' and 'disable' - * methods to exit and enter power saving states. For more information - * see comments for struct mmc_host_ops. - */ -int mmc_host_lazy_disable(struct mmc_host *host) -{ - if (!(host->caps & MMC_CAP_DISABLE)) - return 0; - - if (host->en_dis_recurs) - return 0; - - if (--host->nesting_cnt) - return 0; - - if (!host->enabled) - return 0; - - if (host->disable_delay) { - mmc_schedule_delayed_work(&host->disable, - msecs_to_jiffies(host->disable_delay)); - return 0; - } else - return mmc_host_do_disable(host, 1); -} -EXPORT_SYMBOL(mmc_host_lazy_disable); - -/** - * mmc_release_host - release a host - * @host: mmc host to release - * - * Release a MMC host, allowing others to claim the host - * for their operations. - */ -void mmc_release_host(struct mmc_host *host) -{ - WARN_ON(!host->claimed); - - mmc_host_lazy_disable(host); - - mmc_do_release_host(host); -} - EXPORT_SYMBOL(mmc_release_host); /* @@ -2227,8 +2074,6 @@ void mmc_stop_host(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); #endif - if (host->caps & MMC_CAP_DISABLE) - cancel_delayed_work(&host->disable); cancel_delayed_work_sync(&host->detect); mmc_flush_scheduled_work(); @@ -2423,13 +2268,11 @@ int mmc_suspend_host(struct mmc_host *host) { int err = 0; - if (host->caps & MMC_CAP_DISABLE) - cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); if (mmc_try_claim_host(host)) { err = mmc_cache_ctrl(host, 0); - mmc_do_release_host(host); + mmc_release_host(host); } else { err = -EBUSY; } @@ -2450,7 +2293,7 @@ int mmc_suspend_host(struct mmc_host *host) if (host->bus_ops->suspend) { err = host->bus_ops->suspend(host); } - mmc_do_release_host(host); + mmc_release_host(host); if (err == -ENOSYS || !host->bus_ops->resume) { /* diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index c3704e293a7b..91c84c7a1829 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -330,7 +330,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); - INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); #ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify; #endif diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 08a7852ade44..f2ab9e578126 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -14,7 +14,6 @@ int mmc_register_host_class(void); void mmc_unregister_host_class(void); -void mmc_host_deeper_disable(struct work_struct *work); #endif diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 64a8325a4a8a..8de9c9bdba0b 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1418,17 +1418,14 @@ static int davinci_mmcsd_suspend(struct device *dev) struct mmc_davinci_host *host = platform_get_drvdata(pdev); int ret; - mmc_host_enable(host->mmc); ret = mmc_suspend_host(host->mmc); if (!ret) { writel(0, host->base + DAVINCI_MMCIM); mmc_davinci_reset_ctrl(host, 1); - mmc_host_disable(host->mmc); clk_disable(host->clk); host->suspended = 1; } else { host->suspended = 0; - mmc_host_disable(host->mmc); } return ret; @@ -1444,7 +1441,6 @@ static int davinci_mmcsd_resume(struct device *dev) return 0; clk_enable(host->clk); - mmc_host_enable(host->mmc); mmc_davinci_reset_ctrl(host, 0); ret = mmc_resume_host(host->mmc); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e5501704b2db..98adf0c51e05 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -167,7 +167,6 @@ struct omap_hsmmc_host { int got_dbclk; int response_busy; int context_loss; - int dpm_state; int vdd; int protect_card; int reqs_blocked; @@ -1619,7 +1618,7 @@ static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) return 0; } -static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy) +static int omap_hsmmc_disable_fclk(struct mmc_host *mmc) { struct omap_hsmmc_host *host = mmc_priv(mmc); @@ -1653,15 +1652,8 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data) if (host->pdata->get_context_loss_count) context_loss = host->pdata->get_context_loss_count(host->dev); - seq_printf(s, "mmc%d:\n" - " enabled:\t%d\n" - " dpm_state:\t%d\n" - " nesting_cnt:\t%d\n" - " ctx_loss:\t%d:%d\n" - "\nregs:\n", - mmc->index, mmc->enabled ? 1 : 0, - host->dpm_state, mmc->nesting_cnt, - host->context_loss, context_loss); + seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n", + mmc->index, host->context_loss, context_loss); if (host->suspended) { seq_printf(s, "host suspended, can't read registers\n"); @@ -1800,7 +1792,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_context_save(host); - mmc->caps |= MMC_CAP_DISABLE; if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 87a976cc5654..2bfa589764de 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -175,7 +175,6 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); extern void mmc_release_host(struct mmc_host *host); -extern void mmc_do_release_host(struct mmc_host *host); extern int mmc_try_claim_host(struct mmc_host *host); extern int mmc_flush_cache(struct mmc_card *); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index d1d3743fde90..e05bd241c676 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -80,34 +80,11 @@ struct mmc_ios { struct mmc_host_ops { /* - * Hosts that support power saving can use the 'enable' and 'disable' - * methods to exit and enter power saving states. 'enable' is called - * when the host is claimed and 'disable' is called (or scheduled with - * a delay) when the host is released. The 'disable' is scheduled if - * the disable delay set by 'mmc_set_disable_delay()' is non-zero, - * otherwise 'disable' is called immediately. 'disable' may be - * scheduled repeatedly, to permit ever greater power saving at the - * expense of ever greater latency to re-enable. Rescheduling is - * determined by the return value of the 'disable' method. A positive - * value gives the delay in milliseconds. - * - * In the case where a host function (like set_ios) may be called - * with or without the host claimed, enabling and disabling can be - * done directly and will nest correctly. Call 'mmc_host_enable()' and - * 'mmc_host_lazy_disable()' for this purpose, but note that these - * functions must be paired. - * - * Alternatively, 'mmc_host_enable()' may be paired with - * 'mmc_host_disable()' which calls 'disable' immediately. In this - * case the 'disable' method will be called with 'lazy' set to 0. - * This is mainly useful for error paths. - * - * Because lazy disable may be called from a work queue, the 'disable' - * method must claim the host when 'lazy' != 0, which will work - * correctly because recursion is detected and handled. + * 'enable' is called when the host is claimed and 'disable' is called + * when the host is released. 'enable' and 'disable' are deprecated. */ int (*enable)(struct mmc_host *host); - int (*disable)(struct mmc_host *host, int lazy); + int (*disable)(struct mmc_host *host); /* * It is optional for the host to implement pre_req and post_req in * order to support double buffering of requests (prepare one @@ -218,7 +195,7 @@ struct mmc_host { #define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */ #define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */ #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */ -#define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */ + #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ #define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */ @@ -301,13 +278,7 @@ struct mmc_host { unsigned int removed:1; /* host is being removed */ #endif - /* Only used with MMC_CAP_DISABLE */ - int enabled; /* host is enabled */ int rescan_disable; /* disable card detection */ - int nesting_cnt; /* "enable" nesting count */ - int en_dis_recurs; /* detect recursion */ - unsigned int disable_delay; /* disable delay in msecs */ - struct delayed_work disable; /* disabling work */ struct mmc_card *card; /* device attached to this host */ @@ -407,17 +378,8 @@ int mmc_card_awake(struct mmc_host *host); int mmc_card_sleep(struct mmc_host *host); int mmc_card_can_sleep(struct mmc_host *host); -int mmc_host_enable(struct mmc_host *host); -int mmc_host_disable(struct mmc_host *host); -int mmc_host_lazy_disable(struct mmc_host *host); int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *); -static inline void mmc_set_disable_delay(struct mmc_host *host, - unsigned int disable_delay) -{ - host->disable_delay = disable_delay; -} - /* Module parameter */ extern bool mmc_assume_removable; -- cgit v1.2.3-59-g8ed1b From 956d9fd5eb3cbb322440844ed341145707bd71f8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 5 Mar 2012 15:52:43 +0100 Subject: mmc: core: Clean up after mmc_pre_req if card was removed Make sure mmc_start_req cancels the prepared job, if the request was prevented to be started due to the card has been removed. This bug was introduced in commit: mmc: allow upper layers to know immediately if card has been removed Signed-off-by: Ulf Hansson Reviewed-by: Per Forlin Tested-by: Jaehoon Chung Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 9b56674ddc2a..14f262e9246d 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -249,16 +249,17 @@ static void mmc_wait_done(struct mmc_request *mrq) complete(&mrq->completion); } -static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) +static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) { init_completion(&mrq->completion); mrq->done = mmc_wait_done; if (mmc_card_removed(host->card)) { mrq->cmd->error = -ENOMEDIUM; complete(&mrq->completion); - return; + return -ENOMEDIUM; } mmc_start_request(host, mrq); + return 0; } static void mmc_wait_for_req_done(struct mmc_host *host, @@ -342,6 +343,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, struct mmc_async_req *areq, int *error) { int err = 0; + int start_err = 0; struct mmc_async_req *data = host->areq; /* Prepare a new request */ @@ -351,30 +353,23 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, if (host->areq) { mmc_wait_for_req_done(host, host->areq->mrq); err = host->areq->err_check(host->card, host->areq); - if (err) { - /* post process the completed failed request */ - mmc_post_req(host, host->areq->mrq, 0); - if (areq) - /* - * Cancel the new prepared request, because - * it can't run until the failed - * request has been properly handled. - */ - mmc_post_req(host, areq->mrq, -EINVAL); - - host->areq = NULL; - goto out; - } } - if (areq) - __mmc_start_req(host, areq->mrq); + if (!err && areq) + start_err = __mmc_start_req(host, areq->mrq); if (host->areq) mmc_post_req(host, host->areq->mrq, 0); - host->areq = areq; - out: + /* Cancel a prepared request if it was not started. */ + if ((err || start_err) && areq) + mmc_post_req(host, areq->mrq, -EINVAL); + + if (err) + host->areq = NULL; + else + host->areq = areq; + if (error) *error = err; return data; -- cgit v1.2.3-59-g8ed1b From 3bdc9ba892d6a294d16e9e6e0c4041926aa3d58c Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 12 Mar 2012 04:58:00 -0600 Subject: mmc: use really long write timeout to deal with crappy cards Several people have noticed that crappy SD cards take much longer to complete multiple block writes than the 300ms that Linux specifies. Try to work around this by using a three second write timeout instead. This is a generalized version of a patch from Chase Maupin , whose patch description said: * With certain SD cards timeouts like the following have been seen due to an improper calculation of the dto value: mmcblk0: error -110 transferring data, sector 4126233, nr 8, card status 0xc00 * By removing the dto calculation and setting the timeout value to the maximum specified by the SD card specification part A2 section 2.2.15 these timeouts can be avoided. * This change has been used by beagleboard users as well as the Texas Instruments SDK without a negative impact. * There are multiple discussion threads about this but the most relevant ones are: * http://talk.maemo.org/showthread.php?p=1000707#post1000707 * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg42213.html * Original proposal for this fix was done by Sukumar Ghoral of Texas Instruments * Tested using a Texas Instruments AM335x EVM Signed-off-by: Paul Walmsley Tested-by: Tony Lindgren Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 14f262e9246d..7474c47b9c08 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -527,10 +527,14 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) if (data->flags & MMC_DATA_WRITE) /* - * The limit is really 250 ms, but that is - * insufficient for some crappy cards. + * The MMC spec "It is strongly recommended + * for hosts to implement more than 500ms + * timeout value even if the card indicates + * the 250ms maximum busy length." Even the + * previous value of 300ms is known to be + * insufficient for some cards. */ - limit_us = 300000; + limit_us = 3000000; else limit_us = 100000; -- cgit v1.2.3-59-g8ed1b