All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mmc: eMMC bus width may not work on all platforms
@ 2011-05-17 18:40 Philip Rakity
  2011-05-22  0:40 ` Mok, Tze Siong
  0 siblings, 1 reply; 8+ messages in thread
From: Philip Rakity @ 2011-05-17 18:40 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, Tze Siong Mok, Tomoya MORINAGA, Takashi Iwai, Mark Brown

CMD19 -- The offical way to validate bus widths from the
JEDEC spec does not work on all platforms.  Some platforms
that use PCI/PCIe to connect their SD controllers are known
to fail.

If the quirk MMC_BUS_WIDTH_TEST is not defined we try
to figure out the bus width by reading the ext_csd at different
bus widths and compare this against the ext_csd read in 1 bit
mode.  If no ext_csd is available we default to 1 bit operations.

Code has been tested on mmp2 against 8 bit eMMC and Transcend 2GB
card that is known to not work in 4 bit mode.  The physical
pins on the card are not present to support 4 bit operation.

Signed-off-by: Philip Rakity <prakity@marvell.com>
---
 drivers/mmc/core/mmc.c |  135 ++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 125 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index baab027..42b5045 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
 }
 
 /*
- * Read and decode extended CSD.
+ * Read extended CSD.
  */
-static int mmc_read_ext_csd(struct mmc_card *card)
+static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 {
 	int err;
 	u8 *ext_csd;
 
 	BUG_ON(!card);
+	BUG_ON(!new_ext_csd);
+
+	*new_ext_csd = NULL;
 
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
 		return 0;
@@ -199,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	err = mmc_send_ext_csd(card, ext_csd);
 	if (err) {
+		kfree(ext_csd);
+		*new_ext_csd = NULL;
+
 		/* If the host or the card can't do the switch,
 		 * fail more gracefully. */
 		if ((err != -EINVAL)
 		 && (err != -ENOSYS)
 		 && (err != -EFAULT))
-			goto out;
+			return err;
 
 		/*
 		 * High capacity cards should have this "magic" size
@@ -222,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 				mmc_hostname(card->host));
 			err = 0;
 		}
+	} else
+		*new_ext_csd = ext_csd;
 
-		goto out;
-	}
+	return err;
+}
+
+/*
+ * Decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+
+	BUG_ON(!card);
+
+	if (!ext_csd)
+		return 0;
 
 	/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
 	if (card->csd.structure == 3) {
@@ -372,8 +392,92 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 		card->erased_byte = 0x0;
 
 out:
+	return err;
+}
+
+static inline void mmc_free_ext_csd(u8 *ext_csd)
+{
 	kfree(ext_csd);
+}
+
+static int mmc_cmp_ext_csd(u8 *ext_csd, u8 *bw_ext_csd, unsigned bus_width)
+{
+	if (ext_csd == NULL || bw_ext_csd == NULL)
+		return bus_width != MMC_BUS_WIDTH_1;
+
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	/* only compare read only fields */
 
+	if (ext_csd[EXT_CSD_PARTITION_SUPPORT] !=
+		bw_ext_csd[EXT_CSD_PARTITION_SUPPORT])
+			return -1;
+
+	if (ext_csd[EXT_CSD_ERASED_MEM_CONT] !=
+		bw_ext_csd[EXT_CSD_ERASED_MEM_CONT])
+			return -2;
+
+	if (ext_csd[EXT_CSD_REV] !=
+		bw_ext_csd[EXT_CSD_REV])
+			return -3;
+
+	if (ext_csd[EXT_CSD_STRUCTURE] !=
+		bw_ext_csd[EXT_CSD_STRUCTURE])
+			return -4;
+
+	if (ext_csd[EXT_CSD_CARD_TYPE] !=
+		bw_ext_csd[EXT_CSD_CARD_TYPE])
+			return -5;
+
+	if (ext_csd[EXT_CSD_S_A_TIMEOUT] !=
+		bw_ext_csd[EXT_CSD_S_A_TIMEOUT])
+			return -6;
+
+	if (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] !=
+		bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE])
+			return -7;
+
+	if (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] !=
+		bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT])
+			return -8;
+
+	if (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] !=
+		bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE])
+			return -9;
+
+	if (ext_csd[EXT_CSD_SEC_TRIM_MULT] !=
+		bw_ext_csd[EXT_CSD_SEC_TRIM_MULT])
+			return -10;
+
+	if (ext_csd[EXT_CSD_SEC_ERASE_MULT] !=
+		bw_ext_csd[EXT_CSD_SEC_ERASE_MULT])
+			return -11;
+
+	if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] !=
+		bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT])
+			return -12;
+
+	if (ext_csd[EXT_CSD_TRIM_MULT] !=
+		bw_ext_csd[EXT_CSD_TRIM_MULT])
+			return -13;
+
+	return memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+			&bw_ext_csd[EXT_CSD_SEC_CNT],
+			4);
+}
+
+static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
+			unsigned bus_width)
+{
+	u8 *bw_ext_csd;
+	int err;
+
+	err = mmc_get_ext_csd(card, &bw_ext_csd);
+	if (!err)
+		err = mmc_cmp_ext_csd(ext_csd, bw_ext_csd, bus_width);
+
+	mmc_free_ext_csd(bw_ext_csd);
 	return err;
 }
 
@@ -438,6 +542,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	u32 cid[4];
 	unsigned int max_dtr;
 	u32 rocr;
+	u8 *ext_csd = NULL;
 
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);
@@ -536,7 +641,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		/*
 		 * Fetch and process extended CSD.
 		 */
-		err = mmc_read_ext_csd(card);
+
+		err = mmc_get_ext_csd(card, &ext_csd);
+		if (err)
+			goto free_card;
+		err = mmc_read_ext_csd(card, ext_csd);
 		if (err)
 			goto free_card;
 
@@ -676,14 +785,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					 0);
 			if (!err) {
 				mmc_set_bus_width(card->host, bus_width);
+
 				/*
 				 * If controller can't handle bus width test,
-				 * use the highest bus width to maintain
-				 * compatibility with previous MMC behavior.
+				 * compare ext_csd previously read in 1 bit mode
+				 * against ext_csd at new bus width
 				 */
 				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					break;
-				err = mmc_bus_test(card, bus_width);
+					err = mmc_compare_ext_csds(card,
+						ext_csd,
+						bus_width);
+				else
+					err = mmc_bus_test(card, bus_width);
 				if (!err)
 					break;
 			}
@@ -730,12 +843,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	if (!oldcard)
 		host->card = card;
 
+	mmc_free_ext_csd(ext_csd);
 	return 0;
 
 free_card:
 	if (!oldcard)
 		mmc_remove_card(card);
 err:
+	mmc_free_ext_csd(ext_csd);
 
 	return err;
 }
-- 
1.7.0.4



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* RE: [PATCH] mmc: eMMC bus width may not work on all platforms
  2011-05-17 18:40 [PATCH] mmc: eMMC bus width may not work on all platforms Philip Rakity
@ 2011-05-22  0:40 ` Mok, Tze Siong
  2011-05-22  1:20   ` Chris Ball
  0 siblings, 1 reply; 8+ messages in thread
From: Mok, Tze Siong @ 2011-05-22  0:40 UTC (permalink / raw)
  To: Philip Rakity, Chris Ball
  Cc: Tomoya MORINAGA, Takashi Iwai, Mark Brown, linux-mmc

Hi Chris,

The following patch https://patchwork.kernel.org/patch/792162/ is tested using Intel EG20T PCH, the Transcend MMC 1bit card can now be detected, read and write to the card successfully. 
Note : Need to add MMC_CAP_BUS_WIDTH_TEST caps into the SD host controller HW platform code in order to work.

Tested-by: tze.siong.mok@intel.com


-----Original Message-----
From: Philip Rakity [mailto:prakity@marvell.com] 
Sent: Wednesday, May 18, 2011 2:41 AM
To: linux-mmc@vger.kernel.org
Cc: Chris Ball; Mok, Tze Siong; Tomoya MORINAGA; Takashi Iwai; Mark Brown
Subject: [PATCH] mmc: eMMC bus width may not work on all platforms

CMD19 -- The offical way to validate bus widths from the
JEDEC spec does not work on all platforms.  Some platforms
that use PCI/PCIe to connect their SD controllers are known
to fail.

If the quirk MMC_BUS_WIDTH_TEST is not defined we try
to figure out the bus width by reading the ext_csd at different
bus widths and compare this against the ext_csd read in 1 bit
mode.  If no ext_csd is available we default to 1 bit operations.

Code has been tested on mmp2 against 8 bit eMMC and Transcend 2GB
card that is known to not work in 4 bit mode.  The physical
pins on the card are not present to support 4 bit operation.

Signed-off-by: Philip Rakity <prakity@marvell.com>
---
 drivers/mmc/core/mmc.c |  135 ++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 125 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index baab027..42b5045 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
 }
 
 /*
- * Read and decode extended CSD.
+ * Read extended CSD.
  */
-static int mmc_read_ext_csd(struct mmc_card *card)
+static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 {
 	int err;
 	u8 *ext_csd;
 
 	BUG_ON(!card);
+	BUG_ON(!new_ext_csd);
+
+	*new_ext_csd = NULL;
 
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
 		return 0;
@@ -199,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	err = mmc_send_ext_csd(card, ext_csd);
 	if (err) {
+		kfree(ext_csd);
+		*new_ext_csd = NULL;
+
 		/* If the host or the card can't do the switch,
 		 * fail more gracefully. */
 		if ((err != -EINVAL)
 		 && (err != -ENOSYS)
 		 && (err != -EFAULT))
-			goto out;
+			return err;
 
 		/*
 		 * High capacity cards should have this "magic" size
@@ -222,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 				mmc_hostname(card->host));
 			err = 0;
 		}
+	} else
+		*new_ext_csd = ext_csd;
 
-		goto out;
-	}
+	return err;
+}
+
+/*
+ * Decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+
+	BUG_ON(!card);
+
+	if (!ext_csd)
+		return 0;
 
 	/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
 	if (card->csd.structure == 3) {
@@ -372,8 +392,92 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 		card->erased_byte = 0x0;
 
 out:
+	return err;
+}
+
+static inline void mmc_free_ext_csd(u8 *ext_csd)
+{
 	kfree(ext_csd);
+}
+
+static int mmc_cmp_ext_csd(u8 *ext_csd, u8 *bw_ext_csd, unsigned bus_width)
+{
+	if (ext_csd == NULL || bw_ext_csd == NULL)
+		return bus_width != MMC_BUS_WIDTH_1;
+
+	if (bus_width == MMC_BUS_WIDTH_1)
+		return 0;
+
+	/* only compare read only fields */
 
+	if (ext_csd[EXT_CSD_PARTITION_SUPPORT] !=
+		bw_ext_csd[EXT_CSD_PARTITION_SUPPORT])
+			return -1;
+
+	if (ext_csd[EXT_CSD_ERASED_MEM_CONT] !=
+		bw_ext_csd[EXT_CSD_ERASED_MEM_CONT])
+			return -2;
+
+	if (ext_csd[EXT_CSD_REV] !=
+		bw_ext_csd[EXT_CSD_REV])
+			return -3;
+
+	if (ext_csd[EXT_CSD_STRUCTURE] !=
+		bw_ext_csd[EXT_CSD_STRUCTURE])
+			return -4;
+
+	if (ext_csd[EXT_CSD_CARD_TYPE] !=
+		bw_ext_csd[EXT_CSD_CARD_TYPE])
+			return -5;
+
+	if (ext_csd[EXT_CSD_S_A_TIMEOUT] !=
+		bw_ext_csd[EXT_CSD_S_A_TIMEOUT])
+			return -6;
+
+	if (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] !=
+		bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE])
+			return -7;
+
+	if (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] !=
+		bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT])
+			return -8;
+
+	if (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] !=
+		bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE])
+			return -9;
+
+	if (ext_csd[EXT_CSD_SEC_TRIM_MULT] !=
+		bw_ext_csd[EXT_CSD_SEC_TRIM_MULT])
+			return -10;
+
+	if (ext_csd[EXT_CSD_SEC_ERASE_MULT] !=
+		bw_ext_csd[EXT_CSD_SEC_ERASE_MULT])
+			return -11;
+
+	if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] !=
+		bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT])
+			return -12;
+
+	if (ext_csd[EXT_CSD_TRIM_MULT] !=
+		bw_ext_csd[EXT_CSD_TRIM_MULT])
+			return -13;
+
+	return memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+			&bw_ext_csd[EXT_CSD_SEC_CNT],
+			4);
+}
+
+static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
+			unsigned bus_width)
+{
+	u8 *bw_ext_csd;
+	int err;
+
+	err = mmc_get_ext_csd(card, &bw_ext_csd);
+	if (!err)
+		err = mmc_cmp_ext_csd(ext_csd, bw_ext_csd, bus_width);
+
+	mmc_free_ext_csd(bw_ext_csd);
 	return err;
 }
 
@@ -438,6 +542,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	u32 cid[4];
 	unsigned int max_dtr;
 	u32 rocr;
+	u8 *ext_csd = NULL;
 
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);
@@ -536,7 +641,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		/*
 		 * Fetch and process extended CSD.
 		 */
-		err = mmc_read_ext_csd(card);
+
+		err = mmc_get_ext_csd(card, &ext_csd);
+		if (err)
+			goto free_card;
+		err = mmc_read_ext_csd(card, ext_csd);
 		if (err)
 			goto free_card;
 
@@ -676,14 +785,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					 0);
 			if (!err) {
 				mmc_set_bus_width(card->host, bus_width);
+
 				/*
 				 * If controller can't handle bus width test,
-				 * use the highest bus width to maintain
-				 * compatibility with previous MMC behavior.
+				 * compare ext_csd previously read in 1 bit mode
+				 * against ext_csd at new bus width
 				 */
 				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					break;
-				err = mmc_bus_test(card, bus_width);
+					err = mmc_compare_ext_csds(card,
+						ext_csd,
+						bus_width);
+				else
+					err = mmc_bus_test(card, bus_width);
 				if (!err)
 					break;
 			}
@@ -730,12 +843,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	if (!oldcard)
 		host->card = card;
 
+	mmc_free_ext_csd(ext_csd);
 	return 0;
 
 free_card:
 	if (!oldcard)
 		mmc_remove_card(card);
 err:
+	mmc_free_ext_csd(ext_csd);
 
 	return err;
 }
-- 
1.7.0.4



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] mmc: eMMC bus width may not work on all platforms
  2011-05-22  0:40 ` Mok, Tze Siong
