From 709de99df0ecf3102e7728fbd876a3591859f423 Mon Sep 17 00:00:00 2001 From: Chuanxiao Dong Date: Sat, 22 Jan 2011 04:09:41 +0800 Subject: [PATCH] mmc: export eMMC4.4 enhanced area details to sysfs Enhanced area feature is a new feature defined in eMMC4.4 standard. This user data area provides higher performance/reliability, at the expense of using twice the effective media space due to the area using SLC. The MMC driver now reads out the enhanced area offset and size and adds them to the device attributes in sysfs. Enabling the enhanced area can only be done once, and should be done in manufacturing. To use this feature, bit ERASE_GRP_DEF should also be set. Documentation/ABI/testing/sysfs-devices-mmc describes the two new attributes. Signed-off-by: Chuanxiao Dong Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- Documentation/ABI/testing/sysfs-devices-mmc | 21 ++++++ drivers/mmc/core/mmc.c | 74 +++++++++++++++++++++ include/linux/mmc/card.h | 3 + include/linux/mmc/mmc.h | 3 + 4 files changed, 101 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-devices-mmc diff --git a/Documentation/ABI/testing/sysfs-devices-mmc b/Documentation/ABI/testing/sysfs-devices-mmc new file mode 100644 index 000000000000..5a50ab655843 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-mmc @@ -0,0 +1,21 @@ +What: /sys/devices/.../mmc_host/mmcX/mmcX:XXXX/enhanced_area_offset +Date: January 2011 +Contact: Chuanxiao Dong +Description: + Enhanced area is a new feature defined in eMMC4.4 standard. + eMMC4.4 or later card can support such feature. This kind of + area can help to improve the card performance. If the feature + is enabled, this attribute will indicate the start address of + enhanced data area. If not, this attribute will be -EINVAL. + Unit Byte. Format decimal. + +What: /sys/devices/.../mmc_host/mmcX/mmcX:XXXX/enhanced_area_size +Date: January 2011 +Contact: Chuanxiao Dong +Description: + Enhanced area is a new feature defined in eMMC4.4 standard. + eMMC4.4 or later card can support such feature. This kind of + area can help to improve the card performance. If the feature + is enabled, this attribute will indicate the size of enhanced + data area. If not, this attribute will be -EINVAL. + Unit KByte. Format decimal. diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 16006ef153fe..6396c5d98e85 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -302,6 +302,44 @@ static int mmc_read_ext_csd(struct mmc_card *card) } if (card->ext_csd.rev >= 4) { + /* + * Enhanced area feature support -- check whether the eMMC + * card has the Enhanced area enabled. If so, export enhanced + * area offset and size to user by adding sysfs interface. + */ + if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && + (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { + u8 hc_erase_grp_sz = + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; + u8 hc_wp_grp_sz = + ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + + card->ext_csd.enhanced_area_en = 1; + /* + * calculate the enhanced data area offset, in bytes + */ + card->ext_csd.enhanced_area_offset = + (ext_csd[139] << 24) + (ext_csd[138] << 16) + + (ext_csd[137] << 8) + ext_csd[136]; + if (mmc_card_blockaddr(card)) + card->ext_csd.enhanced_area_offset <<= 9; + /* + * calculate the enhanced data area size, in kilobytes + */ + card->ext_csd.enhanced_area_size = + (ext_csd[142] << 16) + (ext_csd[141] << 8) + + ext_csd[140]; + card->ext_csd.enhanced_area_size *= + (size_t)(hc_erase_grp_sz * hc_wp_grp_sz); + card->ext_csd.enhanced_area_size <<= 9; + } else { + /* + * If the enhanced area is not enabled, disable these + * device attributes. + */ + card->ext_csd.enhanced_area_offset = -EINVAL; + card->ext_csd.enhanced_area_size = -EINVAL; + } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = @@ -336,6 +374,9 @@ 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(serial, "0x%08x\n", card->cid.serial); +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); static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, @@ -349,6 +390,8 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_name.attr, &dev_attr_oemid.attr, &dev_attr_serial.attr, + &dev_attr_enhanced_area_offset.attr, + &dev_attr_enhanced_area_size.attr, NULL, }; @@ -483,6 +526,37 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_set_erase_size(card); } + /* + * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF + * bit. This bit will be lost everytime after a reset or power off. + */ + if (card->ext_csd.enhanced_area_en) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_ERASE_GROUP_DEF, 1); + + if (err && err != -EBADMSG) + goto free_card; + + if (err) { + err = 0; + /* + * Just disable enhanced area off & sz + * will try to enable ERASE_GROUP_DEF + * during next time reinit + */ + card->ext_csd.enhanced_area_offset = -EINVAL; + card->ext_csd.enhanced_area_size = -EINVAL; + } else { + card->ext_csd.erase_group_def = 1; + /* + * enable ERASE_GRP_DEF successfully. + * This will affect the erase size, so + * here need to reset erase size + */ + mmc_set_erase_size(card); + } + } + /* * Activate high speed (if supported) */ diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 8ce082781ccb..4652cf9c5442 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -54,6 +54,9 @@ struct mmc_ext_csd { unsigned int sec_trim_mult; /* Secure trim multiplier */ unsigned int sec_erase_mult; /* Secure erase multiplier */ unsigned int trim_timeout; /* In milliseconds */ + bool enhanced_area_en; /* enable bit */ + unsigned long long enhanced_area_offset; /* Units: Byte */ + unsigned int enhanced_area_size; /* Units: KB */ }; struct sd_scr { diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 612301f85d14..264ba5451e3b 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -253,6 +253,8 @@ struct _mmc_csd { * EXT_CSD fields */ +#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ +#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ #define EXT_CSD_BUS_WIDTH 183 /* R/W */ @@ -262,6 +264,7 @@ struct _mmc_csd { #define EXT_CSD_CARD_TYPE 196 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ #define EXT_CSD_S_A_TIMEOUT 217 /* RO */ +#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ -- 2.20.1