diff options
Diffstat (limited to 'drivers/mmc/core/core.c')
| -rw-r--r-- | drivers/mmc/core/core.c | 179 |
1 files changed, 126 insertions, 53 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 426c7f66b349..860378bea557 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -19,7 +19,6 @@ #include <linux/scatterlist.h> #include <linux/log2.h> #include <linux/pm_runtime.h> -#include <linux/pm_wakeup.h> #include <linux/suspend.h> #include <linux/fault-inject.h> #include <linux/random.h> @@ -336,6 +335,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { int err; + if (mrq->cmd->has_ext_addr) + mmc_send_ext_addr(host, mrq->cmd->ext_addr); + init_completion(&mrq->cmd_completion); mmc_retune_hold(host); @@ -351,6 +353,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) if (err) return err; + if (host->uhs2_sd_tran) + mmc_uhs2_prepare_cmd(host, mrq); + led_trigger_event(host->led, LED_FULL); __mmc_start_request(host, mrq); @@ -450,6 +455,9 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq) if (err) goto out_err; + if (host->uhs2_sd_tran) + mmc_uhs2_prepare_cmd(host, mrq); + err = host->cqe_ops->cqe_request(host, mrq); if (err) goto out_err; @@ -548,21 +556,24 @@ int mmc_cqe_recovery(struct mmc_host *host) memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_STOP_TRANSMISSION; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */ + cmd.flags = MMC_RSP_R1B_NO_CRC | MMC_CMD_AC; /* Ignore CRC */ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT; - mmc_wait_for_cmd(host, &cmd, 0); + mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); + + mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, MMC_BUSY_IO); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_CMDQ_TASK_MGMT; cmd.arg = 1; /* Discard entire queue */ - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */ + cmd.flags = MMC_RSP_R1B_NO_CRC | MMC_CMD_AC; /* Ignore CRC */ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT; - err = mmc_wait_for_cmd(host, &cmd, 0); + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); host->cqe_ops->cqe_recovery_finish(host); + if (err) + err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); + mmc_retune_release(host); return err; @@ -871,7 +882,6 @@ void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx) WARN_ON(ctx && host->claimer != ctx); mmc_release_host(host); - pm_runtime_mark_last_busy(&card->dev); pm_runtime_put_autosuspend(&card->dev); } EXPORT_SYMBOL(mmc_put_card); @@ -1127,7 +1137,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) return 0; } - if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) { + if (!mmc_card_uhs2(host) && host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) { bit = ffs(ocr) - 1; ocr &= 3 << bit; mmc_power_cycle(host, ocr); @@ -1388,6 +1398,29 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr) mmc_power_up(host, ocr); } +/** + * mmc_handle_undervoltage - Handle an undervoltage event on the MMC bus + * @host: The MMC host that detected the undervoltage condition + * + * This function is called when an undervoltage event is detected on one of + * the MMC regulators. + * + * Returns: 0 on success or a negative error code on failure. + */ +int mmc_handle_undervoltage(struct mmc_host *host) +{ + /* Stop the host to prevent races with card removal */ + __mmc_stop_host(host); + + if (!host->bus_ops || !host->bus_ops->handle_undervoltage) + return 0; + + dev_warn(mmc_dev(host), "%s: Undervoltage detected, initiating emergency stop\n", + mmc_hostname(host)); + + return host->bus_ops->handle_undervoltage(host); +} + /* * Assign a mmc bus handler to a host. Only one bus handler may control a * host at any given time. @@ -1593,8 +1626,8 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card, return mmc_mmc_erase_timeout(card, arg, qty); } -static int mmc_do_erase(struct mmc_card *card, unsigned int from, - unsigned int to, unsigned int arg) +static int mmc_do_erase(struct mmc_card *card, sector_t from, + sector_t to, unsigned int arg) { struct mmc_command cmd = {}; unsigned int qty = 0, busy_timeout = 0; @@ -1625,8 +1658,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, else if (mmc_card_sd(card)) qty += to - from + 1; else - qty += ((to / card->erase_size) - - (from / card->erase_size)) + 1; + qty += (mmc_sector_div(to, card->erase_size) - + mmc_sector_div(from, card->erase_size)) + 1; if (!mmc_card_blockaddr(card)) { from <<= 9; @@ -1639,6 +1672,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.opcode = MMC_ERASE_GROUP_START; cmd.arg = from; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + + if (mmc_card_ult_capacity(card)) { + cmd.ext_addr = from >> 32; + cmd.has_ext_addr = true; + } + err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_err("mmc_erase: group start error %d, " @@ -1654,6 +1693,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.opcode = MMC_ERASE_GROUP_END; cmd.arg = to; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + + if (mmc_card_ult_capacity(card)) { + cmd.ext_addr = to >> 32; + cmd.has_ext_addr = true; + } + err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_err("mmc_erase: group end error %d, status %#x\n", @@ -1695,18 +1740,19 @@ out: } static unsigned int mmc_align_erase_size(struct mmc_card *card, - unsigned int *from, - unsigned int *to, + sector_t *from, + sector_t *to, unsigned int nr) { - unsigned int from_new = *from, nr_new = nr, rem; + sector_t from_new = *from; + unsigned int nr_new = nr, rem; /* * When the 'card->erase_size' is power of 2, we can use round_up/down() * to align the erase size efficiently. */ if (is_power_of_2(card->erase_size)) { - unsigned int temp = from_new; + sector_t temp = from_new; from_new = round_up(temp, card->erase_size); rem = from_new - temp; @@ -1718,7 +1764,7 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card, nr_new = round_down(nr_new, card->erase_size); } else { - rem = from_new % card->erase_size; + rem = mmc_sector_mod(from_new, card->erase_size); if (rem) { rem = card->erase_size - rem; from_new += rem; @@ -1751,10 +1797,12 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card, * * Caller must claim host before calling this function. */ -int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, +int mmc_erase(struct mmc_card *card, sector_t from, unsigned int nr, unsigned int arg) { - unsigned int rem, to = from + nr; + unsigned int rem; + sector_t to = from + nr; + int err; if (!(card->csd.cmdclass & CCC_ERASE)) @@ -1775,7 +1823,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, return -EOPNOTSUPP; if (arg == MMC_SECURE_ERASE_ARG) { - if (from % card->erase_size || nr % card->erase_size) + if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size) return -EINVAL; } @@ -1799,7 +1847,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, * and call mmc_do_erase() twice if necessary. This special case is * identified by the card->eg_boundary flag. */ - rem = card->erase_size - (from % card->erase_size); + rem = card->erase_size - mmc_sector_mod(from, card->erase_size); if ((arg & MMC_TRIM_OR_DISCARD_ARGS) && card->eg_boundary && nr > rem) { err = mmc_do_erase(card, from, from + rem - 1, arg); from += rem; @@ -1811,59 +1859,60 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, } EXPORT_SYMBOL(mmc_erase); -int mmc_can_erase(struct mmc_card *card) +bool mmc_card_can_erase(struct mmc_card *card) { - if (card->csd.cmdclass & CCC_ERASE && card->erase_size) - return 1; - return 0; + return (card->csd.cmdclass & CCC_ERASE && card->erase_size); } -EXPORT_SYMBOL(mmc_can_erase); +EXPORT_SYMBOL(mmc_card_can_erase); -int mmc_can_trim(struct mmc_card *card) +bool mmc_card_can_trim(struct mmc_card *card) { - if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) && - (!(card->quirks & MMC_QUIRK_TRIM_BROKEN))) - return 1; - return 0; + return ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) && + (!(card->quirks & MMC_QUIRK_TRIM_BROKEN))); } -EXPORT_SYMBOL(mmc_can_trim); +EXPORT_SYMBOL(mmc_card_can_trim); -int mmc_can_discard(struct mmc_card *card) +bool mmc_card_can_discard(struct mmc_card *card) { /* * As there's no way to detect the discard support bit at v4.5 * use the s/w feature support filed. */ - if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE) - return 1; - return 0; + return (card->ext_csd.feature_support & MMC_DISCARD_FEATURE); } -EXPORT_SYMBOL(mmc_can_discard); +EXPORT_SYMBOL(mmc_card_can_discard); -int mmc_can_sanitize(struct mmc_card *card) +bool mmc_card_can_sanitize(struct mmc_card *card) { - if (!mmc_can_trim(card) && !mmc_can_erase(card)) - return 0; + if (!mmc_card_can_trim(card) && !mmc_card_can_erase(card)) + return false; if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) - return 1; - return 0; + return true; + return false; } -int mmc_can_secure_erase_trim(struct mmc_card *card) +bool mmc_card_can_secure_erase_trim(struct mmc_card *card) { - if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) && - !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN)) - return 1; - return 0; + return ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) && + !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN)); +} +EXPORT_SYMBOL(mmc_card_can_secure_erase_trim); + +bool mmc_card_can_cmd23(struct mmc_card *card) +{ + return ((mmc_card_mmc(card) && + card->csd.mmca_vsn >= CSD_SPEC_VER_3) || + (mmc_card_sd(card) && !mmc_card_ult_capacity(card) && + card->scr.cmds & SD_SCR_CMD23_SUPPORT)); } -EXPORT_SYMBOL(mmc_can_secure_erase_trim); +EXPORT_SYMBOL(mmc_card_can_cmd23); -int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, +int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr) { if (!card->erase_size) return 0; - if (from % card->erase_size || nr % card->erase_size) + if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size) return 0; return 1; } @@ -1961,7 +2010,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) return card->pref_erase; max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG); - if (mmc_can_trim(card)) { + if (mmc_card_can_trim(card)) { max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG); if (max_trim < max_discard || max_discard == 0) max_discard = max_trim; @@ -2244,6 +2293,18 @@ void mmc_rescan(struct work_struct *work) goto out; } + /* + * Ideally we should favor initialization of legacy SD cards and defer + * UHS-II enumeration. However, it seems like cards doesn't reliably + * announce their support for UHS-II in the response to the ACMD41, + * while initializing the legacy SD interface. Therefore, let's start + * with UHS-II for now. + */ + if (!mmc_attach_sd_uhs2(host)) { + mmc_release_host(host); + goto out; + } + for (i = 0; i < ARRAY_SIZE(freqs); i++) { unsigned int freq = freqs[i]; if (freq > host->f_max) { @@ -2257,6 +2318,11 @@ void mmc_rescan(struct work_struct *work) break; } + /* A non-removable card should have been detected by now. */ + if (!mmc_card_is_removable(host) && !host->bus_ops) + pr_info("%s: Failed to initialize a non-removable card", + mmc_hostname(host)); + /* * Ignore the command timeout errors observed during * the card init as those are excepted. @@ -2271,10 +2337,13 @@ void mmc_rescan(struct work_struct *work) void mmc_start_host(struct mmc_host *host) { + bool power_up = !(host->caps2 & + (MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_SD_UHS2)); + host->f_init = max(min(freqs[0], host->f_max), host->f_min); host->rescan_disable = 0; - if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) { + if (power_up) { mmc_claim_host(host); mmc_power_up(host, host->ocr_avail); mmc_release_host(host); @@ -2286,6 +2355,9 @@ void mmc_start_host(struct mmc_host *host) void __mmc_stop_host(struct mmc_host *host) { + if (host->rescan_disable) + return; + if (host->slot.cd_irq >= 0) { mmc_gpio_set_cd_wake(host, false); disable_irq(host->slot.cd_irq); @@ -2352,4 +2424,5 @@ static void __exit mmc_exit(void) subsys_initcall(mmc_init); module_exit(mmc_exit); +MODULE_DESCRIPTION("MMC core driver"); MODULE_LICENSE("GPL"); |