@ 2011-05-22  1:20   ` Chris Ball
  2011-05-22  1:52     ` Philip Rakity
  2011-05-22 17:30     ` [PATCH V2] " Philip Rakity
  0 siblings, 2 replies; 8+ messages in thread
From: Chris Ball @ 2011-05-22  1:20 UTC (permalink / raw)
  To: Mok, Tze Siong
  Cc: Philip Rakity, Tomoya MORINAGA, Takashi Iwai, Mark Brown, linux-mmc

Hi,

On Sat, May 21 2011, Mok, Tze Siong wrote:
> The following patch https://patchwork.kernel.org/patch/792162/ is tested using Intel EG20T PCH, the Transcend MMC 1bit card can now be detected, read and write to the card successfully. 
> Note : Need to add MMC_CAP_BUS_WIDTH_TEST caps into the SD host controller HW platform code in order to work.
>
> Tested-by: tze.siong.mok@intel.com

Great, thank you.  Philip, a few comments:

> +static int mmc_cmp_ext_csd(u8 *ext_csd, u8 *bw_ext_csd, unsigned bus_width)
> +{
> +	if (ext_csd == NULL || bw_ext_csd == NULL)
> +		return bus_width != MMC_BUS_WIDTH_1;
> +
> +	if (bus_width == MMC_BUS_WIDTH_1)
> +		return 0;
> +
> +	/* only compare read only fields */
>  
> +	if (ext_csd[EXT_CSD_PARTITION_SUPPORT] !=
> +		bw_ext_csd[EXT_CSD_PARTITION_SUPPORT])
> +			return -1;
> +
> +	if (ext_csd[EXT_CSD_ERASED_MEM_CONT] !=
> +		bw_ext_csd[EXT_CSD_ERASED_MEM_CONT])
> +			return -2;
> +
> +	if (ext_csd[EXT_CSD_REV] !=
> +		bw_ext_csd[EXT_CSD_REV])
> +			return -3;
> +
> +	if (ext_csd[EXT_CSD_STRUCTURE] !=
> +		bw_ext_csd[EXT_CSD_STRUCTURE])
> +			return -4;
> +
> +	if (ext_csd[EXT_CSD_CARD_TYPE] !=
> +		bw_ext_csd[EXT_CSD_CARD_TYPE])
> +			return -5;
> +
> +	if (ext_csd[EXT_CSD_S_A_TIMEOUT] !=
> +		bw_ext_csd[EXT_CSD_S_A_TIMEOUT])
> +			return -6;
> +
> +	if (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] !=
> +		bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE])
> +			return -7;
> +
> +	if (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] !=
> +		bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT])
> +			return -8;
> +
> +	if (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] !=
> +		bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE])
> +			return -9;
> +
> +	if (ext_csd[EXT_CSD_SEC_TRIM_MULT] !=
> +		bw_ext_csd[EXT_CSD_SEC_TRIM_MULT])
> +			return -10;
> +
> +	if (ext_csd[EXT_CSD_SEC_ERASE_MULT] !=
> +		bw_ext_csd[EXT_CSD_SEC_ERASE_MULT])
> +			return -11;
> +
> +	if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] !=
> +		bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT])
> +			return -12;
> +
> +	if (ext_csd[EXT_CSD_TRIM_MULT] !=
> +		bw_ext_csd[EXT_CSD_TRIM_MULT])
> +			return -13;

Hm, I think people reading dmesg are going to interpret these as errnos,
which they're ambiguous with.  Is returning a different number for each
condition important?

Perhaps just pick one errno to return, have a single long conditional,
and if we're going to fail all of mmc_init_card() because of an error
here, add a printk explaining the situation to this function?

> +
> +	return memcmp(&ext_csd[EXT_CSD_SEC_CNT],
> +			&bw_ext_csd[EXT_CSD_SEC_CNT],
> +			4);
> +}
> +
> +static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
> +			unsigned bus_width)
> +{
> +	u8 *bw_ext_csd;
> +	int err;
> +
> +	err = mmc_get_ext_csd(card, &bw_ext_csd);
> +	if (!err)
> +		err = mmc_cmp_ext_csd(ext_csd, bw_ext_csd, bus_width);
> +
> +	mmc_free_ext_csd(bw_ext_csd);
>  	return err;
>  }

mmc_compare_ext_csds() and mmc_cmp_ext_csd() don't seem like they have
a strong reason for existing as separate functions -- perhaps collapse
them both into a single mmc_compare_ext_csds()?

Thanks!

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] mmc: eMMC bus width may not work on all platforms
  2011-05-22  1:20   ` Chris Ball
