Subject: cfi_cmdset_0002.c: MTD do_write_oneword(): Wacky! Unable to decode failure status

From: Steffen Rumler <[email-masked]>
Date: Fri, 10 Oct 2003 13:57:15 +0200

Hi,

I'm using the 2.4.20 kernel running on a TQM8260 board,
with FUJITSU 29LV652UE90 flash chips.

Sometimes a have seen the following problem inside MTD's
do_write_oneword() and do_erase_oneblock() functions:

    + After starting the erase/write operation, the function
      waits until the flash chips have indicated the end of
      the operation (via dq6 or dq7).

    + After that, the function makes some kind of control read
      in order to check the correctness of the operation.

    + Sometimes this control read fails.

When I make the control read more lazy and try it multiple times (see attached patch),
the problem disappears. The contents of the flash is always correct.

As far as I know, the control read is not performed by the PPCboot.

Has anybody seen the same problem ?

Thanks

--

--------------------------------------------------------------

Steffen Rumler
ICN CP D NT SW 7
Siemens AG
Hofmannstr. 51                 Email: [email-masked]
D-81359 Munich                 Phone: +49 89 722-44061
Germany                        Fax  : +49 89 722-36703

--------------------------------------------------------------

diff -Naur old/cfi_cmdset_0002.c new/cfi_cmdset_0002.c
--- old/cfi_cmdset_0002.c	Fri Oct 10 13:46:22 2003
+++ new/cfi_cmdset_0002.c	Fri Oct 10 13:45:58 2003
@@ -472,6 +472,7 @@
 
 	cfi_word oldstatus, status, prev_oldstatus, prev_status;
 	cfi_word dq6;
+        int i;
 
     /* We use a 1ms + 1 jiffies generic timeout for writes (most devices have
        a max write time of a few hundreds usec). However, we should use the
@@ -618,17 +619,21 @@
 	 * bits aren't still changing  and that the status
 	 * bits erroneously match the datum that was written.
 	 */
-	prev_oldstatus = oldstatus;
-	prev_status = status;
-	oldstatus = cfi_read(map, adr);
-	status = cfi_read(map, adr);
-	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-	       __func__, oldstatus, status );
-
-	if ( oldstatus == datum && status == datum ) {
-		/* success - do nothing */
-		goto write_done;
-	}
+        for(i=0; i<10; i++){
+            
+            prev_oldstatus = oldstatus;
+            prev_status = status;
+            oldstatus = cfi_read(map, adr);
+            status = cfi_read(map, adr);
+            DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+                    __func__, oldstatus, status );
+
+            if ( oldstatus == datum && status == datum ) {
+                /* success - do nothing */
+                goto write_done;
+            }
+            udelay(1);
+        }
 
 	if ( ta ) {
 		cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
@@ -1125,7 +1130,6 @@
 	       __func__, status );
 
 	while( ((status & dq7) != dq7) && 
-	       ((status & dq5) != dq5) &&
 		!( ta = time_after(jiffies, timeo) )) {
 		int wait_reps;
 
@@ -1174,29 +1178,34 @@
 		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x\n",
 		       __func__, status );
 	}
-	prev_status     = status;
-	status          = cfi_read(map, adr);
 
-	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x\n",
-	       __func__, status );
+        for(i=0; i<10; i++){
 
-	if ( cfi_buswidth_is_1() ) {
-		ones =  (__u8)~0;
-	} else if ( cfi_buswidth_is_2() ) {
-		ones = (__u16)~0;
-	} else if ( cfi_buswidth_is_4() ) {
-		ones = (__u32)~0;
-	} else if ( cfi_buswidth_is_8() ) {
-		ones = (__u64)~0;
-	} else {
-		printk(KERN_WARNING "Unsupported buswidth %d\n",CFIDEV_BUSWIDTH);
-		goto erase_failed;
-	}
+            prev_status     = status;
+            status          = cfi_read(map, adr);
 
-	if ( prev_status == ones && status == ones ) {
-		/* success - do nothing */
-		goto erase_done;
-	}
+            DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x\n",
+                    __func__, status );
+
+            if ( cfi_buswidth_is_1() ) {
+                ones =  (__u8)~0;
+            } else if ( cfi_buswidth_is_2() ) {
+                ones = (__u16)~0;
+            } else if ( cfi_buswidth_is_4() ) {
+                ones = (__u32)~0;
+            } else if ( cfi_buswidth_is_8() ) {
+                ones = (__u64)~0;
+            } else {
+                printk(KERN_WARNING "Unsupported buswidth %d\n",CFIDEV_BUSWIDTH);
+                goto erase_failed;
+            }
+
+            if ( prev_status == ones && status == ones ) {
+                /* success - do nothing */
+                goto erase_done;
+            }
+            udelay(1);
+        }
 
 	if ( ta ) {
 		cfi_word dq5mask = ( ( status ^ prev_status ) & dq7 ) >> 2;