Skip to contentSkip to conversation

mmc: fsl_esdhc: Fix PIO timeout

PATCH New Benoît Thébaudeau 3 participants 5 messages Oct 29, 2017 – Nov 1, 2017 MMC, SD and SDIO

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mmc: fsl_esdhc: Fix PIO timeout

The following error has been observed on i.MX25 with a high-speed SDSC card:
Data Write Failed in PIO Mode.

It was caused by the timeout set on PRSSTAT.BWEN, which was triggered because this bit takes 15 ms to be set after writing the first block to DATPORT with this card. Without this timeout, all the blocks are properly written.

This timeout was implemented by decrementing a variable, so it was depending on the CPU frequency. Fix this issue by setting this timeout to a long enough absolute duration (500 ms).

Cc Stefano Babic <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Jaehoon Chung <[email protected]>
---
 drivers/mmc/fsl_esdhc.c | 26 +++++++++++++-------------
 include/fsl_esdhc.h     |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)
drivers/mmc/fsl_esdhc.c +13 -13
index cc188c4260..499d622c6d 100644
@@ -171,20 +171,20 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv,
 	uint databuf;
 	uint size;
 	uint irqstat;
-	uint timeout;
+	ulong start;
 
 	if (data->flags & MMC_DATA_READ) {
 		blocks = data->blocks;
 		buffer = data->dest;
 		while (blocks) {
-			timeout = PIO_TIMEOUT;
+			start = get_timer(0);
 			size = data->blocksize;
 			irqstat = esdhc_read32(&regs->irqstat);
-			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
-				&& --timeout);
-			if (timeout <= 0) {
-				printf("\nData Read Failed in PIO Mode.");
-				return;
+			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)) {
+				if (get_timer(start) > PIO_TIMEOUT) {
+					printf("\nData Read Failed in PIO Mode.");
+					return;
+				}
 			}
 			while (size && (!(irqstat & IRQSTAT_TC))) {
 				udelay(100); /* Wait before last byte transfer complete */
@@ -200,14 +200,14 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv,
 		blocks = data->blocks;
 		buffer = (char *)data->src;
 		while (blocks) {
-			timeout = PIO_TIMEOUT;
+			start = get_timer(0);
 			size = data->blocksize;
 			irqstat = esdhc_read32(&regs->irqstat);
-			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BWEN)
-				&& --timeout);
-			if (timeout <= 0) {
-				printf("\nData Write Failed in PIO Mode.");
-				return;
+			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BWEN)) {
+				if (get_timer(start) > PIO_TIMEOUT) {
+					printf("\nData Write Failed in PIO Mode.");
+					return;
+				}
 			}
 			while (size && (!(irqstat & IRQSTAT_TC))) {
 				udelay(100); /* Wait before last byte transfer complete */
include/fsl_esdhc.h +1 -1
index 02b362d5e3..de1f5e7d9f 100644
@@ -130,7 +130,7 @@
 #define XFERTYP_DMAEN		0x00000001
 
 #define CINS_TIMEOUT		1000
-#define PIO_TIMEOUT		100000
+#define PIO_TIMEOUT		500
 
 #define DSADDR		0x2e004
 
Signature · 1 line
2.14.1
#1 lore raw

PATCH 1/1 mmc: fsl_esdhc: Fix PIO timeout

Quoted 9 lines · Benoît Thébaudeau

The following error has been observed on i.MX25 with a high-speed SDSC card:
Data Write Failed in PIO Mode.

It was caused by the timeout set on PRSSTAT.BWEN, which was triggered because this bit takes 15 ms to be set after writing the first block to DATPORT with this card. Without this timeout, all the blocks are properly written.

Quoted 8 lines

This timeout was implemented by decrementing a variable, so it was depending on the CPU frequency. Fix this issue by setting this timeout to a long enough absolute duration (500 ms).

Cc Stefano Babic <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Jaehoon Chung <[email protected]>
#2 lore raw

PATCH 1/1 mmc: fsl_esdhc: Fix PIO timeout

In reply to Benoît Thébaudeau
Quoted 41 lines · Benoît Thébaudeau

The following error has been observed on i.MX25 with a high-speed SDSC card:
Data Write Failed in PIO Mode.

It was caused by the timeout set on PRSSTAT.BWEN, which was triggered because this bit takes 15 ms to be set after writing the first block to DATPORT with this card. Without this timeout, all the blocks are properly written.

This timeout was implemented by decrementing a variable, so it was depending on the CPU frequency. Fix this issue by setting this timeout to a long enough absolute duration (500 ms).

Cc Stefano Babic <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Jaehoon Chung <[email protected]>
---
 drivers/mmc/fsl_esdhc.c | 26 +++++++++++++-------------
 include/fsl_esdhc.h     |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)
drivers/mmc/fsl_esdhc.c +2 -2
index cc188c4260..499d622c6d 100644
@@ -171,20 +171,20 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv,
        uint databuf;
        uint size;
        uint irqstat;