@ 2011-05-22  1:52     ` Philip Rakity
  2011-05-22 17:30     ` [PATCH V2] " Philip Rakity
  1 sibling, 0 replies; 8+ messages in thread
From: Philip Rakity @ 2011-05-22  1:52 UTC (permalink / raw)
  To: Chris Ball
  Cc: Mok, Tze Siong, Tomoya MORINAGA, Takashi Iwai, Mark Brown, linux-mmc


On May 21, 2011, at 6:20 PM, Chris Ball wrote:

> Hi,
> 
> On Sat, May 21 2011, Mok, Tze Siong wrote:
>> The following patch https://patchwork.kernel.org/patch/792162/ is tested using Intel EG20T PCH, the Transcend MMC 1bit card can now be detected, read and write to the card successfully. 
>> Note : Need to add MMC_CAP_BUS_WIDTH_TEST caps into the SD host controller HW platform code in order to work.
>> 
>> Tested-by: tze.siong.mok@intel.com
> 
> Great, thank you.  Philip, a few comments:
> 
>> +static int mmc_cmp_ext_csd(u8 *ext_csd, u8 *bw_ext_csd, unsigned bus_width)
>> +{
>> +	if (ext_csd == NULL || bw_ext_csd == NULL)
>> +		return bus_width != MMC_BUS_WIDTH_1;
>> +
>> +	if (bus_width == MMC_BUS_WIDTH_1)
>> +		return 0;
>> +
>> +	/* only compare read only fields */
>> 
>> +	if (ext_csd[EXT_CSD_PARTITION_SUPPORT] !=
>> +		bw_ext_csd[EXT_CSD_PARTITION_SUPPORT])
>> +			return -1;
>> +
>> +	if (ext_csd[EXT_CSD_ERASED_MEM_CONT] !=
>> +		bw_ext_csd[EXT_CSD_ERASED_MEM_CONT])
>> +			return -2;
>> +
>> +	if (ext_csd[EXT_CSD_REV] !=
>> +		bw_ext_csd[EXT_CSD_REV])
>> +			return -3;
>> +
>> +	if (ext_csd[EXT_CSD_STRUCTURE] !=
>> +		bw_ext_csd[EXT_CSD_STRUCTURE])
>> +			return -4;
>> +
>> +	if (ext_csd[EXT_CSD_CARD_TYPE] !=
>> +		bw_ext_csd[EXT_CSD_CARD_TYPE])
>> +			return -5;
>> +
>> +	if (ext_csd[EXT_CSD_S_A_TIMEOUT] !=
>> +		bw_ext_csd[EXT_CSD_S_A_TIMEOUT])
>> +			return -6;
>> +
>> +	if (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] !=
>> +		bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE])
>> +			return -7;
>> +
>> +	if (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] !=
>> +		bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT])
>> +			return -8;
>> +
>> +	if (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] !=
>> +		bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE])
>> +			return -9;
>> +
>> +	if (ext_csd[EXT_CSD_SEC_TRIM_MULT] !=
>> +		bw_ext_csd[EXT_CSD_SEC_TRIM_MULT])
>> +			return -10;
>> +
>> +	if (ext_csd[EXT_CSD_SEC_ERASE_MULT] !=
>> +		bw_ext_csd[EXT_CSD_SEC_ERASE_MULT])
>> +			return -11;
>> +
>> +	if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] !=
>> +		bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT])
>> +			return -12;
>> +
>> +	if (ext_csd[EXT_CSD_TRIM_MULT] !=
>> +		bw_ext_csd[EXT_CSD_TRIM_MULT])
>> +			return -13;
> 
> Hm, I think people reading dmesg are going to interpret these as errnos,
> which they're ambiguous with.  Is returning a different number for each
> condition important?
> 

