diff mbox

[v2,1/1] mmc: export enhanced area info to user

Message ID 20101208112101.GA14565@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Chuanxiao.Dong Dec. 8, 2010, 11:21 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 77f93c3..1f49778 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -302,6 +302,64 @@  static int mmc_read_ext_csd(struct mmc_card *card)
 	}
 
 	if (card->ext_csd.rev >= 4) {
+		/*
+		 * Enhanced area feature support
+		 * check whether eMMC card is enabled enhanced area,
+		 * 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];
+			 /*
+			  * FIXME
+			  * Not sure whether need to enable the
+			  * ERASE_GROUP_DEF bit
+			  */
+			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+					EXT_CSD_ERASE_GROUP_DEF, 1);
+
+			if (err && err != -EBADMSG)
+				goto out;
+
+			if (err) {
+				/*
+				 * ignore this err, just disable enhanced area
+				 */
+				err = 0;
+				goto next;
+			}
+			/* update ext_csd ERASE_GRP_DEF bit */
+			ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+			card->ext_csd.erase_group_def =
+				ext_csd[EXT_CSD_ERASE_GROUP_DEF];
+			/*
+			 * set a flag to identify whether the enhanced
+			 * user data are enabled
+			 */
+			card->ext_csd.enh_data_area_en = 1;
+			/*
+			 * caculate the enhanced data area offset, unit B
+			 */
+			card->ext_csd.enh_data_area_off =
+				(ext_csd[139] << 24) + (ext_csd[138] << 16) +
+				(ext_csd[137] << 8) + ext_csd[136];
+			if (mmc_card_blockaddr(card))
+				card->ext_csd.enh_data_area_off <<= 9;
+			/*
+			 * caculate the enhanced data area size, unit KB
+			 */
+			card->ext_csd.enh_data_area_sz =
+				(ext_csd[142] << 16) + (ext_csd[141] << 8) +
+				ext_csd[140];
+			card->ext_csd.enh_data_area_sz *=
+				(size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
+			card->ext_csd.enh_data_area_sz <<= 9;
+		}
+next:
 		card->ext_csd.sec_trim_mult =
 			ext_csd[EXT_CSD_SEC_TRIM_MULT];
 		card->ext_csd.sec_erase_mult =
@@ -336,6 +394,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(enhen, "%d\n", card->ext_csd.enh_data_area_en);
+MMC_DEV_ATTR(enhoff, "0x%llxB\n", card->ext_csd.enh_data_area_off);
+MMC_DEV_ATTR(enhsz, "0x%xKB\n", card->ext_csd.enh_data_area_sz);
 
 static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_cid.attr,
@@ -349,6 +410,9 @@  static struct attribute *mmc_std_attrs[] = {
 	&dev_attr_name.attr,
 	&dev_attr_oemid.attr,
 	&dev_attr_serial.attr,
+	&dev_attr_enhen.attr,
+	&dev_attr_enhoff.attr,
+	&dev_attr_enhsz.attr,
 	NULL,
 };
 
@@ -472,6 +536,34 @@  static int mmc_init_card(struct mmc_host *host, u32 ocr,
 			goto free_card;
 	}
 
+	/*
+	 * If enh_data_are_en is TRUE, means this init card
+	 * operation is used to reinit card after a reset
+	 * ERASE_GRP_DEF register value will be lost everytime
+	 * after a reset or power off.
+	 *
+	 * FIXME
+	 * Not sure whether need to enable ERASE_GRP_DEF bit.
+	 */
+	if (card->ext_csd.enh_data_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.enh_data_area_off = 0;
+			card->ext_csd.enh_data_area_sz = 0;
+		}
+	}
+
 	if (!oldcard) {
 		/*
 		 * Fetch and process extended CSD.
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 8ce0827..e850a39 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 */
+	unsigned int		enh_data_area_en; /* enh area enable bit */
+	loff_t				enh_data_area_off; /* enh area offset */
+	size_t				enh_data_area_sz; /* enh area size */
 };
 
 struct sd_scr {
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 956fbd8..97ca016 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -251,6 +251,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 */
@@ -260,6 +262,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 */