-       uint timeout;
+       ulong start;
 
        if (data->flags & MMC_DATA_READ) {
                blocks = data->blocks;
                buffer = data->dest;
                while (blocks) {
-                       timeout = PIO_TIMEOUT;
+                       start = get_timer(0);
                        size = data->blocksize;
                        irqstat = esdhc_read32(&regs->irqstat);

drivers/mmc/fsl_esdhc.c static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv, · line 187

Quoted 10 lines
drivers/mmc/fsl_esdhc.c +5 -5
-                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
-                               && --timeout);
-                       if (timeout <= 0) {
-                               printf("\nData Read Failed in PIO Mode.");
-                               return;
+                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)) {
+                               if (get_timer(start) > PIO_TIMEOUT) {
+                                       printf("\nData Read Failed in PIO Mode.");
+                                       return;
+                               }

How about using wait_for_bit here?

thanks!

Signature · 4 lines
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.
#3 lore raw

PATCH 1/1 mmc: fsl_esdhc: Fix PIO timeout

Quoted 47 lines · Jagan Teki
Quoted 45 lines · Benoît Thébaudeau

The following error has been observed on i.MX25 with a high-speed SDSC card:
Data Write Failed in PIO Mode.

It was caused by the timeout set on PRSSTAT.BWEN, which was triggered because this bit takes 15 ms to be set after writing the first block to DATPORT with this card. Without this timeout, all the blocks are properly written.

This timeout was implemented by decrementing a variable, so it was depending on the CPU frequency. Fix this issue by setting this timeout to a long enough absolute duration (500 ms).

Cc Stefano Babic <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Jaehoon Chung <[email protected]>
---
 drivers/mmc/fsl_esdhc.c | 26 +++++++++++++-------------
 include/fsl_esdhc.h     |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)
drivers/mmc/fsl_esdhc.c +2 -6
index cc188c4260..499d622c6d 100644
@@ -171,20 +171,20 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv,
        uint databuf;
        uint size;
        uint irqstat;
-       uint timeout;
+       ulong start;
 
        if (data->flags & MMC_DATA_READ) {
                blocks = data->blocks;
                buffer = data->dest;
                while (blocks) {
-                       timeout = PIO_TIMEOUT;
+                       start = get_timer(0);
                        size = data->blocksize;
                        irqstat = esdhc_read32(&regs->irqstat);
-                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
-                               && --timeout);
-                       if (timeout <= 0) {
-                               printf("\nData Read Failed in PIO Mode.");
Quoted 8 lines

drivers/mmc/fsl_esdhc.c static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv, · line 187

Quoted 6 lines
drivers/mmc/fsl_esdhc.c +5 -1
-                               return;
+                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)) {
+                               if (get_timer(start) > PIO_TIMEOUT) {
+                                       printf("\nData Read Failed in PIO Mode.");
+                                       return;
+                               }

How about using wait_for_bit here?

wait_for_bit() uses readl(), whereas here esdhc_read32() is used in order to take the IP vs. CPU endianness compatibility issues into account.

Best regards,
Benoît

#4 lore raw

PATCH 1/1 mmc: fsl_esdhc: Fix PIO timeout

Quoted 57 lines · Benoît Thébaudeau
Quoted 47 lines · Jagan Teki
Quoted 45 lines · Benoît Thébaudeau

The following error has been observed on i.MX25 with a high-speed SDSC card:
Data Write Failed in PIO Mode.

It was caused by the timeout set on PRSSTAT.BWEN, which was triggered because this bit takes 15 ms to be set after writing the first block to DATPORT with this card. Without this timeout, all the blocks are properly written.

This timeout was implemented by decrementing a variable, so it was depending on the CPU frequency. Fix this issue by setting this timeout to a long enough absolute duration (500 ms).

Cc Stefano Babic <[email protected]>
Cc Fabio Estevam <[email protected]>
Cc Jaehoon Chung <[email protected]>
---
 drivers/mmc/fsl_esdhc.c | 26 +++++++++++++-------------
 include/fsl_esdhc.h     |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)
drivers/mmc/fsl_esdhc.c +2 -6
index cc188c4260..499d622c6d 100644
@@ -171,20 +171,20 @@ static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv,
        uint databuf;
        uint size;
        uint irqstat;
-       uint timeout;
+       ulong start;
 
        if (data->flags & MMC_DATA_READ) {
                blocks = data->blocks;
                buffer = data->dest;
                while (blocks) {
-                       timeout = PIO_TIMEOUT;
+                       start = get_timer(0);
                        size = data->blocksize;
                        irqstat = esdhc_read32(&regs->irqstat);
-                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)
-                               && --timeout);
-                       if (timeout <= 0) {
-                               printf("\nData Read Failed in PIO Mode.");
Quoted 8 lines

drivers/mmc/fsl_esdhc.c static void esdhc_pio_read_write(struct fsl_esdhc_priv *priv, · line 187

Quoted 6 lines
drivers/mmc/fsl_esdhc.c +5 -1
-                               return;
+                       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_BREN)) {
+                               if (get_timer(start) > PIO_TIMEOUT) {
+                                       printf("\nData Read Failed in PIO Mode.");
+                                       return;
+                               }

How about using wait_for_bit here?

Quoted 3 lines

wait_for_bit() uses readl(), whereas here esdhc_read32() is used in order to take the IP vs. CPU endianness compatibility issues into account.

thanks!

Signature · 4 lines
Jagan Teki
Free Software Engineer | www.openedev.com
U-Boot, Linux | Upstream Maintainer
Hyderabad, India.