Skip to contentSkip to conversation

mmc: Fix OCR polling and splitted initialization

PATCH New Andrew Gabbasov 5 participants 15 messages Mar 19, 2015 – May 5, 2015 MMC, SD and SDIO

lore
Share & tools
lore
#0 lore raw

cover mmc: Fix OCR polling and splitted initialization

Patch 4 contains a fix for a problem that really occures with some MMC cards, that are capable to get to ready state within a single polling call.

Patch 6 is a fix for an error, that may be not so important and is not visible at the moment, since no platform does actually use pre-initialization. However, it still makes sense to fix it. It also makes the code more clean, straightforward, and understandable.

Patch 5 eliminates some unneeded delays in polling loops, thus improving overall performance.

Patches 2 and 3 clean up the code, making it simpler and more correct.

Patch 1 is actually not directly related to the patched code area, but just uses the occasion to fix the typo.

This is a series of patches, the next patch depending on previous ones, so that should be applied in order, on top of previous ones.

Andrew Gabbasov (6):
mmc: Fix typo in MMC type checking macro
mmc: Avoid extra duplicate entry in mmc device structure
mmc: Do not pass external mmc_cmd structure to mmc_send_op_cond_iter()
mmc: Continue polling MMC card for OCR only if it is still not ready
mmc: Restructure polling loops to avoid extra delays
mmc: Fix splitting device initialization

 drivers/mmc/mmc.c | 90 ++++++++++++++++++++++++++++++-------------------------
 include/mmc.h     |  6 ++--
 2 files changed, 51 insertions(+), 45 deletions(-)
Signature · 1 line
2.1.0
#1 lore raw

PATCH 1/6 mmc: Fix typo in MMC type checking macro

The version flag constant name used in IS_MMC macro is incorrect/undefined.

---
 include/mmc.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/mmc.h +1 -1
index 2ad0f19..a251531 100644
@@ -61,7 +61,7 @@
 #define SD_DATA_4BIT	0x00040000
 
 #define IS_SD(x)	((x)->version & SD_VERSION_SD)
-#define IS_MMC(x)	((x)->version & SD_VERSION_MMC)
+#define IS_MMC(x)	((x)->version & MMC_VERSION_MMC)
 
 #define MMC_DATA_READ		1
 #define MMC_DATA_WRITE		2
Signature · 1 line
2.1.0
#2 lore raw

PATCH 1/6 mmc: Fix typo in MMC type checking macro

Hi Andrew,

Quoted 25 lines · Andrew Gabbasov

The version flag constant name used in IS_MMC macro is incorrect/undefined.

---
include/mmc.h | 2 +-

1 file changed, 1 insertion(+), 1 deletion(-)
include/mmc.h +1 -1
index 2ad0f19..a251531 100644
@@ -61,7 +61,7 @@
 #define SD_DATA_4BIT	0x00040000
 
 #define IS_SD(x)	((x)->version & SD_VERSION_SD)
-#define IS_MMC(x)	((x)->version & SD_VERSION_MMC)
+#define IS_MMC(x)	((x)->version & MMC_VERSION_MMC)
 
 #define MMC_DATA_READ		1
 #define MMC_DATA_WRITE		2
Signature · 1 line
2.1.0

Thanks, applied.

BTW, please make sure you CC me personally when sending patches since this slipped out of my attention.

Regards

? Pantelis

#3 lore raw

PATCH 2/6 mmc: Avoid extra duplicate entry in mmc device structure

In reply to Andrew Gabbasov

The 'op_cond_response' field in mmc structure contains the response from the last SEND_OP_COND MMC command while making iterational polling of the card. Later it is copied to 'ocr' field, designed to contain the OCR register value, which is actually the same response from the same command. So, these fields have actually the same data, just in different time periods. It's easier to use the same 'ocr' field in both cases at once, without temporary using of the 'op_cond_response' field.

---
 drivers/mmc/mmc.c | 13 +++++++------
 include/mmc.h     |  1 -
 2 files changed, 7 insertions(+), 7 deletions(-)