No -- was just a way for me to debug -- not important

> Perhaps just pick one errno to return, have a single long conditional,
> and if we're going to fail all of mmc_init_card() because of an error
> here, add a printk explaining the situation to this function?

which errro would you suggest. 

 I do not want to have a long conditional unless
this is very important.  Hard to follow.  (see below)

> 
>> +
>> +	return memcmp(&ext_csd[EXT_CSD_SEC_CNT],
>> +			&bw_ext_csd[EXT_CSD_SEC_CNT],
>> +			4);
>> +}
>> +
>> +static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
>> +			unsigned bus_width)
>> +{
>> +	u8 *bw_ext_csd;
>> +	int err;
>> +
>> +	err = mmc_get_ext_csd(card, &bw_ext_csd);
>> +	if (!err)
>> +		err = mmc_cmp_ext_csd(ext_csd, bw_ext_csd, bus_width);

would it be better to add
		if (err)
			err = ERRNO WE WANT TO USE;

>> +
>> +	mmc_free_ext_csd(bw_ext_csd);
>> 	return err;
>> }
> 
> mmc_compare_ext_csds() and mmc_cmp_ext_csd() don't seem like they have
> a strong reason for existing as separate functions -- perhaps collapse
> them both into a single mmc_compare_ext_csds()?

