dslinux/linux-2.6.x/drivers/mmc scsd_c.c

amadeus dslinux_amadeus at user.in-berlin.de
Fri Jun 30 22:44:01 CEST 2006


Update of /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc
In directory antilope:/tmp/cvs-serv11544/linux-2.6.x/drivers/mmc

Modified Files:
	scsd_c.c 
Log Message:
Improved Version with Error Checking

Index: scsd_c.c
===================================================================
RCS file: /cvsroot/dslinux/dslinux/linux-2.6.x/drivers/mmc/scsd_c.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- scsd_c.c	27 Jun 2006 16:00:34 -0000	1.1
+++ scsd_c.c	30 Jun 2006 20:43:59 -0000	1.2
@@ -30,17 +30,25 @@
 #include <asm/scatterlist.h>
 #include <asm/sizes.h>
 
-#undef  READ_CRC	/* do CRC for data reads */
+#define  READ_CRC	/* do CRC for data reads */
+#undef   HALT_ON_ERROR	/* stop after error, so we can see what's happened */
 
 #ifdef CONFIG_MMC_DEBUG
 #define READ_CRC
+#define HALT_ON_ERROR
 #define DBG(x...)	printk(x)
 #else
 #define DBG(x...)	do { } while (0)
 #endif
 
+#ifdef HALT_ON_ERROR
+#define halt() do { } while (1)
+#else
+#define halt() do { } while (0)
+#endif
+
 #define DRIVER_NAME	"scsd"
-#define DRIVER_VERSION	"1.0.0"
+#define DRIVER_VERSION	"1.0.1"
 
 /*****************************************************************************/
 /* IO registers */
@@ -149,6 +157,37 @@
 	return res;
 }
 
+/* Wait until ready on the data lines */
+/* return 0 if ready, 1 if busy */
+static int scsd_waitready(void)
+{
+	u32 ioadr = SC_SD_DATAREAD;
+	u32 tries = 2000000; /* app. 1000 ms */
+	u32 count = 0;
+
+	/* skip max. 2 Z-bits */
+	readl(ioadr);
+
+	do {
+		if (readw(ioadr) & 0x0100) {
+			/* data line is high */
+			count++;
+			if (count > 8) {
+				/* minimum 8 bit not busy */
+				return 0;
+			}
+		} else {				
+			/* data line is low */
+			count = 0;
+			tries--;
+			if (!tries) {
+				/* busy for a very long time */
+				return 1;
+			}
+		}		
+	} while (1);
+}
+
 /* send a SD command */
 /* @return 0 for success, != 0 otherwise */
 static int scsd_send_cmd(struct mmc_command *cmd)
@@ -173,9 +212,9 @@
 	i = 500000; /* app. 250 ms */
 	while (!(readw(ioadr) & 0x0001) && i) i--;
 	if (!i) {
-		/* Timeout error */
-		DBG("Timeout waiting for non-busy\n");
+		printk( KERN_ERR "CMD:timeout after command\n");
 		cmd->error = MMC_ERR_TIMEOUT;
+		halt();
 		return -1;
 	}
 
@@ -215,7 +254,7 @@
 		while ((readw(ioadr) & 0x0001) && i) i--;
 		if (!i) {
 			/* Timeout error */
-			DBG("Timeout after Command\n");
+			printk(KERN_ERR "Timeout after Command\n");
 			cmd->error = MMC_ERR_TIMEOUT;
 			return -1;
 		}