drivers/mmc/mmc.c +7 -6
index a13769e..fe00a19 100644
@@ -362,8 +362,8 @@ static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
 	if (use_arg && !mmc_host_is_spi(mmc)) {
 		cmd->cmdarg =
 			(mmc->cfg->voltages &
-			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
-			(mmc->op_cond_response & OCR_ACCESS_MODE);
+			(mmc->ocr & OCR_VOLTAGE_MASK)) |
+			(mmc->ocr & OCR_ACCESS_MODE);
 
 		if (mmc->cfg->host_caps & MMC_MODE_HC)
 			cmd->cmdarg |= OCR_HCS;
@@ -371,7 +371,7 @@ static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
 	err = mmc_send_cmd(mmc, cmd, NULL);
 	if (err)
 		return err;
-	mmc->op_cond_response = cmd->response[0];
+	mmc->ocr = cmd->response[0];
 	return 0;
 }
 
@@ -391,7 +391,7 @@ static int mmc_send_op_cond(struct mmc *mmc)
 			return err;
 
 		/* exit if not busy (flag seems to be inverted) */
-		if (mmc->op_cond_response & OCR_BUSY)
+		if (mmc->ocr & OCR_BUSY)
 			return 0;
 	}
 	return IN_PROGRESS;
@@ -413,7 +413,7 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 		if (get_timer(start) > timeout)
 			return UNUSABLE_ERR;
 		udelay(100);
-	} while (!(mmc->op_cond_response & OCR_BUSY));
+	} while (!(mmc->ocr & OCR_BUSY));
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
@@ -424,10 +424,11 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 
 		if (err)
 			return err;
+
+		mmc->ocr = cmd.response[0];
 	}
 
 	mmc->version = MMC_VERSION_UNKNOWN;
-	mmc->ocr = cmd.response[0];
 
 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
 	mmc->rca = 1;
include/mmc.h +0 -1
index a251531..644e3fa 100644
@@ -356,7 +356,6 @@ struct mmc {
 	char op_cond_pending;	/* 1 if we are waiting on an op_cond command */
 	char init_in_progress;	/* 1 if we have done mmc_start_init() */
 	char preinit;		/* start init as early as possible */
-	uint op_cond_response;	/* the response byte from the last op_cond */
 	int ddr_mode;
 };
 
Signature · 1 line
2.1.0
#4 lore raw

PATCH 2/6 mmc: Avoid extra duplicate entry in mmc device structure

Hi Andrw,

Quoted 86 lines · Andrew Gabbasov

The 'op_cond_response' field in mmc structure contains the response from the last SEND_OP_COND MMC command while making iterational polling of the card. Later it is copied to 'ocr' field, designed to contain the OCR register value, which is actually the same response from the same command. So, these fields have actually the same data, just in different time periods. It's easier to use the same 'ocr' field in both cases at once, without temporary using of the 'op_cond_response' field.

---
drivers/mmc/mmc.c | 13 +++++++------
include/mmc.h | 1 -

2 files changed, 7 insertions(+), 7 deletions(-)
drivers/mmc/mmc.c +7 -6
index a13769e..fe00a19 100644
@@ -362,8 +362,8 @@ static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
 	if (use_arg && !mmc_host_is_spi(mmc)) {
 		cmd->cmdarg =
 			(mmc->cfg->voltages &
-			(mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
-			(mmc->op_cond_response & OCR_ACCESS_MODE);
+			(mmc->ocr & OCR_VOLTAGE_MASK)) |
+			(mmc->ocr & OCR_ACCESS_MODE);
 
 		if (mmc->cfg->host_caps & MMC_MODE_HC)
 			cmd->cmdarg |= OCR_HCS;
@@ -371,7 +371,7 @@ static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
 	err = mmc_send_cmd(mmc, cmd, NULL);
 	if (err)
 		return err;
-	mmc->op_cond_response = cmd->response[0];
+	mmc->ocr = cmd->response[0];
 	return 0;
 }
 
@@ -391,7 +391,7 @@ static int mmc_send_op_cond(struct mmc *mmc)
 			return err;
 
 		/* exit if not busy (flag seems to be inverted) */
-		if (mmc->op_cond_response & OCR_BUSY)
+		if (mmc->ocr & OCR_BUSY)
 			return 0;
 	}
 	return IN_PROGRESS;
@@ -413,7 +413,7 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 		if (get_timer(start) > timeout)
 			return UNUSABLE_ERR;
 		udelay(100);
-	} while (!(mmc->op_cond_response & OCR_BUSY));
+	} while (!(mmc->ocr & OCR_BUSY));
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
@@ -424,10 +424,11 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 
 		if (err)
 			return err;
+
+		mmc->ocr = cmd.response[0];
 	}
 
 	mmc->version = MMC_VERSION_UNKNOWN;
-	mmc->ocr = cmd.response[0];
 
 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
 	mmc->rca = 1;