I can do this.

> 
> Thanks!
> 
> - Chris.
> -- 
> Chris Ball   <cjb@laptop.org>   <http://printf.net/>
> One Laptop Per Child
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH V2] mmc: eMMC bus width may not work on all platforms
  2011-05-22  1:20   ` Chris Ball
  2011-05-22  1:52     ` Philip Rakity
@ 2011-05-22 17:30     ` Philip Rakity
  2011-05-24  4:42       ` Chris Ball
  1 sibling, 1 reply; 8+ messages in thread
From: Philip Rakity @ 2011-05-22 17:30 UTC (permalink / raw)
  To: Chris Ball
  Cc: Mok, Tze Siong, Tomoya MORINAGA, Takashi Iwai, Mark Brown, linux-mmc


Note:  I cannot test test for a few days.  Following Chris suggestion posting to list.

version 2
---
return -EINVAL when compare of ext_csd_fails
combine two compare routines into one per suggestion
from Chris.

---
version 1

CMD19 -- The offical way to validate bus widths from the
JEDEC spec does not work on all platforms.  Some platforms
that use PCI/PCIe to connect their SD controllers are known
to fail.

If the quirk MMC_BUS_WIDTH_TEST is not defined we try
to figure out the bus width by reading the ext_csd at different
bus widths and compare this against the ext_csd read in 1 bit
mode.  If no ext_csd is available we default to 1 bit operations.

Code has been tested on mmp2 against 8 bit eMMC and Transcend 2GB
card that is known to not work in 4 bit mode.  The physical
pins on the card are not present to support 4 bit operation.

Signed-off-by: Philip Rakity <prakity@marvell.com>
---
 drivers/mmc/core/mmc.c |  113 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 103 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index baab027..6db91d6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
 }
 
 /*
- * Read and decode extended CSD.
+ * Read extended CSD.
  */
