diff options
Diffstat (limited to 'drivers/mmc/core/mmc.c')
| -rw-r--r-- | drivers/mmc/core/mmc.c | 745 |
1 files changed, 494 insertions, 251 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4ffea14b7eb6..7c86efb1044a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1,20 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/mmc.c * * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/err.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/stat.h> +#include <linux/string.h> #include <linux/pm_runtime.h> +#include <linux/random.h> +#include <linux/sysfs.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> @@ -30,6 +30,15 @@ #include "pwrseq.h" #define DEFAULT_CMD6_TIMEOUT_MS 500 +#define MIN_CACHE_EN_TIMEOUT_MS 1600 +#define CACHE_FLUSH_TIMEOUT_MS 30000 /* 30s */ + +enum mmc_poweroff_type { + MMC_POWEROFF_SUSPEND, + MMC_POWEROFF_SHUTDOWN, + MMC_POWEROFF_UNDERVOLTAGE, + MMC_POWEROFF_UNBIND, +}; static const unsigned int tran_exp[] = { 10000, 100000, 1000000, 10000000, @@ -41,29 +50,15 @@ static const unsigned char tran_mant[] = { 35, 40, 45, 50, 55, 60, 70, 80, }; -static const unsigned int tacc_exp[] = { +static const unsigned int taac_exp[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; -static const unsigned int tacc_mant[] = { +static const unsigned int taac_mant[] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; -#define UNSTUFF_BITS(resp,start,size) \ - ({ \ - const int __size = size; \ - const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \ - const int __off = 3 - ((start) / 32); \ - const int __shft = (start) & 31; \ - u32 __res; \ - \ - __res = resp[__off] >> __shft; \ - if (__size + __shft > 32) \ - __res |= resp[__off-1] << ((32 - __shft) % 32); \ - __res & __mask; \ - }) - /* * Given the decoded CSD structure, decode the raw CID to our CID structure. */ @@ -72,42 +67,48 @@ static int mmc_decode_cid(struct mmc_card *card) u32 *resp = card->raw_cid; /* + * Add the raw card ID (cid) data to the entropy pool. It doesn't + * matter that not all of it is unique, it's just bonus entropy. + */ + add_device_randomness(&card->raw_cid, sizeof(card->raw_cid)); + + /* * The selection of the format here is based upon published - * specs from sandisk and from what people have reported. + * specs from SanDisk and from what people have reported. */ switch (card->csd.mmca_vsn) { case 0: /* MMC v1.0 - v1.2 */ case 1: /* MMC v1.4 */ - card->cid.manfid = UNSTUFF_BITS(resp, 104, 24); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); - card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8); - card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4); - card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4); - card->cid.serial = UNSTUFF_BITS(resp, 16, 24); - card->cid.month = UNSTUFF_BITS(resp, 12, 4); - card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + card->cid.manfid = unstuff_bits(resp, 104, 24); + card->cid.prod_name[0] = unstuff_bits(resp, 96, 8); + card->cid.prod_name[1] = unstuff_bits(resp, 88, 8); + card->cid.prod_name[2] = unstuff_bits(resp, 80, 8); + card->cid.prod_name[3] = unstuff_bits(resp, 72, 8); + card->cid.prod_name[4] = unstuff_bits(resp, 64, 8); + card->cid.prod_name[5] = unstuff_bits(resp, 56, 8); + card->cid.prod_name[6] = unstuff_bits(resp, 48, 8); + card->cid.hwrev = unstuff_bits(resp, 44, 4); + card->cid.fwrev = unstuff_bits(resp, 40, 4); + card->cid.serial = unstuff_bits(resp, 16, 24); + card->cid.month = unstuff_bits(resp, 12, 4); + card->cid.year = unstuff_bits(resp, 8, 4) + 1997; break; case 2: /* MMC v2.0 - v2.2 */ case 3: /* MMC v3.1 - v3.3 */ case 4: /* MMC v4 */ - card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); - card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); - card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); - card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); - card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); - card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); - card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); - card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); - card->cid.prv = UNSTUFF_BITS(resp, 48, 8); - card->cid.serial = UNSTUFF_BITS(resp, 16, 32); - card->cid.month = UNSTUFF_BITS(resp, 12, 4); - card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; + card->cid.manfid = unstuff_bits(resp, 120, 8); + card->cid.oemid = unstuff_bits(resp, 104, 16); + card->cid.prod_name[0] = unstuff_bits(resp, 96, 8); + card->cid.prod_name[1] = unstuff_bits(resp, 88, 8); + card->cid.prod_name[2] = unstuff_bits(resp, 80, 8); + card->cid.prod_name[3] = unstuff_bits(resp, 72, 8); + card->cid.prod_name[4] = unstuff_bits(resp, 64, 8); + card->cid.prod_name[5] = unstuff_bits(resp, 56, 8); + card->cid.prv = unstuff_bits(resp, 48, 8); + card->cid.serial = unstuff_bits(resp, 16, 32); + card->cid.month = unstuff_bits(resp, 12, 4); + card->cid.year = unstuff_bits(resp, 8, 4) + 1997; break; default: @@ -116,6 +117,9 @@ static int mmc_decode_cid(struct mmc_card *card) return -EINVAL; } + /* some product names include trailing whitespace */ + strim(card->cid.prod_name); + return 0; } @@ -129,6 +133,17 @@ static void mmc_set_erase_size(struct mmc_card *card) mmc_init_erase(card); } + +static void mmc_set_wp_grp_size(struct mmc_card *card) +{ + if (card->ext_csd.erase_group_def & 1) + card->wp_grp_size = card->ext_csd.hc_erase_size * + card->ext_csd.raw_hc_erase_gap_size; + else + card->wp_grp_size = card->csd.erase_size * + (card->csd.wp_grp_size + 1); +} + /* * Given a 128-bit response, decode to our card CSD structure. */ @@ -143,42 +158,43 @@ static int mmc_decode_csd(struct mmc_card *card) * v1.2 has extra information in bits 15, 11 and 10. * We also support eMMC v4.4 & v4.41. */ - csd->structure = UNSTUFF_BITS(resp, 126, 2); + csd->structure = unstuff_bits(resp, 126, 2); if (csd->structure == 0) { pr_err("%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd->structure); return -EINVAL; } - csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4); - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); - csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; - csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + csd->mmca_vsn = unstuff_bits(resp, 122, 4); + m = unstuff_bits(resp, 115, 4); + e = unstuff_bits(resp, 112, 3); + csd->taac_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + csd->taac_clks = unstuff_bits(resp, 104, 8) * 100; - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); + m = unstuff_bits(resp, 99, 4); + e = unstuff_bits(resp, 96, 3); csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + csd->cmdclass = unstuff_bits(resp, 84, 12); - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); + e = unstuff_bits(resp, 47, 3); + m = unstuff_bits(resp, 62, 12); csd->capacity = (1 + m) << (e + 2); - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); - csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); - csd->dsr_imp = UNSTUFF_BITS(resp, 76, 1); - csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); - csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); - csd->write_partial = UNSTUFF_BITS(resp, 21, 1); + csd->read_blkbits = unstuff_bits(resp, 80, 4); + csd->read_partial = unstuff_bits(resp, 79, 1); + csd->write_misalign = unstuff_bits(resp, 78, 1); + csd->read_misalign = unstuff_bits(resp, 77, 1); + csd->dsr_imp = unstuff_bits(resp, 76, 1); + csd->r2w_factor = unstuff_bits(resp, 26, 3); + csd->write_blkbits = unstuff_bits(resp, 22, 4); + csd->write_partial = unstuff_bits(resp, 21, 1); if (csd->write_blkbits >= 9) { - a = UNSTUFF_BITS(resp, 42, 5); - b = UNSTUFF_BITS(resp, 37, 5); + a = unstuff_bits(resp, 42, 5); + b = unstuff_bits(resp, 37, 5); csd->erase_size = (a + 1) * (b + 1); csd->erase_size <<= csd->write_blkbits - 9; + csd->wp_grp_size = unstuff_bits(resp, 32, 5); } return 0; @@ -299,7 +315,7 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd) } } -static void mmc_part_add(struct mmc_card *card, unsigned int size, +static void mmc_part_add(struct mmc_card *card, u64 size, unsigned int part_cfg, char *name, int idx, bool ro, int area_type) { @@ -315,7 +331,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) { int idx; u8 hc_erase_grp_sz, hc_wp_grp_sz; - unsigned int part_size; + u64 part_size; /* * General purpose partition feature support -- @@ -345,8 +361,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] << 8) + ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; - part_size *= (size_t)(hc_erase_grp_sz * - hc_wp_grp_sz); + part_size *= (hc_erase_grp_sz * hc_wp_grp_sz); mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, "gp%d", idx, false, @@ -364,7 +379,7 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) { int err = 0, idx; - unsigned int part_size; + u64 part_size; struct device_node *np; bool broken_hpi = false; @@ -413,23 +428,20 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT]; card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; - mmc_select_card_type(card); card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.raw_erase_timeout_mult = ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.raw_hc_erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; + card->ext_csd.raw_boot_mult = + ext_csd[EXT_CSD_BOOT_MULT]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; /* EXT_CSD value is in units of 10ms, but we store in ms */ card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; - /* Some eMMC set the value too low so set a minimum */ - if (card->ext_csd.part_time && - card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME) - card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME; /* Sleep / awake timeout in 100ns units */ if (sa_shift > 0 && sa_shift <= 0x17) @@ -448,7 +460,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) * There are two boot regions of equal size, defined in * multiples of 128K. */ - if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { + if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_host_can_access_boot(card->host)) { for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; mmc_part_add(card, part_size, @@ -526,8 +538,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) card->cid.year += 16; /* check whether the eMMC card supports BKOPS */ - if (!mmc_card_broken_hpi(card) && - ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { + if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) { card->ext_csd.bkops = 1; card->ext_csd.man_bkops_en = (ext_csd[EXT_CSD_BKOPS_EN] & @@ -568,7 +579,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) * RPMB regions are defined in multiples of 128K. */ card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT]; - if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_cmd23(card->host)) { + if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_can_cmd23(card->host)) { mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17, EXT_CSD_PART_CONFIG_ACC_RPMB, "rpmb", 0, false, @@ -611,15 +622,21 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) } else { card->ext_csd.data_tag_unit_size = 0; } - - card->ext_csd.max_packed_writes = - ext_csd[EXT_CSD_MAX_PACKED_WRITES]; - card->ext_csd.max_packed_reads = - ext_csd[EXT_CSD_MAX_PACKED_READS]; } else { card->ext_csd.data_sector_size = 512; } + /* + * GENERIC_CMD6_TIME is to be used "unless a specific timeout is defined + * when accessing a specific field", so use it here if there is no + * PARTITION_SWITCH_TIME. + */ + if (!card->ext_csd.part_time) + card->ext_csd.part_time = card->ext_csd.generic_cmd6_time; + /* Some eMMC set the value too low so set a minimum */ + if (card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME) + card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME; + /* eMMC v5 or later */ if (card->ext_csd.rev >= 7) { memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION], @@ -651,6 +668,9 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host), card->ext_csd.cmdq_depth); } + card->ext_csd.enhanced_rpmb_supported = + (card->ext_csd.rel_param & + EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR); } out: return err; @@ -661,7 +681,7 @@ static int mmc_read_ext_csd(struct mmc_card *card) u8 *ext_csd; int err; - if (!mmc_can_ext_csd(card)) + if (!mmc_card_can_ext_csd(card)) return 0; err = mmc_get_ext_csd(card, &ext_csd); @@ -774,13 +794,15 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9); MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9); +MMC_DEV_ATTR(wp_grp_size, "%u\n", card->wp_grp_size << 9); MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable); MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv); -MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info); +MMC_DEV_ATTR(rev, "0x%x\n", card->ext_csd.rev); +MMC_DEV_ATTR(pre_eol_info, "0x%02x\n", card->ext_csd.pre_eol_info); MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n", card->ext_csd.device_life_time_est_typ_a, card->ext_csd.device_life_time_est_typ_b); @@ -789,8 +811,11 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", card->ext_csd.enhanced_area_offset); MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); +MMC_DEV_ATTR(enhanced_rpmb_supported, "%#x\n", + card->ext_csd.enhanced_rpmb_supported); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); -MMC_DEV_ATTR(ocr, "%08x\n", card->ocr); +MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); +MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en); static ssize_t mmc_fwrev_show(struct device *dev, @@ -799,15 +824,14 @@ static ssize_t mmc_fwrev_show(struct device *dev, { struct mmc_card *card = mmc_dev_to_card(dev); - if (card->ext_csd.rev < 7) { - return sprintf(buf, "0x%x\n", card->cid.fwrev); - } else { - return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, - card->ext_csd.fwrev); - } + if (card->ext_csd.rev < 7) + return sysfs_emit(buf, "0x%x\n", card->cid.fwrev); + else + return sysfs_emit(buf, "0x%*phN\n", MMC_FIRMWARE_LEN, + card->ext_csd.fwrev); } -static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL); +static DEVICE_ATTR(fwrev, 0444, mmc_fwrev_show, NULL); static ssize_t mmc_dsr_show(struct device *dev, struct device_attribute *attr, @@ -817,13 +841,13 @@ static ssize_t mmc_dsr_show(struct device *dev, struct mmc_host *host = card->host; if (card->csd.dsr_imp && host->dsr_req) - return sprintf(buf, "0x%x\n", host->dsr); + return sysfs_emit(buf, "0x%x\n", host->dsr); else /* return default DSR value */ - return sprintf(buf, "0x%x\n", 0x404); + return sysfs_emit(buf, "0x%x\n", 0x404); } -static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL); +static DEVICE_ATTR(dsr, 0444, mmc_dsr_show, NULL); static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, @@ -831,6 +855,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_date.attr, &dev_attr_erase_size.attr, &dev_attr_preferred_erase_size.attr, + &dev_attr_wp_grp_size.attr, &dev_attr_fwrev.attr, &dev_attr_ffu_capable.attr, &dev_attr_hwrev.attr, @@ -838,21 +863,24 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_name.attr, &dev_attr_oemid.attr, &dev_attr_prv.attr, + &dev_attr_rev.attr, &dev_attr_pre_eol_info.attr, &dev_attr_life_time.attr, &dev_attr_serial.attr, &dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_size.attr, &dev_attr_raw_rpmb_size_mult.attr, + &dev_attr_enhanced_rpmb_supported.attr, &dev_attr_rel_sectors.attr, &dev_attr_ocr.attr, + &dev_attr_rca.attr, &dev_attr_dsr.attr, &dev_attr_cmdq_en.attr, NULL, }; ATTRIBUTE_GROUPS(mmc_std); -static struct device_type mmc_type = { +static const struct device_type mmc_type = { .groups = mmc_std_groups, }; @@ -932,7 +960,7 @@ static int mmc_select_powerclass(struct mmc_card *card) int err, ddr; /* Power class selection is supported for versions >= 4.0 */ - if (!mmc_can_ext_csd(card)) + if (!mmc_card_can_ext_csd(card)) return 0; bus_width = host->ios.bus_width; @@ -984,16 +1012,18 @@ static int mmc_select_bus_width(struct mmc_card *card) static unsigned ext_csd_bits[] = { EXT_CSD_BUS_WIDTH_8, EXT_CSD_BUS_WIDTH_4, + EXT_CSD_BUS_WIDTH_1, }; static unsigned bus_widths[] = { MMC_BUS_WIDTH_8, MMC_BUS_WIDTH_4, + MMC_BUS_WIDTH_1, }; struct mmc_host *host = card->host; unsigned idx, bus_width = 0; int err = 0; - if (!mmc_can_ext_csd(card) || + if (!mmc_card_can_ext_csd(card) || !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; @@ -1055,7 +1085,7 @@ static int mmc_select_hs(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS, - true, true, true); + true, true, MMC_CMD_RETRIES); if (err) pr_warn("%s: switch to high-speed failed, err:%d\n", mmc_hostname(card->host), err); @@ -1087,7 +1117,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card) ext_csd_bits, card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_DDR52, - true, true, true); + true, true, MMC_CMD_RETRIES); if (err) { pr_err("%s: switch to bus width %d ddr failed\n", mmc_hostname(host), 1 << bus_width); @@ -1155,24 +1185,31 @@ static int mmc_select_hs400(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, 0, - true, false, true); + false, true, MMC_CMD_RETRIES); if (err) { pr_err("%s: switch to high-speed from hs200 failed, err:%d\n", mmc_hostname(host), err); return err; } + /* Prepare host to downgrade to HS timing */ + if (host->ops->hs400_downgrade) + host->ops->hs400_downgrade(host); + /* Set host controller to HS timing */ - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + mmc_set_timing(host, MMC_TIMING_MMC_HS); /* Reduce frequency to HS frequency */ max_dtr = card->ext_csd.hs_max_dtr; mmc_set_clock(host, max_dtr); - err = mmc_switch_status(card); + err = mmc_switch_status(card, true); if (err) goto out_err; + if (host->ops->hs400_prepare_ddr) + host->ops->hs400_prepare_ddr(host); + /* Switch card to DDR */ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, @@ -1190,7 +1227,7 @@ static int mmc_select_hs400(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, 0, - true, false, true); + false, true, MMC_CMD_RETRIES); if (err) { pr_err("%s: switch to hs400 failed, err:%d\n", mmc_hostname(host), err); @@ -1201,7 +1238,18 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_bus_speed(card); - err = mmc_switch_status(card); + if (host->ops->execute_hs400_tuning) { + mmc_retune_disable(host); + err = host->ops->execute_hs400_tuning(host, card); + mmc_retune_enable(host); + if (err) + goto out_err; + } + + if (host->ops->hs400_complete) + host->ops->hs400_complete(host); + + err = mmc_switch_status(card, true); if (err) goto out_err; @@ -1233,26 +1281,29 @@ int mmc_hs400_to_hs200(struct mmc_card *card) val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, 0, - true, false, true); + false, true, MMC_CMD_RETRIES); if (err) goto out_err; + if (host->ops->hs400_downgrade) + host->ops->hs400_downgrade(host); + mmc_set_timing(host, MMC_TIMING_MMC_DDR52); - err = mmc_switch_status(card); + err = mmc_switch_status(card, true); if (err) goto out_err; /* Switch HS DDR to HS */ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time, - 0, true, false, true); + 0, false, true, MMC_CMD_RETRIES); if (err) goto out_err; mmc_set_timing(host, MMC_TIMING_MMC_HS); - err = mmc_switch_status(card); + err = mmc_switch_status(card, true); if (err) goto out_err; @@ -1261,7 +1312,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, 0, - true, false, true); + false, true, MMC_CMD_RETRIES); if (err) goto out_err; @@ -1272,12 +1323,16 @@ int mmc_hs400_to_hs200(struct mmc_card *card) * failed. If there really is a problem, we would expect tuning will * fail and the result ends up the same. */ - err = __mmc_switch_status(card, false); + err = mmc_switch_status(card, false); if (err) goto out_err; mmc_set_bus_speed(card); + /* Prepare tuning for HS400 mode. */ + if (host->ops->prepare_hs400_tuning) + host->ops->prepare_hs400_tuning(host, &host->ios); + return 0; out_err: @@ -1286,17 +1341,34 @@ out_err: return err; } +static void mmc_select_driver_type(struct mmc_card *card) +{ + int card_drv_type, drive_strength, drv_type = 0; + int fixed_drv_type = card->host->fixed_drv_type; + + card_drv_type = card->ext_csd.raw_driver_strength | + mmc_driver_type_mask(0); + + if (fixed_drv_type >= 0) + drive_strength = card_drv_type & mmc_driver_type_mask(fixed_drv_type) + ? fixed_drv_type : 0; + else + drive_strength = mmc_select_drive_strength(card, + card->ext_csd.hs200_max_dtr, + card_drv_type, &drv_type); + + card->drive_strength = drive_strength; + + if (drv_type) + mmc_set_driver_type(card->host, drv_type); +} + static int mmc_select_hs400es(struct mmc_card *card) { struct mmc_host *host = card->host; - int err = 0; + int err = -EINVAL; u8 val; - if (!(host->caps & MMC_CAP_8_BIT_DATA)) { - err = -ENOTSUPP; - goto out_err; - } - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V) err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); @@ -1308,27 +1380,35 @@ static int mmc_select_hs400es(struct mmc_card *card) goto out_err; err = mmc_select_bus_width(card); - if (err < 0) + if (err != MMC_BUS_WIDTH_8) { + pr_err("%s: switch to 8bit bus width failed, err:%d\n", + mmc_hostname(host), err); + err = err < 0 ? err : -ENOTSUPP; goto out_err; + } /* Switch card to HS mode */ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, card->ext_csd.generic_cmd6_time, 0, - true, false, true); + false, true, MMC_CMD_RETRIES); if (err) { pr_err("%s: switch to hs for hs400es failed, err:%d\n", mmc_hostname(host), err); goto out_err; } + /* + * Bump to HS timing and frequency. Some cards don't handle + * SEND_STATUS reliably at the initial frequency. + */ mmc_set_timing(host, MMC_TIMING_MMC_HS); - err = mmc_switch_status(card); + mmc_set_bus_speed(card); + + err = mmc_switch_status(card, true); if (err) goto out_err; - mmc_set_clock(host, card->ext_csd.hs_max_dtr); - /* Switch card to DDR with strobe bit */ val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE; err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, @@ -1341,13 +1421,15 @@ static int mmc_select_hs400es(struct mmc_card *card) goto out_err; } + mmc_select_driver_type(card); + /* Switch card to HS400 */ val = EXT_CSD_TIMING_HS400 | card->drive_strength << EXT_CSD_DRV_STR_SHIFT; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, 0, - true, false, true); + false, true, MMC_CMD_RETRIES); if (err) { pr_err("%s: switch to hs400es failed, err:%d\n", mmc_hostname(host), err); @@ -1362,7 +1444,7 @@ static int mmc_select_hs400es(struct mmc_card *card) if (host->ops->hs400_enhanced_strobe) host->ops->hs400_enhanced_strobe(host, &host->ios); - err = mmc_switch_status(card); + err = mmc_switch_status(card, true); if (err) goto out_err; @@ -1374,23 +1456,6 @@ out_err: return err; } -static void mmc_select_driver_type(struct mmc_card *card) -{ - int card_drv_type, drive_strength, drv_type; - - card_drv_type = card->ext_csd.raw_driver_strength | - mmc_driver_type_mask(0); - - drive_strength = mmc_select_drive_strength(card, - card->ext_csd.hs200_max_dtr, - card_drv_type, &drv_type); - - card->drive_strength = drive_strength; - - if (drv_type) - mmc_set_driver_type(card->host, drv_type); -} - /* * For device supporting HS200 mode, the following sequence * should be done before executing the tuning process. @@ -1401,7 +1466,7 @@ static void mmc_select_driver_type(struct mmc_card *card) static int mmc_select_hs200(struct mmc_card *card) { struct mmc_host *host = card->host; - unsigned int old_timing, old_signal_voltage; + unsigned int old_timing, old_signal_voltage, old_clock; int err = -EINVAL; u8 val; @@ -1429,25 +1494,36 @@ static int mmc_select_hs200(struct mmc_card *card) err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, 0, - true, false, true); + false, true, MMC_CMD_RETRIES); if (err) goto err; + + /* + * Bump to HS timing and frequency. Some cards don't handle + * SEND_STATUS reliably at the initial frequency. + * NB: We can't move to full (HS200) speeds until after we've + * successfully switched over. + */ old_timing = host->ios.timing; + old_clock = host->ios.clock; mmc_set_timing(host, MMC_TIMING_MMC_HS200); + mmc_set_clock(card->host, card->ext_csd.hs_max_dtr); /* * For HS200, CRC errors are not a reliable way to know the * switch failed. If there really is a problem, we would expect * tuning will fail and the result ends up the same. */ - err = __mmc_switch_status(card, false); + err = mmc_switch_status(card, false); /* * mmc_select_timing() assumes timing has not changed if * it is a switch error. */ - if (err == -EBADMSG) + if (err == -EBADMSG) { + mmc_set_clock(host, old_clock); mmc_set_timing(host, old_timing); + } } err: if (err) { @@ -1468,16 +1544,26 @@ static int mmc_select_timing(struct mmc_card *card) { int err = 0; - if (!mmc_can_ext_csd(card)) + if (!mmc_card_can_ext_csd(card)) goto bus_speed; - if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) { err = mmc_select_hs400es(card); - else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) + goto out; + } + + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) { err = mmc_select_hs200(card); - else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) + if (err == -EBADMSG) + card->mmc_avail_type &= ~EXT_CSD_CARD_TYPE_HS200; + else + goto out; + } + + if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) err = mmc_select_hs(card); +out: if (err && err != -EBADMSG) return err; @@ -1562,6 +1648,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (oldcard) { if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) { + pr_debug("%s: Perhaps the card was replaced\n", + mmc_hostname(host)); err = -ENOENT; goto err; } @@ -1651,6 +1739,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_set_erase_size(card); } + /* + * Reselect the card type since host caps could have been changed when + * debugging even if the card is not new. + */ + mmc_select_card_type(card); + /* Enable ERASE_GRP_DEF. This bit is lost after a reset or power off. */ if (card->ext_csd.rev >= 3) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, @@ -1661,7 +1755,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto free_card; if (err) { - err = 0; /* * Just disable enhanced area off & sz * will try to enable ERASE_GROUP_DEF @@ -1679,7 +1772,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_set_erase_size(card); } } - + mmc_set_wp_grp_size(card); /* * Ensure eMMC user default partition is enabled */ @@ -1711,6 +1804,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, card->ext_csd.power_off_notification = EXT_CSD_POWER_ON; } + /* set erase_arg */ + if (mmc_card_can_discard(card)) + card->erase_arg = MMC_DISCARD_ARG; + else if (mmc_card_can_trim(card)) + card->erase_arg = MMC_TRIM_ARG; + else + card->erase_arg = MMC_ERASE_ARG; + /* * Select timing interface */ @@ -1719,14 +1820,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, goto free_card; if (mmc_card_hs200(card)) { + host->doing_init_tune = 1; + err = mmc_hs200_tuning(card); - if (err) - goto free_card; + if (!err) + err = mmc_select_hs400(card); + + host->doing_init_tune = 0; - err = mmc_select_hs400(card); if (err) goto free_card; - } else if (!mmc_card_hs400es(card)) { + } else if (mmc_card_hs400es(card)) { + if (host->ops->execute_hs400_tuning) { + err = host->ops->execute_hs400_tuning(host, card); + if (err) + goto free_card; + } + } else { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); if (err > 0 && mmc_card_hs(card)) { @@ -1753,20 +1863,25 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (err) { pr_warn("%s: Enabling HPI failed\n", mmc_hostname(card->host)); - err = 0; - } else + card->ext_csd.hpi_en = 0; + } else { card->ext_csd.hpi_en = 1; + } } /* - * If cache size is higher than 0, this indicates - * the existence of cache and it can be turned on. + * If cache size is higher than 0, this indicates the existence of cache + * and it can be turned on. Note that some eMMCs from Micron has been + * reported to need ~800 ms timeout, while enabling the cache after + * sudden power failure tests. Let's extend the timeout to a minimum of + * DEFAULT_CACHE_EN_TIMEOUT_MS and do it for all cards. */ - if (!mmc_card_broken_hpi(card) && - card->ext_csd.cache_size > 0) { + if (card->ext_csd.cache_size > 0) { + unsigned int timeout_ms = MIN_CACHE_EN_TIMEOUT_MS; + + timeout_ms = max(card->ext_csd.generic_cmd6_time, timeout_ms); err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, 1, - card->ext_csd.generic_cmd6_time); + EXT_CSD_CACHE_CTRL, 1, timeout_ms); if (err && err != -EBADMSG) goto free_card; @@ -1777,42 +1892,58 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, pr_warn("%s: Cache is supported, but failed to turn on (%d)\n", mmc_hostname(card->host), err); card->ext_csd.cache_ctrl = 0; - err = 0; } else { card->ext_csd.cache_ctrl = 1; } } /* + * Enable Command Queue if supported. Note that Packed Commands cannot + * be used with Command Queue. + */ + card->ext_csd.cmdq_en = false; + if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) { + err = mmc_cmdq_enable(card); + if (err && err != -EBADMSG) + goto free_card; + if (err) { + pr_warn("%s: Enabling CMDQ failed\n", + mmc_hostname(card->host)); + card->ext_csd.cmdq_support = false; + card->ext_csd.cmdq_depth = 0; + } + } + /* * In some cases (e.g. RPMB or mmc_test), the Command Queue must be * disabled for a time, so a flag is needed to indicate to re-enable the * Command Queue. */ card->reenable_cmdq = card->ext_csd.cmdq_en; - /* - * The mandatory minimum values are defined for packed command. - * read: 5, write: 3 - */ - if (card->ext_csd.max_packed_writes >= 3 && - card->ext_csd.max_packed_reads >= 5 && - host->caps2 & MMC_CAP2_PACKED_CMD) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_EXP_EVENTS_CTRL, - EXT_CSD_PACKED_EVENT_EN, - card->ext_csd.generic_cmd6_time); - if (err && err != -EBADMSG) - goto free_card; - if (err) { - pr_warn("%s: Enabling packed event failed\n", - mmc_hostname(card->host)); - card->ext_csd.packed_event_en = 0; - err = 0; - } else { - card->ext_csd.packed_event_en = 1; + if (host->cqe_ops && !host->cqe_enabled) { + err = host->cqe_ops->cqe_enable(host, card); + if (!err) { + host->cqe_enabled = true; + + if (card->ext_csd.cmdq_en) { + pr_info("%s: Command Queue Engine enabled\n", + mmc_hostname(host)); + } else { + host->hsq_enabled = true; + pr_info("%s: Host Software Queue enabled\n", + mmc_hostname(host)); + } } } + if (host->caps2 & MMC_CAP2_AVOID_3_3V && + host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + pr_err("%s: Host failed to negotiate down from 3.3V\n", + mmc_hostname(host)); + err = -EINVAL; + goto free_card; + } + if (!oldcard) host->card = card; @@ -1825,9 +1956,17 @@ err: return err; } -static int mmc_can_sleep(struct mmc_card *card) +static bool mmc_card_can_sleep(struct mmc_card *card) { - return (card && card->ext_csd.rev >= 3); + return card->ext_csd.rev >= 3; +} + +static int mmc_sleep_busy_cb(void *cb_data, bool *busy) +{ + struct mmc_host *host = cb_data; + + *busy = host->ops->card_busy(host); + return 0; } static int mmc_sleep(struct mmc_host *host) @@ -1835,6 +1974,7 @@ static int mmc_sleep(struct mmc_host *host) struct mmc_command cmd = {}; struct mmc_card *card = host->card; unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000); + bool use_r1b_resp; int err; /* Re-tuning can't be done once the card is deselected */ @@ -1847,45 +1987,53 @@ static int mmc_sleep(struct mmc_host *host) cmd.opcode = MMC_SLEEP_AWAKE; cmd.arg = card->rca << 16; cmd.arg |= 1 << 15; - - /* - * 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; - } + use_r1b_resp = mmc_prepare_busy_cmd(host, &cmd, timeout_ms); err = mmc_wait_for_cmd(host, &cmd, 0); if (err) goto out_release; /* - * If the host does not wait while the card signals busy, then we will - * will have to wait the sleep/awake timeout. Note, we cannot use the - * SEND_STATUS command to poll the status because that command (and most - * others) is invalid while the card sleeps. + * If the host does not wait while the card signals busy, then we can + * try to poll, but only if the host supports HW polling, as the + * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need + * to wait the sleep/awake timeout. */ - if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) + if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp) + goto out_release; + + if (!host->ops->card_busy) { mmc_delay(timeout_ms); + goto out_release; + } + + err = __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_sleep_busy_cb, host); out_release: mmc_retune_release(host); return err; } -static int mmc_can_poweroff_notify(const struct mmc_card *card) +static bool mmc_card_can_poweroff_notify(const struct mmc_card *card) { return card && mmc_card_mmc(card) && (card->ext_csd.power_off_notification == EXT_CSD_POWER_ON); } +static bool mmc_host_can_poweroff_notify(const struct mmc_host *host, + enum mmc_poweroff_type pm_type) +{ + if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) + return true; + + if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND && + pm_type == MMC_POWEROFF_SUSPEND) + return true; + + return pm_type == MMC_POWEROFF_SHUTDOWN; +} + static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) { unsigned int timeout = card->ext_csd.generic_cmd6_time; @@ -1897,7 +2045,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, 0, true, false, false); + notify_type, timeout, 0, false, false, MMC_CMD_RETRIES); if (err) pr_err("%s: Power Off Notification timed out, %u\n", mmc_hostname(card->host), timeout); @@ -1909,15 +2057,6 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) } /* - * Host is being removed. Free up the current card. - */ -static void mmc_remove(struct mmc_host *host) -{ - mmc_remove_card(host->card); - host->card = NULL; -} - -/* * Card detection - card is alive. */ static int mmc_alive(struct mmc_host *host) @@ -1932,17 +2071,18 @@ static void mmc_detect(struct mmc_host *host) { int err; - mmc_get_card(host->card); + mmc_get_card(host->card, NULL); /* * Just check if our card has been removed. */ err = _mmc_detect_card_removed(host); - mmc_put_card(host->card); + mmc_put_card(host->card, NULL); if (err) { - mmc_remove(host); + mmc_remove_card(host->card); + host->card = NULL; mmc_claim_host(host); mmc_detach_bus(host); @@ -1951,31 +2091,62 @@ static void mmc_detect(struct mmc_host *host) } } -static int _mmc_suspend(struct mmc_host *host, bool is_suspend) +static bool _mmc_cache_enabled(struct mmc_host *host) +{ + return host->card->ext_csd.cache_size > 0 && + host->card->ext_csd.cache_ctrl & 1; +} + +/* + * Flush the internal cache of the eMMC to non-volatile storage. + */ +static int _mmc_flush_cache(struct mmc_host *host) +{ + int err = 0; + + if (mmc_card_broken_cache_flush(host->card) && !host->card->written_flag) + return 0; + + if (_mmc_cache_enabled(host)) { + err = mmc_switch(host->card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_FLUSH_CACHE, 1, + CACHE_FLUSH_TIMEOUT_MS); + if (err) + pr_err("%s: cache flush error %d\n", mmc_hostname(host), err); + else + host->card->written_flag = false; + } + + return err; +} + +static int _mmc_suspend(struct mmc_host *host, enum mmc_poweroff_type pm_type) { + unsigned int notify_type = EXT_CSD_POWER_OFF_SHORT; int err = 0; - unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT : - EXT_CSD_POWER_OFF_LONG; + + if (pm_type == MMC_POWEROFF_SHUTDOWN) + notify_type = EXT_CSD_POWER_OFF_LONG; mmc_claim_host(host); if (mmc_card_suspended(host->card)) goto out; - if (mmc_card_doing_bkops(host->card)) { - err = mmc_stop_bkops(host->card); + /* + * For the undervoltage case, we care more about device integrity. + * Avoid cache flush and notify the device to power off quickly. + */ + if (pm_type != MMC_POWEROFF_UNDERVOLTAGE) { + err = _mmc_flush_cache(host); if (err) goto out; } - err = mmc_flush_cache(host->card); - if (err) - goto out; - - if (mmc_can_poweroff_notify(host->card) && - ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend)) + if (mmc_card_can_poweroff_notify(host->card) && + mmc_host_can_poweroff_notify(host, pm_type)) err = mmc_poweroff_notify(host->card, notify_type); - else if (mmc_can_sleep(host->card)) + else if (mmc_card_can_sleep(host->card)) err = mmc_sleep(host); else if (!mmc_host_is_spi(host)) err = mmc_deselect_cards(host); @@ -1990,13 +2161,27 @@ out: } /* + * Host is being removed. Free up the current card and do a graceful power-off. + */ +static void mmc_remove(struct mmc_host *host) +{ + get_device(&host->card->dev); + mmc_remove_card(host->card); + + _mmc_suspend(host, MMC_POWEROFF_UNBIND); + + put_device(&host->card->dev); + host->card = NULL; +} + +/* * Suspend callback */ static int mmc_suspend(struct mmc_host *host) { int err; - err = _mmc_suspend(host, true); + err = _mmc_suspend(host, MMC_POWEROFF_SUSPEND); if (!err) { pm_runtime_disable(&host->card->dev); pm_runtime_set_suspended(&host->card->dev); @@ -2035,15 +2220,23 @@ static int mmc_shutdown(struct mmc_host *host) int err = 0; /* - * In a specific case for poweroff notify, we need to resume the card - * before we can shutdown it properly. + * In case of undervoltage, the card will be powered off (removed) by + * _mmc_handle_undervoltage() + */ + if (mmc_card_removed(host->card)) + return 0; + + /* + * If the card remains suspended at this point and it was done by using + * the sleep-cmd (CMD5), we may need to re-initialize it first, to allow + * us to send the preferred poweroff-notification cmd at shutdown. */ - if (mmc_can_poweroff_notify(host->card) && - !(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE)) + if (mmc_card_can_poweroff_notify(host->card) && + !mmc_host_can_poweroff_notify(host, MMC_POWEROFF_SUSPEND)) err = _mmc_resume(host); if (!err) - err = _mmc_suspend(host, false); + err = _mmc_suspend(host, MMC_POWEROFF_SHUTDOWN); return err; } @@ -2067,7 +2260,7 @@ static int mmc_runtime_suspend(struct mmc_host *host) if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) return 0; - err = _mmc_suspend(host, true); + err = _mmc_suspend(host, MMC_POWEROFF_SUSPEND); if (err) pr_err("%s: error %d doing aggressive suspend\n", mmc_hostname(host), err); @@ -2090,17 +2283,15 @@ static int mmc_runtime_resume(struct mmc_host *host) return 0; } -static int mmc_can_reset(struct mmc_card *card) +static bool mmc_card_can_reset(struct mmc_card *card) { u8 rst_n_function; rst_n_function = card->ext_csd.rst_n_function; - if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) - return 0; - return 1; + return ((rst_n_function & EXT_CSD_RST_N_EN_MASK) == EXT_CSD_RST_N_ENABLED); } -static int mmc_reset(struct mmc_host *host) +static int _mmc_hw_reset(struct mmc_host *host) { struct mmc_card *card = host->card; @@ -2108,13 +2299,13 @@ static int mmc_reset(struct mmc_host *host) * In the case of recovery, we can't expect flushing the cache to work * always, but we have a go and ignore errors. */ - mmc_flush_cache(host->card); + _mmc_flush_cache(host); - if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset && - mmc_can_reset(card)) { + if ((host->caps & MMC_CAP_HW_RESET) && host->ops->card_hw_reset && + mmc_card_can_reset(card)) { /* If the card accept RST_n signal, send it. */ mmc_set_clock(host, host->f_init); - host->ops->hw_reset(host); + host->ops->card_hw_reset(host); /* Set initial state and call mmc_set_ios */ mmc_set_initial_state(host); } else { @@ -2125,6 +2316,55 @@ static int mmc_reset(struct mmc_host *host) return mmc_init_card(host, card->ocr, card); } +/** + * _mmc_handle_undervoltage - Handle an undervoltage event for MMC/eMMC devices + * @host: MMC host structure + * + * This function is triggered when an undervoltage condition is detected. + * It attempts to transition the device into a low-power or safe state to + * prevent data corruption. + * + * Steps performed: + * - Perform an emergency suspend using EXT_CSD_POWER_OFF_SHORT if possible. + * - If power-off notify is not supported, fallback mechanisms like sleep or + * deselecting the card are attempted. + * - Cache flushing is skipped to reduce execution time. + * - Mark the card as removed to prevent further interactions after + * undervoltage. + * + * Note: This function does not handle host claiming or releasing. The caller + * must ensure that the host is properly claimed before calling this + * function and released afterward. + * + * Returns: 0 on success, or a negative error code if any step fails. + */ +static int _mmc_handle_undervoltage(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + int err; + + /* + * Perform an emergency suspend to power off the eMMC quickly. + * This ensures the device enters a safe state before power is lost. + * We first attempt EXT_CSD_POWER_OFF_SHORT, but if power-off notify + * is not supported, we fall back to sleep mode or deselecting the card. + * Cache flushing is skipped to minimize delay. + */ + err = _mmc_suspend(host, MMC_POWEROFF_UNDERVOLTAGE); + if (err) + pr_err("%s: undervoltage suspend failed: %pe\n", + mmc_hostname(host), ERR_PTR(err)); + + /* + * Mark the card as removed to prevent further operations. + * This ensures the system does not attempt to access the device + * after an undervoltage event, avoiding potential corruption. + */ + mmc_card_set_removed(card); + + return err; +} + static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, @@ -2134,7 +2374,10 @@ static const struct mmc_bus_ops mmc_ops = { .runtime_resume = mmc_runtime_resume, .alive = mmc_alive, .shutdown = mmc_shutdown, - .reset = mmc_reset, + .hw_reset = _mmc_hw_reset, + .cache_enabled = _mmc_cache_enabled, + .flush_cache = _mmc_flush_cache, + .handle_undervoltage = _mmc_handle_undervoltage, }; /* |