@@ -248,21 +287,21 @@
 		DBG("Got native response %X %X %X %X\n", cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
 		break;
 	default:
-		DBG("Invalid flags code from mmc layer: %d\n", cmd->flags);
+		printk(KERN_ERR "Invalid flags code from mmc layer: %d\n", cmd->flags);
 		cmd->error = MMC_ERR_INVALID;
+		halt();
 		return -1;
 	}
 
 	/* Busy command? (== STOP) */
 	if (cmd->flags & MMC_RSP_BUSY) {
-		ioadr = SC_SD_DATAREAD;
 
-		i = 500000; /* app. 250 ms */
-		while (!(readw(ioadr) & 0x0100) && i) i--;
-		if (!i) {
+		/* Wait until ready on the data lines */
+		if (scsd_waitready()) {
 			/* Timeout error */
-			DBG("Timeout waiting for not busy\n");
+			printk(KERN_ERR "Busy: timeout waiting for not busy\n");
 			cmd->error = MMC_ERR_TIMEOUT;
+			halt();
 			return -1;
 		}
 	}
@@ -320,8 +359,9 @@
 				while ((readw(ioadr) & 0x0100) && i) i--;
 				if (!i) {
 					/* Timeout error */
-					DBG("Timeout waiting for read data\n");
+					printk(KERN_ERR "Read: timeout waiting for read data\n");
 					data->error = MMC_ERR_TIMEOUT;
+					halt();
 					return;
 				}
 		
@@ -342,28 +382,25 @@
 #ifdef READ_CRC
 				for (i = 0; i < 4; i++) {
 					if (crc16[i] != crcread[i]) {
-						printk (KERN_ERR "scsd: CRC read different Block\n");
+						printk (KERN_ERR "Read: CRC read different\n");
 						data->error = MMC_ERR_BADCRC;
+						halt();
 						return;
 					}
 				} 
 #endif
 			} else if (data->flags & MMC_DATA_WRITE) {
 
-				ioadr = SC_SD_DATAWRITE;
-
-				/* wait until not busy */
-				i = 500000; /* app. 250 ms */
-				while (!(readw(ioadr) & 0x0100) && i) i--;
-				if (!i) {
+				/* Wait until ready on the data lines */
+				if (scsd_waitready()) {
 					/* Timeout error */
-					DBG("Timeout waiting for not busy\n");
+					printk(KERN_ERR "before Write: timeout waiting for ready\n");
 					data->error = MMC_ERR_TIMEOUT;
+					halt();
 					return;
 				}
-				/* skip one Z bit */
-				readw(ioadr);
-		
+				ioadr = SC_SD_DATAWRITE;
+
 				/* calculate the crc */
 				sd_crc16_s(p, length, crc16);
 
@@ -388,12 +425,13 @@
 				while ((readw(ioadr) & 0x0100) && i) i--;
 				if (!i) {
 					/* Timeout error */
-					DBG("Timeout waiting for CRC response\n");
+					printk(KERN_ERR "Timeout waiting for CRC response\n");
 					data->error = MMC_ERR_TIMEOUT;
+					halt();
 					return;
 				}
 
-				/* read CRC response (3 bit)*/
+				/* read CRC response (3 bit) + end bit */
 				readl(ioadr);
 				tmp = readl(ioadr);
 				tmp >>= 16;
@@ -401,20 +439,22 @@
 				i = 0;
 				if (tmp & 0x1000) i |= 0x04;
 				if (tmp & 0x0100) i |= 0x02;
-				if (tmp & 0x0010) i |= 0x01;
+ 				if (tmp & 0x0010) i |= 0x01;
 				DBG("CRC Response = %d\n", i);
-				if (i != 2) {
+				/* found that SD cards give response codes 2 AND 3, without error */
+				if ((i != 2) && (i != 3)) {
+					printk(KERN_ERR "Write: CRC bad code= %d tmp= %X\n", i, tmp);
 					data->error = MMC_ERR_BADCRC;
+					halt();
 					return;				
 				}					
 			
-				/* wait until ready */
-				i = 500000; /* app. 250 ms */
-				while (!(readw(ioadr) & 0x0100) && i) i--;
-				if (!i) {
+				/* Wait until ready on the data lines */
+				if (scsd_waitready()) {
 					/* Timeout error */
-					DBG("Timeout waiting for ready\n");
+					printk(KERN_ERR "Write: timeout waiting for ready\n");
 					data->error = MMC_ERR_TIMEOUT;
+					halt();
 					return;
 				}
 
@@ -441,6 +481,7 @@
 
 	u32 ioadr = SC_SD_CMD;
 	int ret;
+	int retry = 1;
 
     	DBG("%s Opcode %d, arg %d\n",__FUNCTION__, mrq->cmd->opcode, mrq->cmd->arg);
 
@@ -451,6 +492,13 @@
 	}
 
 	switch (mrq->cmd->opcode){
+	/* do a retry for data I/O */
+	case MMC_READ_SINGLE_BLOCK:
+	case MMC_READ_MULTIPLE_BLOCK:
+	case MMC_WRITE_BLOCK:
+	case MMC_WRITE_MULTIPLE_BLOCK:
+		retry = 3;
+		break;
 	/* check if we have an inactivation command */
 	case SD_APP_OP_COND:
 	case MMC_GO_INACTIVE_STATE:
@@ -468,20 +516,31 @@
 		break;
 	}
 
-    	/* Send the command to the card */
-	ret = scsd_send_cmd(mrq->cmd);
-	if (!ret) {
+	while (retry--) {
+		/* Send the command to the card */
+		mrq->cmd->error = MMC_ERR_NONE;
+		ret = scsd_send_cmd(mrq->cmd);
+		if (ret) 
+			continue;
+
 		/* check if we have an activation */
 		if (mrq->cmd->opcode == MMC_SET_RELATIVE_ADDR)
 			host->inactive = 0;
 
 		if ( mrq->data ) {
+			mrq->data->error = MMC_ERR_NONE;
 			scsd_xfer( mrq->data );
 			if (mrq->stop) {
-				scsd_send_cmd(mrq->stop);
+				mrq->stop->error = MMC_ERR_NONE;
+				ret = scsd_send_cmd(mrq->stop);
+				if (ret)
+					continue;
 			}
+			if (mrq->data->error != MMC_ERR_NONE)
+				continue;
 		}
-    	}
+		break;
+	}
 
 	/* minimum 8 bits after last command */
 	ret=4; while (ret--) readl(ioadr);




More information about the dslinux-commit mailing list