include/mmc.h +0 -1
index a251531..644e3fa 100644
@@ -356,7 +356,6 @@ struct mmc {
 	char op_cond_pending;	/* 1 if we are waiting on an op_cond command */
 	char init_in_progress;	/* 1 if we have done mmc_start_init() */
 	char preinit;		/* start init as early as possible */
-	uint op_cond_response;	/* the response byte from the last op_cond */
 	int ddr_mode;
 };
 
Signature · 1 line
2.1.0

Thanks, applied.

Regards

? Pantelis

#5 lore raw

PATCH 3/6 mmc: Do not pass external mmc_cmd structure to mmc_send_op_cond_iter()

In reply to Andrew Gabbasov

The previous change to use 'ocr' structure field for storing send_op_cond command response also stopped using command response directly outside of mmc_send_op_cond_iter(). Now it becomes possible to use command structure in mmc_send_op_cond_iter() locally, removing a necessity to pass it as an argument from the caller.

---
 drivers/mmc/mmc.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)
drivers/mmc/mmc.c +11 -13
index fe00a19..d073d79 100644
@@ -350,34 +350,32 @@ static int sd_send_op_cond(struct mmc *mmc)
 	return 0;
 }
 
-/* We pass in the cmd since otherwise the init seems to fail */
-static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
-		int use_arg)
+static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
 {
+	struct mmc_cmd cmd;
 	int err;
 
-	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
-	cmd->resp_type = MMC_RSP_R3;
-	cmd->cmdarg = 0;
+	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
+	cmd.resp_type = MMC_RSP_R3;
+	cmd.cmdarg = 0;
 	if (use_arg && !mmc_host_is_spi(mmc)) {
-		cmd->cmdarg =
+		cmd.cmdarg =
 			(mmc->cfg->voltages &
 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
 			(mmc->ocr & OCR_ACCESS_MODE);
 
 		if (mmc->cfg->host_caps & MMC_MODE_HC)
-			cmd->cmdarg |= OCR_HCS;
+			cmd.cmdarg |= OCR_HCS;
 	}
-	err = mmc_send_cmd(mmc, cmd, NULL);
+	err = mmc_send_cmd(mmc, &cmd, NULL);
 	if (err)
 		return err;
-	mmc->ocr = cmd->response[0];
+	mmc->ocr = cmd.response[0];
 	return 0;
 }
 
 static int mmc_send_op_cond(struct mmc *mmc)
 {
-	struct mmc_cmd cmd;
 	int err, i;
 
 	/* Some cards seem to need this */
@@ -386,7 +384,7 @@ static int mmc_send_op_cond(struct mmc *mmc)
  	/* Asking to the card its capabilities */
 	mmc->op_cond_pending = 1;
 	for (i = 0; i < 2; i++) {
-		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
+		err = mmc_send_op_cond_iter(mmc, i != 0);
 		if (err)
 			return err;
 
@@ -407,7 +405,7 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	mmc->op_cond_pending = 0;
 	start = get_timer(0);
 	do {
-		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
+		err = mmc_send_op_cond_iter(mmc, 1);
 		if (err)
 			return err;
 		if (get_timer(start) > timeout)
Signature · 1 line
2.1.0
#6 lore raw

PATCH 3/6 mmc: Do not pass external mmc_cmd structure to mmc_send_op_cond_iter()

Hi Andrew,

Quoted 81 lines · Andrew Gabbasov

The previous change to use 'ocr' structure field for storing send_op_cond command response also stopped using command response directly outside of mmc_send_op_cond_iter(). Now it becomes possible to use command structure in mmc_send_op_cond_iter() locally, removing a necessity to pass it as an argument from the caller.

---
drivers/mmc/mmc.c | 24 +++++++++++-------------

1 file changed, 11 insertions(+), 13 deletions(-)
drivers/mmc/mmc.c +11 -13
index fe00a19..d073d79 100644
@@ -350,34 +350,32 @@ static int sd_send_op_cond(struct mmc *mmc)
 	return 0;
 }
 
-/* We pass in the cmd since otherwise the init seems to fail */
-static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
-		int use_arg)
+static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
 {
+	struct mmc_cmd cmd;
 	int err;
 
-	cmd->cmdidx = MMC_CMD_SEND_OP_COND;
-	cmd->resp_type = MMC_RSP_R3;
-	cmd->cmdarg = 0;
+	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
+	cmd.resp_type = MMC_RSP_R3;
+	cmd.cmdarg = 0;
 	if (use_arg && !mmc_host_is_spi(mmc)) {
-		cmd->cmdarg =
+		cmd.cmdarg =
 			(mmc->cfg->voltages &
 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
 			(mmc->ocr & OCR_ACCESS_MODE);
 
 		if (mmc->cfg->host_caps & MMC_MODE_HC)
-			cmd->cmdarg |= OCR_HCS;
+			cmd.cmdarg |= OCR_HCS;
 	}
-	err = mmc_send_cmd(mmc, cmd, NULL);
+	err = mmc_send_cmd(mmc, &cmd, NULL);
 	if (err)
 		return err;
-	mmc->ocr = cmd->response[0];
+	mmc->ocr = cmd.response[0];
 	return 0;
 }
 
 static int mmc_send_op_cond(struct mmc *mmc)
 {
-	struct mmc_cmd cmd;
 	int err, i;
 
 	/* Some cards seem to need this */
@@ -386,7 +384,7 @@ static int mmc_send_op_cond(struct mmc *mmc)
 	/* Asking to the card its capabilities */
 	mmc->op_cond_pending = 1;
 	for (i = 0; i < 2; i++) {
-		err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
+		err = mmc_send_op_cond_iter(mmc, i != 0);
 		if (err)
 			return err;
 
@@ -407,7 +405,7 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	mmc->op_cond_pending = 0;
 	start = get_timer(0);
 	do {
-		err = mmc_send_op_cond_iter(mmc, &cmd, 1);
+		err = mmc_send_op_cond_iter(mmc, 1);
 		if (err)
 			return err;
 		if (get_timer(start) > timeout)
Signature · 1 line
2.1.0

Thanks, Applied.

? Pantelis

#7 lore raw

PATCH 4/6 mmc: Continue polling MMC card for OCR only if it is still not ready

In reply to Andrew Gabbasov

Some MMC cards come to ready state quite quickly, so that the respective flag appears to be set in mmc_send_op_cond already. In this case trying to continue polling the card with CMD1 in mmc_complete_op_cond is incorrect and may lead to unpredictable results. So check the flag before polling and skip it appropriately.

---
 drivers/mmc/mmc.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/mmc/mmc.c +11 -9
index d073d79..42af47c 100644
@@ -403,15 +403,17 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	int err;
 
 	mmc->op_cond_pending = 0;
-	start = get_timer(0);
-	do {
-		err = mmc_send_op_cond_iter(mmc, 1);
-		if (err)
-			return err;
-		if (get_timer(start) > timeout)
-			return UNUSABLE_ERR;
-		udelay(100);
-	} while (!(mmc->ocr & OCR_BUSY));
+	if (!(mmc->ocr & OCR_BUSY)) {
+		start = get_timer(0);
+		do {
+			err = mmc_send_op_cond_iter(mmc, 1);
+			if (err)
+				return err;
+			if (get_timer(start) > timeout)
+				return UNUSABLE_ERR;
+			udelay(100);
+		} while (!(mmc->ocr & OCR_BUSY));
+	}
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
Signature · 1 line
2.1.0
#8 lore raw

PATCH 4/6 mmc: Continue polling MMC card for OCR only if it is still not ready

Hi, Andrew

There is already a patch to fix this issue.
Patchwork: https://patchwork.ozlabs.org/patch/451775/

Regards,
Peng.

-----Original Message-----
From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Andrew Gabbasov
Sent: Thursday, March 19, 2015 8:44 PM
To: u-boot at lists.denx.de
Subject: [U-Boot] [PATCH 4/6] mmc: Continue polling MMC card for OCR only if it is still not ready

Some MMC cards come to ready state quite quickly, so that the respective flag appears to be set in mmc_send_op_cond already. In this case trying to continue polling the card with CMD1 in mmc_complete_op_cond is incorrect and may lead to unpredictable results. So check the flag before polling and skip it appropriately.

---
 drivers/mmc/mmc.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/mmc/mmc.c +11 -9
@@ -403,15 +403,17 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	int err;
 
 	mmc->op_cond_pending = 0;
-	start = get_timer(0);
-	do {
-		err = mmc_send_op_cond_iter(mmc, 1);
-		if (err)
-			return err;
-		if (get_timer(start) > timeout)
-			return UNUSABLE_ERR;
-		udelay(100);
-	} while (!(mmc->ocr & OCR_BUSY));
+	if (!(mmc->ocr & OCR_BUSY)) {
+		start = get_timer(0);
+		do {
+			err = mmc_send_op_cond_iter(mmc, 1);
+			if (err)
+				return err;
+			if (get_timer(start) > timeout)
+				return UNUSABLE_ERR;
+			udelay(100);
+		} while (!(mmc->ocr & OCR_BUSY));
+	}
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;

--
2.1.0

_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

#9 lore raw

PATCH 4/6 mmc: Continue polling MMC card for OCR only if it is still not ready

Quoted 42 lines · Peng.Fan at freescale.com

Hi, Andrew

There is already a patch to fix this issue.
Patchwork: https://patchwork.ozlabs.org/patch/451775/

Regards,
Peng.

-----Original Message-----
From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Andrew Gabbasov
Sent: Thursday, March 19, 2015 8:44 PM
To: u-boot at lists.denx.de
Subject: [U-Boot] [PATCH 4/6] mmc: Continue polling MMC card for OCR only if it is still not ready

Some MMC cards come to ready state quite quickly, so that the respective flag appears to be set in mmc_send_op_cond already. In this case trying to continue polling the card with CMD1 in mmc_complete_op_cond is incorrect and may lead to unpredictable results. So check the flag before polling and skip it appropriately.

---
 drivers/mmc/mmc.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/mmc/mmc.c +5 -9
@@ -403,15 +403,17 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	int err;
 
 	mmc->op_cond_pending = 0;
-	start = get_timer(0);
-	do {
-		err = mmc_send_op_cond_iter(mmc, 1);
-		if (err)
-			return err;
-		if (get_timer(start) > timeout)
-			return UNUSABLE_ERR;
-		udelay(100);
-	} while (!(mmc->ocr & OCR_BUSY));
+	if (!(mmc->ocr & OCR_BUSY)) {
+		start = get_timer(0);
+		do {
+			err = mmc_send_op_cond_iter(mmc, 1);
+			if (err)

drivers/mmc/mmc.c static int mmc_complete_op_cond(struct mmc *mmc)

Quoted 10 lines
drivers/mmc/mmc.c +6 -1
+				return err;
+			if (get_timer(start) > timeout)
+				return UNUSABLE_ERR;
+			udelay(100);
+		} while (!(mmc->ocr & OCR_BUSY));
+	}
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
--

Here's another patch that solves the problem a little earlier. It has this disadvantage of being slightly bigger,
though it makes the code look better.

https://github.com/boundarydevices/u-boot-imx6/commit/c0260ca

I'll ack any version as they all seem to solve the problem.

Troy

#10 lore raw

PATCH 4/6 mmc: Continue polling MMC card for OCR only if it is still not ready

In reply to Andrew Gabbasov

Hi Andrew,

Quoted 47 lines · Andrew Gabbasov

Some MMC cards come to ready state quite quickly, so that the respective flag appears to be set in mmc_send_op_cond already. In this case trying to continue polling the card with CMD1 in mmc_complete_op_cond is incorrect and may lead to unpredictable results. So check the flag before polling and skip it appropriately.

---
drivers/mmc/mmc.c | 20 +++++++++++---------

1 file changed, 11 insertions(+), 9 deletions(-)
drivers/mmc/mmc.c +11 -9
index d073d79..42af47c 100644
@@ -403,15 +403,17 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	int err;
 
 	mmc->op_cond_pending = 0;
-	start = get_timer(0);
-	do {
-		err = mmc_send_op_cond_iter(mmc, 1);
-		if (err)
-			return err;
-		if (get_timer(start) > timeout)
-			return UNUSABLE_ERR;
-		udelay(100);
-	} while (!(mmc->ocr & OCR_BUSY));
+	if (!(mmc->ocr & OCR_BUSY)) {
+		start = get_timer(0);
+		do {
+			err = mmc_send_op_cond_iter(mmc, 1);
+			if (err)
+				return err;
+			if (get_timer(start) > timeout)
+				return UNUSABLE_ERR;
+			udelay(100);
+		} while (!(mmc->ocr & OCR_BUSY));
+	}
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
Signature · 1 line
2.1.0

Thanks, Applied.

? Pantelis

PS. Peng, I?m picking up this instead of your patch.

#11 lore raw

PATCH 5/6 mmc: Restructure polling loops to avoid extra delays

In reply to Andrew Gabbasov

The polling loops in sd_send_op_cond and mmc_complete_op_cond functions check the ready flag state at the end of the loop, that is after executing a delay inside the loop, which, in case of exiting with no error, is not needed. Also, one of these loops, as well as the loop in mmc_send_status, have the delay just before exiting on timeout conditions.

Restructure all these loops to check the respective conditions before making a delay for the next loop pass, and to appropriately exit without the delay.

---
 drivers/mmc/mmc.c | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)
drivers/mmc/mmc.c +17 -10
index 42af47c..b81533c 100644
@@ -118,7 +118,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)
 	if (!mmc_host_is_spi(mmc))
 		cmd.cmdarg = mmc->rca << 16;
 
-	do {
+	while (1) {
 		err = mmc_send_cmd(mmc, &cmd, NULL);
 		if (!err) {
 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
@@ -135,9 +135,11 @@ int mmc_send_status(struct mmc *mmc, int timeout)
 		} else if (--retries < 0)
 			return err;
 
-		udelay(1000);
+		if (timeout-- <= 0)
+			break;
 
-	} while (timeout--);
+		udelay(1000);
+	}
 
 #ifdef CONFIG_MMC_TRACE
 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
@@ -291,7 +293,7 @@ static int sd_send_op_cond(struct mmc *mmc)
 	int err;
 	struct mmc_cmd cmd;
 
-	do {
+	while (1) {
 		cmd.cmdidx = MMC_CMD_APP_CMD;
 		cmd.resp_type = MMC_RSP_R1;
 		cmd.cmdarg = 0;
@@ -322,11 +324,14 @@ static int sd_send_op_cond(struct mmc *mmc)
 		if (err)
 			return err;
 
-		udelay(1000);
-	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
+		if (cmd.response[0] & OCR_BUSY)
+			break;
 
-	if (timeout <= 0)
-		return UNUSABLE_ERR;
+		if (timeout-- <= 0)
+			return UNUSABLE_ERR;
+
+		udelay(1000);
+	}
 
 	if (mmc->version != SD_VERSION_2)
 		mmc->version = SD_VERSION_1_0;
@@ -405,14 +410,16 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	mmc->op_cond_pending = 0;
 	if (!(mmc->ocr & OCR_BUSY)) {
 		start = get_timer(0);
-		do {
+		while (1) {
 			err = mmc_send_op_cond_iter(mmc, 1);
 			if (err)
 				return err;
+			if (mmc->ocr & OCR_BUSY)
+				break;
 			if (get_timer(start) > timeout)
 				return UNUSABLE_ERR;
 			udelay(100);
-		} while (!(mmc->ocr & OCR_BUSY));
+		}
 	}
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
Signature · 1 line
2.1.0
#12 lore raw

PATCH 5/6 mmc: Restructure polling loops to avoid extra delays

Hi Andrew,

Quoted 93 lines · Andrew Gabbasov

The polling loops in sd_send_op_cond and mmc_complete_op_cond functions check the ready flag state at the end of the loop, that is after executing a delay inside the loop, which, in case of exiting with no error, is not needed. Also, one of these loops, as well as the loop in mmc_send_status, have the delay just before exiting on timeout conditions.

Restructure all these loops to check the respective conditions before making a delay for the next loop pass, and to appropriately exit without the delay.

---
drivers/mmc/mmc.c | 27 +++++++++++++++++----------

1 file changed, 17 insertions(+), 10 deletions(-)
drivers/mmc/mmc.c +17 -10
index 42af47c..b81533c 100644
@@ -118,7 +118,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)
 	if (!mmc_host_is_spi(mmc))
 		cmd.cmdarg = mmc->rca << 16;
 
-	do {
+	while (1) {
 		err = mmc_send_cmd(mmc, &cmd, NULL);
 		if (!err) {
 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
@@ -135,9 +135,11 @@ int mmc_send_status(struct mmc *mmc, int timeout)
 		} else if (--retries < 0)
 			return err;
 
-		udelay(1000);
+		if (timeout-- <= 0)
+			break;
 
-	} while (timeout--);
+		udelay(1000);
+	}
 
 #ifdef CONFIG_MMC_TRACE
 	status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
@@ -291,7 +293,7 @@ static int sd_send_op_cond(struct mmc *mmc)
 	int err;
 	struct mmc_cmd cmd;
 
-	do {
+	while (1) {
 		cmd.cmdidx = MMC_CMD_APP_CMD;
 		cmd.resp_type = MMC_RSP_R1;
 		cmd.cmdarg = 0;
@@ -322,11 +324,14 @@ static int sd_send_op_cond(struct mmc *mmc)
 		if (err)
 			return err;
 
-		udelay(1000);
-	} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
+		if (cmd.response[0] & OCR_BUSY)
+			break;
 
-	if (timeout <= 0)
-		return UNUSABLE_ERR;
+		if (timeout-- <= 0)
+			return UNUSABLE_ERR;
+
+		udelay(1000);
+	}
 
 	if (mmc->version != SD_VERSION_2)
 		mmc->version = SD_VERSION_1_0;
@@ -405,14 +410,16 @@ static int mmc_complete_op_cond(struct mmc *mmc)
 	mmc->op_cond_pending = 0;
 	if (!(mmc->ocr & OCR_BUSY)) {
 		start = get_timer(0);
-		do {
+		while (1) {
 			err = mmc_send_op_cond_iter(mmc, 1);
 			if (err)
 				return err;
+			if (mmc->ocr & OCR_BUSY)
+				break;
 			if (get_timer(start) > timeout)
 				return UNUSABLE_ERR;
 			udelay(100);
-		} while (!(mmc->ocr & OCR_BUSY));
+		}
 	}
 
 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
Signature · 1 line
2.1.0

Thanks, Applied.

? Pantelis

#13 lore raw

PATCH 6/6 mmc: Fix splitting device initialization

In reply to Andrew Gabbasov

Starting part of device initialization sets the init_in_progress flag only if the MMC card did not yet come to ready state and needs to continue polling. If the card is SD or if the MMC card became ready quickly, the flag is not set and (if using pre-initialization) the starting phase will be re-executed from mmc_init function.

Set the init_in_progress flag in all non-error cases. Also, move flags setting statements around so that the flags are not set in error paths. Also, IN_PROGRESS return status becomes unnecessary, so get rid of it.

---
 drivers/mmc/mmc.c | 16 ++++++++--------
 include/mmc.h     |  3 +--
 2 files changed, 9 insertions(+), 10 deletions(-)
drivers/mmc/mmc.c +8 -8
index b81533c..31f8647 100644
@@ -387,7 +387,6 @@ static int mmc_send_op_cond(struct mmc *mmc)
 	mmc_go_idle(mmc);
 
  	/* Asking to the card its capabilities */
-	mmc->op_cond_pending = 1;
 	for (i = 0; i < 2; i++) {
 		err = mmc_send_op_cond_iter(mmc, i != 0);
 		if (err)
@@ -395,9 +394,10 @@ static int mmc_send_op_cond(struct mmc *mmc)
 
 		/* exit if not busy (flag seems to be inverted) */
 		if (mmc->ocr & OCR_BUSY)
-			return 0;
+			break;
 	}
-	return IN_PROGRESS;
+	mmc->op_cond_pending = 1;
+	return 0;
 }
 
 static int mmc_complete_op_cond(struct mmc *mmc)
@@ -1627,7 +1627,7 @@ int mmc_start_init(struct mmc *mmc)
 	if (err == TIMEOUT) {
 		err = mmc_send_op_cond(mmc);
 
-		if (err && err != IN_PROGRESS) {
+		if (err) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 			printf("Card did not respond to voltage select!\n");
 #endif
@@ -1635,7 +1635,7 @@ int mmc_start_init(struct mmc *mmc)
 		}
 	}
 
-	if (err == IN_PROGRESS)
+	if (!err)
 		mmc->init_in_progress = 1;
 
 	return err;
@@ -1645,6 +1645,7 @@ static int mmc_complete_init(struct mmc *mmc)
 {
 	int err = 0;
 
+	mmc->init_in_progress = 0;
 	if (mmc->op_cond_pending)
 		err = mmc_complete_op_cond(mmc);
 
@@ -1654,13 +1655,12 @@ static int mmc_complete_init(struct mmc *mmc)
 		mmc->has_init = 0;
 	else
 		mmc->has_init = 1;
-	mmc->init_in_progress = 0;
 	return err;
 }
 
 int mmc_init(struct mmc *mmc)
 {
-	int err = IN_PROGRESS;
+	int err = 0;
 	unsigned start;
 
 	if (mmc->has_init)
@@ -1671,7 +1671,7 @@ int mmc_init(struct mmc *mmc)
 	if (!mmc->init_in_progress)
 		err = mmc_start_init(mmc);
 
-	if (!err || err == IN_PROGRESS)
+	if (!err)
 		err = mmc_complete_init(mmc);
 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
 	return err;
include/mmc.h +1 -2
index 644e3fa..fbcbe35 100644
@@ -70,8 +70,7 @@
 #define UNUSABLE_ERR		-17 /* Unusable Card */
 #define COMM_ERR		-18 /* Communications Error */
 #define TIMEOUT			-19
-#define IN_PROGRESS		-20 /* operation is in progress */
-#define SWITCH_ERR		-21 /* Card reports failure to switch mode */
+#define SWITCH_ERR		-20 /* Card reports failure to switch mode */
 
 #define MMC_CMD_GO_IDLE_STATE		0
 #define MMC_CMD_SEND_OP_COND		1
Signature · 1 line
2.1.0
#14 lore raw

PATCH 6/6 mmc: Fix splitting device initialization

Hi Andrew,

Quoted 109 lines · Andrew Gabbasov

Starting part of device initialization sets the init_in_progress flag only if the MMC card did not yet come to ready state and needs to continue polling. If the card is SD or if the MMC card became ready quickly, the flag is not set and (if using pre-initialization) the starting phase will be re-executed from mmc_init function.

Set the init_in_progress flag in all non-error cases. Also, move flags setting statements around so that the flags are not set in error paths. Also, IN_PROGRESS return status becomes unnecessary, so get rid of it.

---
drivers/mmc/mmc.c | 16 ++++++++--------
include/mmc.h | 3 +--

2 files changed, 9 insertions(+), 10 deletions(-)
drivers/mmc/mmc.c +8 -8
index b81533c..31f8647 100644
@@ -387,7 +387,6 @@ static int mmc_send_op_cond(struct mmc *mmc)
 	mmc_go_idle(mmc);
 
 	/* Asking to the card its capabilities */
-	mmc->op_cond_pending = 1;
 	for (i = 0; i < 2; i++) {
 		err = mmc_send_op_cond_iter(mmc, i != 0);
 		if (err)
@@ -395,9 +394,10 @@ static int mmc_send_op_cond(struct mmc *mmc)
 
 		/* exit if not busy (flag seems to be inverted) */
 		if (mmc->ocr & OCR_BUSY)
-			return 0;
+			break;
 	}
-	return IN_PROGRESS;
+	mmc->op_cond_pending = 1;
+	return 0;
 }
 
 static int mmc_complete_op_cond(struct mmc *mmc)
@@ -1627,7 +1627,7 @@ int mmc_start_init(struct mmc *mmc)
 	if (err == TIMEOUT) {
 		err = mmc_send_op_cond(mmc);
 
-		if (err && err != IN_PROGRESS) {
+		if (err) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 			printf("Card did not respond to voltage select!\n");
 #endif
@@ -1635,7 +1635,7 @@ int mmc_start_init(struct mmc *mmc)
 		}
 	}
 
-	if (err == IN_PROGRESS)
+	if (!err)
 		mmc->init_in_progress = 1;
 
 	return err;
@@ -1645,6 +1645,7 @@ static int mmc_complete_init(struct mmc *mmc)
 {
 	int err = 0;
 
+	mmc->init_in_progress = 0;
 	if (mmc->op_cond_pending)
 		err = mmc_complete_op_cond(mmc);
 
@@ -1654,13 +1655,12 @@ static int mmc_complete_init(struct mmc *mmc)
 		mmc->has_init = 0;
 	else
 		mmc->has_init = 1;
-	mmc->init_in_progress = 0;
 	return err;
 }
 
 int mmc_init(struct mmc *mmc)
 {
-	int err = IN_PROGRESS;
+	int err = 0;
 	unsigned start;
 
 	if (mmc->has_init)
@@ -1671,7 +1671,7 @@ int mmc_init(struct mmc *mmc)
 	if (!mmc->init_in_progress)
 		err = mmc_start_init(mmc);
 
-	if (!err || err == IN_PROGRESS)
+	if (!err)
 		err = mmc_complete_init(mmc);
 	debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
 	return err;
include/mmc.h +1 -2
index 644e3fa..fbcbe35 100644
@@ -70,8 +70,7 @@
 #define UNUSABLE_ERR		-17 /* Unusable Card */
 #define COMM_ERR		-18 /* Communications Error */
 #define TIMEOUT			-19
-#define IN_PROGRESS		-20 /* operation is in progress */
-#define SWITCH_ERR		-21 /* Card reports failure to switch mode */
+#define SWITCH_ERR		-20 /* Card reports failure to switch mode */
 
 #define MMC_CMD_GO_IDLE_STATE		0
 #define MMC_CMD_SEND_OP_COND		1
Signature · 1 line
2.1.0

Thanks, Applied.

? Pantelis