-static int mmc_read_ext_csd(struct mmc_card *card)
+static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 {
 	int err;
 	u8 *ext_csd;
 
 	BUG_ON(!card);
+	BUG_ON(!new_ext_csd);
+
+	*new_ext_csd = NULL;
 
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
 		return 0;
@@ -199,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	err = mmc_send_ext_csd(card, ext_csd);
 	if (err) {
+		kfree(ext_csd);
+		*new_ext_csd = NULL;
+
 		/* If the host or the card can't do the switch,
 		 * fail more gracefully. */
 		if ((err != -EINVAL)
 		 && (err != -ENOSYS)
 		 && (err != -EFAULT))
-			goto out;
+			return err;
 
 		/*
 		 * High capacity cards should have this "magic" size
@@ -222,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 				mmc_hostname(card->host));
 			err = 0;
 		}
+	} else
+		*new_ext_csd = ext_csd;
 
-		goto out;
-	}
+	return err;
+}
+
+/*
+ * Decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+
+	BUG_ON(!card);
+
+	if (!ext_csd)
+		return 0;
 
 	/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
 	if (card->csd.structure == 3) {
@@ -372,8 +392,70 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 		card->erased_byte = 0x0;
 
 out:
+	return err;
+}
+
+static inline void mmc_free_ext_csd(u8 *ext_csd)
+{
 	kfree(ext_csd);
+}
+
 
+static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
+			unsigned bus_width)
+{
+	u8 *bw_ext_csd;
+	int err;
+
+	err = mmc_get_ext_csd(card, &bw_ext_csd);
+	if (err)
+		return err;
+
+	if ((ext_csd == NULL || bw_ext_csd == NULL)) {
+		if (bus_width != MMC_BUS_WIDTH_1)
+			err = -EINVAL;
+		goto out;
+	}
+
+	if (bus_width == MMC_BUS_WIDTH_1)
+		goto out;
+
+	/* only compare read only fields */
+
+	err =	(!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
+			bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
+		(ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
+			bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
+		(ext_csd[EXT_CSD_REV] ==
+			bw_ext_csd[EXT_CSD_REV]) &&
+		(ext_csd[EXT_CSD_STRUCTURE] ==
+			bw_ext_csd[EXT_CSD_STRUCTURE]) &&
+		(ext_csd[EXT_CSD_CARD_TYPE] ==
+			bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
+		(ext_csd[EXT_CSD_S_A_TIMEOUT] ==
+			bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
+		(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+			bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+		(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
+			bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
+		(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+			bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+		(ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
+			bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
+		(ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
+			bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
+		(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
+			bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
+		(ext_csd[EXT_CSD_TRIM_MULT] ==
+			bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
+		memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+			&bw_ext_csd[EXT_CSD_SEC_CNT],
+			4) != 0);
+	if (err)
+		err = -EINVAL;
+
+out:
+	mmc_free_ext_csd(bw_ext_csd);
 	return err;
 }


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH V2] mmc: eMMC bus width may not work on all platforms
  2011-05-22 17:30     ` [PATCH V2] " Philip Rakity
@ 2011-05-24  4:42       ` Chris Ball
  2011-05-25  1:14         ` Philip Rakity
  0 siblings, 1 reply; 8+ messages in thread
From: Chris Ball @ 2011-05-24  4:42 UTC (permalink / raw)
  To: Philip Rakity
  Cc: Mok, Tze Siong, Tomoya MORINAGA, Takashi Iwai, Mark Brown, linux-mmc

Hi Philip,

On Sun, May 22 2011, Philip Rakity wrote:
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index baab027..6db91d6 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
>  }
>  
>  /*
> - * Read and decode extended CSD.
> + * Read extended CSD.
>   */
> -static int mmc_read_ext_csd(struct mmc_card *card)
> +static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)

This one doesn't work -- you're missing the half of the patch that hooks
up the rest of mmc.c to the new code, which was in v1.  As-is, we get:

drivers/mmc/core/mmc.c: In function ‘mmc_init_card’:
drivers/mmc/core/mmc.c:621:3: error: too few arguments to function ‘mmc_read_ext_csd’
drivers/mmc/core/mmc.c:240:12: note: declared here
drivers/mmc/core/mmc.c: At top level:
drivers/mmc/core/mmc.c:404:12: warning: ‘mmc_compare_ext_csds’ defined but not used [-Wunused-function]

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH V2] mmc: eMMC bus width may not work on all platforms
  2011-05-24  4:42       ` Chris Ball
@ 2011-05-25  1:14         ` Philip Rakity
  2011-05-31 18:11           ` Philip Rakity
  0 siblings, 1 reply; 8+ messages in thread
From: Philip Rakity @ 2011-05-25  1:14 UTC (permalink / raw)
  To: Chris Ball
  Cc: Mok, Tze Siong, Tomoya MORINAGA, Takashi Iwai, Mark Brown, linux-mmc


resend 

Note:  I cannot test test for a few days.  Following Chris
suggestion posting to list.

version 2
---
return -EINVAL when compare of ext_csd_fails
combine two compare routines into one per suggestion
from Chris.

---
version 1

CMD19 -- The offical way to validate bus widths from the
JEDEC spec does not work on all platforms.  Some platforms
that use PCI/PCIe to connect their SD controllers are known
to fail.

If the quirk MMC_BUS_WIDTH_TEST is not defined we try
to figure out the bus width by reading the ext_csd at different
bus widths and compare this against the ext_csd read in 1 bit
mode.  If no ext_csd is available we default to 1 bit operations.

Code has been tested on mmp2 against 8 bit eMMC and Transcend 2GB
card that is known to not work in 4 bit mode.  The physical
pins on the card are not present to support 4 bit operation.

Signed-off-by: Philip Rakity <prakity@marvell.com>
---
 drivers/mmc/core/mmc.c |  113 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 103 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index baab027..6db91d6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
 }
 
 /*
- * Read and decode extended CSD.
+ * Read extended CSD.
  */
-static int mmc_read_ext_csd(struct mmc_card *card)
+static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 {
 	int err;
 	u8 *ext_csd;
 
 	BUG_ON(!card);
+	BUG_ON(!new_ext_csd);
+
+	*new_ext_csd = NULL;
 
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
 		return 0;
@@ -199,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
 	err = mmc_send_ext_csd(card, ext_csd);
 	if (err) {
+		kfree(ext_csd);
+		*new_ext_csd = NULL;
+
 		/* If the host or the card can't do the switch,
 		 * fail more gracefully. */
 		if ((err != -EINVAL)
 		 && (err != -ENOSYS)
 		 && (err != -EFAULT))
-			goto out;
+			return err;
 
 		/*
 		 * High capacity cards should have this "magic" size
@@ -222,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 				mmc_hostname(card->host));
 			err = 0;
 		}
+	} else
+		*new_ext_csd = ext_csd;
 
-		goto out;
-	}
+	return err;
+}
+
+/*
+ * Decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	int err = 0;
+
+	BUG_ON(!card);
+
+	if (!ext_csd)
+		return 0;
 
 	/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
 	if (card->csd.structure == 3) {
@@ -372,8 +392,70 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 		card->erased_byte = 0x0;
 
 out:
+	return err;
+}
+
+static inline void mmc_free_ext_csd(u8 *ext_csd)
+{
 	kfree(ext_csd);
+}
+
 
+static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
+			unsigned bus_width)
+{
+	u8 *bw_ext_csd;
+	int err;
+
+	err = mmc_get_ext_csd(card, &bw_ext_csd);
+	if (err)
+		return err;
+
+	if ((ext_csd == NULL || bw_ext_csd == NULL)) {
+		if (bus_width != MMC_BUS_WIDTH_1)
+			err = -EINVAL;
+		goto out;
+	}
+
+	if (bus_width == MMC_BUS_WIDTH_1)
+		goto out;
+
+	/* only compare read only fields */
+
+	err =	(!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
+			bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
+		(ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
+			bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
+		(ext_csd[EXT_CSD_REV] ==
+			bw_ext_csd[EXT_CSD_REV]) &&
+		(ext_csd[EXT_CSD_STRUCTURE] ==
+			bw_ext_csd[EXT_CSD_STRUCTURE]) &&
+		(ext_csd[EXT_CSD_CARD_TYPE] ==
+			bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
+		(ext_csd[EXT_CSD_S_A_TIMEOUT] ==
+			bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
+		(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+			bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+		(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
+			bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
+		(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+			bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+		(ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
+			bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
+		(ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
+			bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
+		(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
+			bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
+		(ext_csd[EXT_CSD_TRIM_MULT] ==
+			bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
+		memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+			&bw_ext_csd[EXT_CSD_SEC_CNT],
+			4) != 0);
+	if (err)
+		err = -EINVAL;
+
+out:
+	mmc_free_ext_csd(bw_ext_csd);
 	return err;
 }
 
@@ -438,6 +520,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	u32 cid[4];
 	unsigned int max_dtr;
 	u32 rocr;
+	u8 *ext_csd = NULL;
 
 	BUG_ON(!host);
 	WARN_ON(!host->claimed);
@@ -536,7 +619,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		/*
 		 * Fetch and process extended CSD.
 		 */
-		err = mmc_read_ext_csd(card);
+
+		err = mmc_get_ext_csd(card, &ext_csd);
+		if (err)
+			goto free_card;
+		err = mmc_read_ext_csd(card, ext_csd);
 		if (err)
 			goto free_card;
 
@@ -676,14 +763,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 					 0);
 			if (!err) {
 				mmc_set_bus_width(card->host, bus_width);
+
 				/*
 				 * If controller can't handle bus width test,
-				 * use the highest bus width to maintain
-				 * compatibility with previous MMC behavior.
+				 * compare ext_csd previously read in 1 bit mode
+				 * against ext_csd at new bus width
 				 */
 				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-					break;
-				err = mmc_bus_test(card, bus_width);
+					err = mmc_compare_ext_csds(card,
+						ext_csd,
+						bus_width);
+				else
+					err = mmc_bus_test(card, bus_width);
 				if (!err)
 					break;
 			}
@@ -730,12 +821,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	if (!oldcard)
 		host->card = card;
 
+	mmc_free_ext_csd(ext_csd);
 	return 0;
 
 free_card:
 	if (!oldcard)
 		mmc_remove_card(card);
 err:
+	mmc_free_ext_csd(ext_csd);
 
 	return err;
 }
-- 
1.7.0.4



On May 23, 2011, at 9:42 PM, Chris Ball wrote:

> Hi Philip,
> 
> On Sun, May 22 2011, Philip Rakity wrote:
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index baab027..6db91d6 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
>> }
>> 
>> /*
>> - * Read and decode extended CSD.
>> + * Read extended CSD.
>>  */
>> -static int mmc_read_ext_csd(struct mmc_card *card)
>> +static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> 
> This one doesn't work -- you're missing the half of the patch that hooks
> up the rest of mmc.c to the new code, which was in v1.  As-is, we get:
> 
> drivers/mmc/core/mmc.c: In function ‘mmc_init_card’:
> drivers/mmc/core/mmc.c:621:3: error: too few arguments to function ‘mmc_read_ext_csd’
> drivers/mmc/core/mmc.c:240:12: note: declared here
> drivers/mmc/core/mmc.c: At top level:
> drivers/mmc/core/mmc.c:404:12: warning: ‘mmc_compare_ext_csds’ defined but not used [-Wunused-function]
> 
> - Chris.
> -- 
> Chris Ball   <cjb@laptop.org>   <http://printf.net/>
> One Laptop Per Child
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH V2] mmc: eMMC bus width may not work on all platforms
  2011-05-25  1:14         ` Philip Rakity
@ 2011-05-31 18:11           ` Philip Rakity
  0 siblings, 0 replies; 8+ messages in thread
From: Philip Rakity @ 2011-05-31 18:11 UTC (permalink / raw)
  To: Chris Ball
  Cc: Mok, Tze Siong, Tomoya MORINAGA, Takashi Iwai, Mark Brown, linux-mmc


Chris,

Just tested the mod on brownstone.  Works.

Philip

On May 24, 2011, at 6:14 PM, Philip Rakity wrote:

> 
> resend 
> 
> Note:  I cannot test test for a few days.  Following Chris
> suggestion posting to list.
> 
> version 2
> ---
> return -EINVAL when compare of ext_csd_fails
> combine two compare routines into one per suggestion
> from Chris.
> 
> ---
> version 1
> 
> CMD19 -- The offical way to validate bus widths from the
> JEDEC spec does not work on all platforms.  Some platforms
> that use PCI/PCIe to connect their SD controllers are known
> to fail.
> 
> If the quirk MMC_BUS_WIDTH_TEST is not defined we try
> to figure out the bus width by reading the ext_csd at different
> bus widths and compare this against the ext_csd read in 1 bit
> mode.  If no ext_csd is available we default to 1 bit operations.
> 
> Code has been tested on mmp2 against 8 bit eMMC and Transcend 2GB
> card that is known to not work in 4 bit mode.  The physical
> pins on the card are not present to support 4 bit operation.
> 
> Signed-off-by: Philip Rakity <prakity@marvell.com>
> ---
> drivers/mmc/core/mmc.c |  113 +++++++++++++++++++++++++++++++++++++++++++----
> 1 files changed, 103 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index baab027..6db91d6 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
> }
> 
> /*
> - * Read and decode extended CSD.
> + * Read extended CSD.
>  */
> -static int mmc_read_ext_csd(struct mmc_card *card)
> +static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
> {
> 	int err;
> 	u8 *ext_csd;
> 
> 	BUG_ON(!card);
> +	BUG_ON(!new_ext_csd);
> +
> +	*new_ext_csd = NULL;
> 
> 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
> 		return 0;
> @@ -199,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
> 
> 	err = mmc_send_ext_csd(card, ext_csd);
> 	if (err) {
> +		kfree(ext_csd);
> +		*new_ext_csd = NULL;
> +
> 		/* If the host or the card can't do the switch,
> 		 * fail more gracefully. */
> 		if ((err != -EINVAL)
> 		 && (err != -ENOSYS)
> 		 && (err != -EFAULT))
> -			goto out;
> +			return err;
> 
> 		/*
> 		 * High capacity cards should have this "magic" size
> @@ -222,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
> 				mmc_hostname(card->host));
> 			err = 0;
> 		}
> +	} else
> +		*new_ext_csd = ext_csd;
> 
> -		goto out;
> -	}
> +	return err;
> +}
> +
> +/*
> + * Decode extended CSD.
> + */
> +static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
> +{
> +	int err = 0;
> +
> +	BUG_ON(!card);
> +
> +	if (!ext_csd)
> +		return 0;
> 
> 	/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
> 	if (card->csd.structure == 3) {
> @@ -372,8 +392,70 @@ static int mmc_read_ext_csd(struct mmc_card *card)
> 		card->erased_byte = 0x0;
> 
> out:
> +	return err;
> +}
> +
> +static inline void mmc_free_ext_csd(u8 *ext_csd)
> +{
> 	kfree(ext_csd);
> +}
> +
> 
> +static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
> +			unsigned bus_width)
> +{
> +	u8 *bw_ext_csd;
> +	int err;
> +
> +	err = mmc_get_ext_csd(card, &bw_ext_csd);
> +	if (err)
> +		return err;
> +
> +	if ((ext_csd == NULL || bw_ext_csd == NULL)) {
> +		if (bus_width != MMC_BUS_WIDTH_1)
> +			err = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (bus_width == MMC_BUS_WIDTH_1)
> +		goto out;
> +
> +	/* only compare read only fields */
> +
> +	err =	(!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
> +			bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
> +		(ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
> +			bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
> +		(ext_csd[EXT_CSD_REV] ==
> +			bw_ext_csd[EXT_CSD_REV]) &&
> +		(ext_csd[EXT_CSD_STRUCTURE] ==
> +			bw_ext_csd[EXT_CSD_STRUCTURE]) &&
> +		(ext_csd[EXT_CSD_CARD_TYPE] ==
> +			bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
> +		(ext_csd[EXT_CSD_S_A_TIMEOUT] ==
> +			bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
> +		(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
> +			bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
> +		(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
> +			bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
> +		(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
> +			bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
> +		(ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
> +			bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
> +		(ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
> +			bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
> +		(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
> +			bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
> +		(ext_csd[EXT_CSD_TRIM_MULT] ==
> +			bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
> +		memcmp(&ext_csd[EXT_CSD_SEC_CNT],
> +			&bw_ext_csd[EXT_CSD_SEC_CNT],
> +			4) != 0);
> +	if (err)
> +		err = -EINVAL;
> +
> +out:
> +	mmc_free_ext_csd(bw_ext_csd);
> 	return err;
> }
> 
> @@ -438,6 +520,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> 	u32 cid[4];
> 	unsigned int max_dtr;
> 	u32 rocr;
> +	u8 *ext_csd = NULL;
> 
> 	BUG_ON(!host);
> 	WARN_ON(!host->claimed);
> @@ -536,7 +619,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> 		/*
> 		 * Fetch and process extended CSD.
> 		 */
> -		err = mmc_read_ext_csd(card);
> +
> +		err = mmc_get_ext_csd(card, &ext_csd);
> +		if (err)
> +			goto free_card;
> +		err = mmc_read_ext_csd(card, ext_csd);
> 		if (err)
> 			goto free_card;
> 
> @@ -676,14 +763,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> 					 0);
> 			if (!err) {
> 				mmc_set_bus_width(card->host, bus_width);
> +
> 				/*
> 				 * If controller can't handle bus width test,
> -				 * use the highest bus width to maintain
> -				 * compatibility with previous MMC behavior.
> +				 * compare ext_csd previously read in 1 bit mode
> +				 * against ext_csd at new bus width
> 				 */
> 				if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> -					break;
> -				err = mmc_bus_test(card, bus_width);
> +					err = mmc_compare_ext_csds(card,
> +						ext_csd,
> +						bus_width);
> +				else
> +					err = mmc_bus_test(card, bus_width);
> 				if (!err)
> 					break;
> 			}
> @@ -730,12 +821,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
> 	if (!oldcard)
> 		host->card = card;
> 
> +	mmc_free_ext_csd(ext_csd);
> 	return 0;
> 
> free_card:
> 	if (!oldcard)
> 		mmc_remove_card(card);
> err:
> +	mmc_free_ext_csd(ext_csd);
> 
> 	return err;
> }
> -- 
> 1.7.0.4
> 
> 
> 
> On May 23, 2011, at 9:42 PM, Chris Ball wrote:
> 
>> Hi Philip,
>> 
>> On Sun, May 22 2011, Philip Rakity wrote:
>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>> index baab027..6db91d6 100644
>>> --- a/drivers/mmc/core/mmc.c
>>> +++ b/drivers/mmc/core/mmc.c
>>> @@ -174,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
>>> }
>>> 
>>> /*
>>> - * Read and decode extended CSD.
>>> + * Read extended CSD.
>>> */
>>> -static int mmc_read_ext_csd(struct mmc_card *card)
>>> +static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>> 
>> This one doesn't work -- you're missing the half of the patch that hooks
>> up the rest of mmc.c to the new code, which was in v1.  As-is, we get:
>> 
>> drivers/mmc/core/mmc.c: In function ‘mmc_init_card’:
>> drivers/mmc/core/mmc.c:621:3: error: too few arguments to function ‘mmc_read_ext_csd’
>> drivers/mmc/core/mmc.c:240:12: note: declared here
>> drivers/mmc/core/mmc.c: At top level:
>> drivers/mmc/core/mmc.c:404:12: warning: ‘mmc_compare_ext_csds’ defined but not used [-Wunused-function]
>> 
>> - Chris.
>> -- 
>> Chris Ball   <cjb@laptop.org>   <http://printf.net/>
>> One Laptop Per Child
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-05-31 18:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-17 18:40 [PATCH] mmc: eMMC bus width may not work on all platforms Philip Rakity
2011-05-22  0:40 ` Mok, Tze Siong
2011-05-22  1:20   ` Chris Ball
2011-05-22  1:52     ` Philip Rakity
2011-05-22 17:30     ` [PATCH V2] " Philip Rakity
2011-05-24  4:42       ` Chris Ball
2011-05-25  1:14         ` Philip Rakity
2011-05-31 18:11           ` Philip Rakity

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.