diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-09 08:39:39 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-09 08:39:39 -0700 |
commit | 97e18dc007546fce8e99098480b921a02ebb3037 (patch) | |
tree | f38c022d034e0172e83f6972983577f790f24dac /drivers/mmc | |
parent | 042f7b7cbd1e531278a09c449563165ba1f07673 (diff) | |
parent | c67480173f72e883235dd0ad09d90156c8f87600 (diff) |
Merge tag 'mmc-updates-for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC updates from Chris Ball:
"MMC highlights for 3.15:
Core:
- CONFIG_MMC_UNSAFE_RESUME=y is now default behavior
- DT bindings for SDHCI UHS, eMMC HS200, high-speed DDR, at 1.8/1.2V
- Add GPIO descriptor based slot-gpio card detect API
Drivers:
- dw_mmc: Refactor SOCFPGA support as a variant inside dw_mmc-pltfm.c
- mmci: Support HW busy detection on ux500
- omap: Support MMC_ERASE
- omap_hsmmc: Support MMC_PM_KEEP_POWER, MMC_PM_WAKE_SDIO_IRQ, (a)cmd23
- rtsx: Support pre-req/post-req async
- sdhci: Add support for Realtek RTS5250 controllers
- sdhci-acpi: Add support for 80860F16, fix 80860F14/SDIO card detect
- sdhci-msm: Add new driver for Qualcomm SDHCI chipset support
- sdhci-pxav3: Add support for Marvell Armada 380 and 385 SoCs"
* tag 'mmc-updates-for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (102 commits)
mmc: sdhci-acpi: Intel SDIO has broken card detect
mmc: sdhci-pxav3: add support for the Armada 38x SDHCI controller
mmc: sdhci-msm: Add platform_execute_tuning implementation
mmc: sdhci-msm: Initial support for Qualcomm chipsets
mmc: sdhci-msm: Qualcomm SDHCI binding documentation
sdhci: only reprogram retuning timer when flag is set
mmc: rename ARCH_BCM to ARCH_BCM_MOBILE
mmc: sdhci: Allow for irq being shared
mmc: sdhci-acpi: Add device id 80860F16
mmc: sdhci-acpi: Fix broken card detect for ACPI HID 80860F14
mmc: slot-gpio: Add GPIO descriptor based CD GPIO API
mmc: slot-gpio: Split out CD IRQ request into a separate function
mmc: slot-gpio: Record GPIO descriptors instead of GPIO numbers
Revert "dts: socfpga: Add support for SD/MMC on the SOCFPGA platform"
mmc: sdhci-spear: use generic card detection gpio support
mmc: sdhci-spear: remove support for power gpio
mmc: sdhci-spear: simplify resource handling
mmc: sdhci-spear: fix platform_data usage
mmc: sdhci-spear: fix error handling paths for DT
mmc: sdhci-bcm-kona: fix build errors when built-in
...
Diffstat (limited to 'drivers/mmc')
37 files changed, 1978 insertions, 1093 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 7b5424f398ac..452782bffebc 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -415,8 +415,7 @@ static int ioctl_do_sanitize(struct mmc_card *card) { int err; - if (!(mmc_can_sanitize(card) && - (card->host->caps2 & MMC_CAP2_SANITIZE))) { + if (!mmc_can_sanitize(card)) { pr_warn("%s: %s - SANITIZE is not supported\n", mmc_hostname(card->host), __func__); err = -EOPNOTSUPP; @@ -722,19 +721,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) return result; } -static int send_stop(struct mmc_card *card, u32 *status) -{ - struct mmc_command cmd = {0}; - int err; - - cmd.opcode = MMC_STOP_TRANSMISSION; - cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - err = mmc_wait_for_cmd(card->host, &cmd, 5); - if (err == 0) - *status = cmd.resp[0]; - return err; -} - static int get_card_status(struct mmc_card *card, u32 *status, int retries) { struct mmc_command cmd = {0}; @@ -750,6 +736,99 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries) return err; } +static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, + bool hw_busy_detect, struct request *req, int *gen_err) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); + int err = 0; + u32 status; + + do { + err = get_card_status(card, &status, 5); + if (err) { + pr_err("%s: error %d requesting status\n", + req->rq_disk->disk_name, err); + return err; + } + + if (status & R1_ERROR) { + pr_err("%s: %s: error sending status cmd, status %#x\n", + req->rq_disk->disk_name, __func__, status); + *gen_err = 1; + } + + /* We may rely on the host hw to handle busy detection.*/ + if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && + hw_busy_detect) + break; + + /* + * Timeout if the device never becomes ready for data and never + * leaves the program state. + */ + if (time_after(jiffies, timeout)) { + pr_err("%s: Card stuck in programming state! %s %s\n", + mmc_hostname(card->host), + req->rq_disk->disk_name, __func__); + return -ETIMEDOUT; + } + + /* + * Some cards mishandle the status bits, + * so make sure to check both the busy + * indication and the card state. + */ + } while (!(status & R1_READY_FOR_DATA) || + (R1_CURRENT_STATE(status) == R1_STATE_PRG)); + + return err; +} + +static int send_stop(struct mmc_card *card, unsigned int timeout_ms, + struct request *req, int *gen_err, u32 *stop_status) +{ + struct mmc_host *host = card->host; + struct mmc_command cmd = {0}; + int err; + bool use_r1b_resp = rq_data_dir(req) == WRITE; + + /* + * Normally we use R1B responses for WRITE, but in cases where the host + * has specified a max_busy_timeout we need to validate it. A failure + * means we need to prevent the host from doing hw busy detection, which + * is done by converting to a R1 response instead. + */ + if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) + use_r1b_resp = false; + + cmd.opcode = MMC_STOP_TRANSMISSION; + if (use_r1b_resp) { + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; + cmd.busy_timeout = timeout_ms; + } else { + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + } + + err = mmc_wait_for_cmd(host, &cmd, 5); + if (err) + return err; + + *stop_status = cmd.resp[0]; + + /* No need to check card status in case of READ. */ + if (rq_data_dir(req) == READ) + return 0; + + if (!mmc_host_is_spi(host) && + (*stop_status & R1_ERROR)) { + pr_err("%s: %s: general error sending stop command, resp %#x\n", + req->rq_disk->disk_name, __func__, *stop_status); + *gen_err = 1; + } + + return card_busy_detect(card, timeout_ms, use_r1b_resp, req, gen_err); +} + #define ERR_NOMEDIUM 3 #define ERR_RETRY 2 #define ERR_ABORT 1 @@ -866,26 +945,21 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, */ if (R1_CURRENT_STATE(status) == R1_STATE_DATA || R1_CURRENT_STATE(status) == R1_STATE_RCV) { - err = send_stop(card, &stop_status); - if (err) + err = send_stop(card, + DIV_ROUND_UP(brq->data.timeout_ns, 1000000), + req, gen_err, &stop_status); + if (err) { pr_err("%s: error %d sending stop command\n", req->rq_disk->disk_name, err); - - /* - * If the stop cmd also timed out, the card is probably - * not present, so abort. Other errors are bad news too. - */ - if (err) + /* + * If the stop cmd also timed out, the card is probably + * not present, so abort. Other errors are bad news too. + */ return ERR_ABORT; + } + if (stop_status & R1_CARD_ECC_FAILED) *ecc_err = 1; - if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) - if (stop_status & R1_ERROR) { - pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n", - req->rq_disk->disk_name, __func__, - stop_status); - *gen_err = 1; - } } /* Check for set block count errors */ @@ -1157,8 +1231,7 @@ static int mmc_blk_err_check(struct mmc_card *card, * program mode, which we have to wait for it to complete. */ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { - u32 status; - unsigned long timeout; + int err; /* Check stop command response */ if (brq->stop.resp[0] & R1_ERROR) { @@ -1168,39 +1241,10 @@ static int mmc_blk_err_check(struct mmc_card *card, gen_err = 1; } - timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS); - do { - int err = get_card_status(card, &status, 5); - if (err) { - pr_err("%s: error %d requesting status\n", - req->rq_disk->disk_name, err); - return MMC_BLK_CMD_ERR; - } - - if (status & R1_ERROR) { - pr_err("%s: %s: general error sending status command, card status %#x\n", - req->rq_disk->disk_name, __func__, - status); - gen_err = 1; - } - - /* Timeout if the device never becomes ready for data - * and never leaves the program state. - */ - if (time_after(jiffies, timeout)) { - pr_err("%s: Card stuck in programming state!"\ - " %s %s\n", mmc_hostname(card->host), - req->rq_disk->disk_name, __func__); - - return MMC_BLK_CMD_ERR; - } - /* - * Some cards mishandle the status bits, - * so make sure to check both the busy - * indication and the card state. - */ - } while (!(status & R1_READY_FOR_DATA) || - (R1_CURRENT_STATE(status) == R1_STATE_PRG)); + err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req, + &gen_err); + if (err) + return MMC_BLK_CMD_ERR; } /* if general error occurs, retry the write operation. */ @@ -1335,7 +1379,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, brq->data.blksz = 512; brq->stop.opcode = MMC_STOP_TRANSMISSION; brq->stop.arg = 0; - brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; brq->data.blocks = blk_rq_sectors(req); /* @@ -1378,9 +1421,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, if (rq_data_dir(req) == READ) { brq->cmd.opcode = readcmd; brq->data.flags |= MMC_DATA_READ; + if (brq->mrq.stop) + brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | + MMC_CMD_AC; } else { brq->cmd.opcode = writecmd; brq->data.flags |= MMC_DATA_WRITE; + if (brq->mrq.stop) + brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | + MMC_CMD_AC; } if (do_rel_wr) diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 269d072ef55e..9ebee72d9c3f 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -2,21 +2,6 @@ # MMC core configuration # -config MMC_UNSAFE_RESUME - bool "Assume MMC/SD cards are non-removable (DANGEROUS)" - help - If you say Y here, the MMC layer will assume that all cards - stayed in their respective slots during the suspend. The - normal behaviour is to remove them at suspend and - redetecting them at resume. Breaking this assumption will - in most cases result in data corruption. - - This option is usually just for embedded systems which use - a MMC/SD card for rootfs. Most people should say N here. - - This option sets a default which can be overridden by the - module parameter "removable=0" or "removable=1". - config MMC_CLKGATE bool "MMC host clock gating" help diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 64145a32b917..824644875d41 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -185,24 +185,16 @@ static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; - int ret = 0; - if (host->bus_ops->runtime_suspend) - ret = host->bus_ops->runtime_suspend(host); - - return ret; + return host->bus_ops->runtime_suspend(host); } static int mmc_runtime_resume(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); struct mmc_host *host = card->host; - int ret = 0; - if (host->bus_ops->runtime_resume) - ret = host->bus_ops->runtime_resume(host); - - return ret; + return host->bus_ops->runtime_resume(host); } static int mmc_runtime_idle(struct device *dev) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 098374b1ab2b..acbc3f2aaaf9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -34,6 +34,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> #include <linux/mmc/sd.h> +#include <linux/mmc/slot-gpio.h> #include "core.h" #include "bus.h" @@ -65,23 +66,6 @@ bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); /* - * We normally treat cards as removed during suspend if they are not - * known to be on a non-removable bus, to avoid the risk of writing - * back data to a different card after resume. Allow this to be - * overridden if necessary. - */ -#ifdef CONFIG_MMC_UNSAFE_RESUME -bool mmc_assume_removable; -#else -bool mmc_assume_removable = 1; -#endif -EXPORT_SYMBOL(mmc_assume_removable); -module_param_named(removable, mmc_assume_removable, bool, 0644); -MODULE_PARM_DESC( - removable, - "MMC/SD cards are removable and may be removed during suspend"); - -/* * Internal function. Schedule delayed work in the MMC work queue. */ static int mmc_schedule_delayed_work(struct delayed_work *work, @@ -302,7 +286,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) } err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true); + EXT_CSD_BKOPS_START, 1, timeout, + use_busy_signal, true, false); if (err) { pr_warn("%s: Error %d starting bkops\n", mmc_hostname(card->host), err); @@ -1950,7 +1935,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.opcode = MMC_ERASE; cmd.arg = arg; cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; - cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty); + cmd.busy_timeout = mmc_erase_timeout(card, arg, qty); err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_err("mmc_erase: erase error %d, status %#x\n", @@ -2137,7 +2122,7 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card, y = 0; for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) { timeout = mmc_erase_timeout(card, arg, qty + x); - if (timeout > host->max_discard_to) + if (timeout > host->max_busy_timeout) break; if (timeout < last_timeout) break; @@ -2169,7 +2154,7 @@ 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) + if (!host->max_busy_timeout) return UINT_MAX; /* @@ -2189,7 +2174,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) max_discard = 0; } pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n", - mmc_hostname(host), max_discard, host->max_discard_to); + mmc_hostname(host), max_discard, host->max_busy_timeout); return max_discard; } EXPORT_SYMBOL(mmc_calc_max_discard); @@ -2248,9 +2233,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check) { struct mmc_card *card = host->card; - if (!host->bus_ops->power_restore) - return -EOPNOTSUPP; - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) return -EOPNOTSUPP; @@ -2352,7 +2334,7 @@ int _mmc_detect_card_removed(struct mmc_host *host) { int ret; - if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) + if (host->caps & MMC_CAP_NONREMOVABLE) return 0; if (!host->card || mmc_card_removed(host->card)) @@ -2435,7 +2417,7 @@ void mmc_rescan(struct work_struct *work) * if there is a _removable_ card registered, check whether it is * still present */ - if (host->bus_ops && host->bus_ops->detect && !host->bus_dead + if (host->bus_ops && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE)) host->bus_ops->detect(host); @@ -2490,6 +2472,7 @@ void mmc_start_host(struct mmc_host *host) mmc_power_off(host); else mmc_power_up(host, host->ocr_avail); + mmc_gpiod_request_cd_irq(host); _mmc_detect_change(host, 0, false); } @@ -2501,6 +2484,8 @@ void mmc_stop_host(struct mmc_host *host) host->removed = 1; spin_unlock_irqrestore(&host->lock, flags); #endif + if (host->slot.cd_irq >= 0) + disable_irq(host->slot.cd_irq); host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); @@ -2537,7 +2522,7 @@ int mmc_power_save_host(struct mmc_host *host) mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + if (!host->bus_ops || host->bus_dead) { mmc_bus_put(host); return -EINVAL; } @@ -2563,7 +2548,7 @@ int mmc_power_restore_host(struct mmc_host *host) mmc_bus_get(host); - if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) { + if (!host->bus_ops || host->bus_dead) { mmc_bus_put(host); return -EINVAL; } @@ -2582,12 +2567,8 @@ EXPORT_SYMBOL(mmc_power_restore_host); */ int mmc_flush_cache(struct mmc_card *card) { - struct mmc_host *host = card->host; int err = 0; - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) - return err; - if (mmc_card_mmc(card) && (card->ext_csd.cache_size > 0) && (card->ext_csd.cache_ctrl & 1)) { @@ -2602,44 +2583,6 @@ int mmc_flush_cache(struct mmc_card *card) } EXPORT_SYMBOL(mmc_flush_cache); -/* - * Turn the cache ON/OFF. - * Turning the cache OFF shall trigger flushing of the data - * to the non-volatile storage. - * This function should be called with host claimed - */ -int mmc_cache_ctrl(struct mmc_host *host, u8 enable) -{ - struct mmc_card *card = host->card; - unsigned int timeout; - int err = 0; - - if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || - mmc_card_is_removable(host)) - return err; - - if (card && mmc_card_mmc(card) && - (card->ext_csd.cache_size > 0)) { - enable = !!enable; - - if (card->ext_csd.cache_ctrl ^ enable) { - timeout = enable ? card->ext_csd.generic_cmd6_time : 0; - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, enable, timeout); - if (err) - pr_err("%s: cache %s error %d\n", - mmc_hostname(card->host), - enable ? "on" : "off", - err); - else - card->ext_csd.cache_ctrl = enable; - } - } - - return err; -} -EXPORT_SYMBOL(mmc_cache_ctrl); - #ifdef CONFIG_PM /* Do the card removal on suspend if card is assumed removeable @@ -2668,7 +2611,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, /* Validate prerequisites for suspend */ if (host->bus_ops->pre_suspend) err = host->bus_ops->pre_suspend(host); - if (!err && host->bus_ops->suspend) + if (!err) break; /* Calling bus_ops->remove() with a claimed host can deadlock */ diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 114f6bdfbef3..fdea825dbb24 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -419,6 +419,16 @@ int mmc_of_parse(struct mmc_host *host) host->caps |= MMC_CAP_SD_HIGHSPEED; if (of_find_property(np, "cap-mmc-highspeed", &len)) host->caps |= MMC_CAP_MMC_HIGHSPEED; + if (of_find_property(np, "sd-uhs-sdr12", &len)) + host->caps |= MMC_CAP_UHS_SDR12; + if (of_find_property(np, "sd-uhs-sdr25", &len)) + host->caps |= MMC_CAP_UHS_SDR25; + if (of_find_property(np, "sd-uhs-sdr50", &len)) + host->caps |= MMC_CAP_UHS_SDR50; + if (of_find_property(np, "sd-uhs-sdr104", &len)) + host->caps |= MMC_CAP_UHS_SDR104; + if (of_find_property(np, "sd-uhs-ddr50", &len)) + host->caps |= MMC_CAP_UHS_DDR50; if (of_find_property(np, "cap-power-off-card", &len)) host->caps |= MMC_CAP_POWER_OFF_CARD; if (of_find_property(np, "cap-sdio-irq", &len)) @@ -429,6 +439,14 @@ int mmc_of_parse(struct mmc_host *host) host->pm_caps |= MMC_PM_KEEP_POWER; if (of_find_property(np, "enable-sdio-wakeup", &len)) host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + if (of_find_property(np, "mmc-ddr-1_8v", &len)) + host->caps |= MMC_CAP_1_8V_DDR; + if (of_find_property(np, "mmc-ddr-1_2v", &len)) + host->caps |= MMC_CAP_1_2V_DDR; + if (of_find_property(np, "mmc-hs200-1_8v", &len)) + host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; + if (of_find_property(np, "mmc-hs200-1_2v", &len)) + host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; return 0; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 98e9eb0f6643..1ab5f3a0af5b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -856,8 +856,10 @@ static int mmc_select_hs200(struct mmc_card *card) /* switch to HS200 mode if bus width set successfully */ if (!err) - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 2, 0); + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 2, + card->ext_csd.generic_cmd6_time, + true, true, true); err: return err; } @@ -1074,9 +1076,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, host->caps2 & MMC_CAP2_HS200) err = mmc_select_hs200(card); else if (host->caps & MMC_CAP_MMC_HIGHSPEED) - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 1, - card->ext_csd.generic_cmd6_time); + err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 1, + card->ext_csd.generic_cmd6_time, + true, true, true); if (err && err != -EBADMSG) goto free_card; @@ -1287,8 +1290,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * If cache size is higher than 0, this indicates * the existence of cache and it can be turned on. */ - if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && - card->ext_csd.cache_size > 0) { + if (card->ext_csd.cache_size > 0) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL, 1, card->ext_csd.generic_cmd6_time); @@ -1356,11 +1358,9 @@ static int mmc_sleep(struct mmc_host *host) { struct mmc_command cmd = {0}; struct mmc_card *card = host->card; + unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000); int err; - if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) - return 0; - err = mmc_deselect_cards(host); if (err) return err; @@ -1369,7 +1369,19 @@ static int mmc_sleep(struct mmc_host *host) cmd.arg = card->rca << 16; cmd.arg |= 1 << 15; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + /* + * If the max_busy_timeout of the host is specified, validate it against + * the sleep cmd timeout. A failure means we need to prevent the host + * from doing hw busy detection, which is done by converting to a R1 + * response instead of a R1B. + */ + if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) { + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + } else { + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + cmd.busy_timeout = timeout_ms; + } + err = mmc_wait_for_cmd(host, &cmd, 0); if (err) return err; @@ -1380,8 +1392,8 @@ static int mmc_sleep(struct mmc_host *host) * SEND_STATUS command to poll the status because that command (and most * others) is invalid while the card sleeps. */ - if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) - mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000)); + if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) + mmc_delay(timeout_ms); return err; } @@ -1404,7 +1416,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_OFF_NOTIFICATION, - notify_type, timeout, true, false); + notify_type, timeout, true, false, false); if (err) pr_err("%s: Power Off Notification timed out, %u\n", mmc_hostname(card->host), timeout); @@ -1484,7 +1496,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) goto out; } - err = mmc_cache_ctrl(host, 0); + err = mmc_flush_cache(host->card); if (err) goto out; @@ -1636,16 +1648,6 @@ static int mmc_power_restore(struct mmc_host *host) static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, - .suspend = NULL, - .resume = NULL, - .power_restore = mmc_power_restore, - .alive = mmc_alive, - .shutdown = mmc_shutdown, -}; - -static const struct mmc_bus_ops mmc_ops_unsafe = { - .remove = mmc_remove, - .detect = mmc_detect, .suspend = mmc_suspend, .resume = mmc_resume, .runtime_suspend = mmc_runtime_suspend, @@ -1655,17 +1657,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { .shutdown = mmc_shutdown, }; -static void mmc_attach_bus_ops(struct mmc_host *host) -{ - const struct mmc_bus_ops *bus_ops; - - if (!mmc_card_is_removable(host)) - bus_ops = &mmc_ops_unsafe; - else - bus_ops = &mmc_ops; - mmc_attach_bus(host, bus_ops); -} - /* * Starting point for MMC card init. */ @@ -1685,7 +1676,7 @@ int mmc_attach_mmc(struct mmc_host *host) if (err) return err; - mmc_attach_bus_ops(host); + mmc_attach_bus(host, &mmc_ops); if (host->ocr_avail_mmc) host->ocr_avail = host->ocr_avail_mmc; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index e5b5eeb548d1..f51b5ba3bbea 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -405,20 +405,30 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc) * timeout of zero implies maximum possible timeout * @use_busy_signal: use the busy signal as response type * @send_status: send status cmd to poll for busy + * @ignore_crc: ignore CRC errors when sending status cmd to poll for busy * * Modifies the EXT_CSD register for selected card. */ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, - unsigned int timeout_ms, bool use_busy_signal, bool send_status) + unsigned int timeout_ms, bool use_busy_signal, bool send_status, + bool ignore_crc) { + struct mmc_host *host = card->host; int err; struct mmc_command cmd = {0}; unsigned long timeout; u32 status = 0; - bool ignore_crc = false; + bool use_r1b_resp = use_busy_signal; - BUG_ON(!card); - BUG_ON(!card->host); + /* + * If the cmd timeout and the max_busy_timeout of the host are both + * specified, let's validate them. A failure means we need to prevent + * the host from doing hw busy detection, which is done by converting + * to a R1 response instead of a R1B. + */ + if (timeout_ms && host->max_busy_timeout && + (timeout_ms > host->max_busy_timeout)) + use_r1b_resp = false; cmd.opcode = MMC_SWITCH; cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | @@ -426,17 +436,21 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, (value << 8) | set; cmd.flags = MMC_CMD_AC; |