Fix for CFI Flash Driver bug in 2.4 Kernel
From: Matsen, Dean (WA26) <hidden>
Date: 2006-02-23 21:48:47
All, This patch applies to 2.4.22 from Monta Vista. We started seeing a kernel panic due to the really SLOOOOW 29LV641MH-120 flash parts. Interestingly, the same part with 90mS access time (29LV641MH-120) are about 10 times faster erasing and programming. Turns out there are two problems in the driver code: 1- the timeout is calculated incorrectly, based on HZ/100, which is zero on my system 'cuz "HZ" is equal to 100 2- when the timeout occurs, the code erroneously releases a spinlock twice. I have not checked to see if there is a similar problem in the 2.6 kernel Regards, Dean Matsen Software Architect Alerton Honeywell dean.matsen@honeywell.com Patch follows: ------------------------------------------------------------------------ ---------------------- diff --unified --recursive ppc-linux-kernel.org/drivers/mtd/chips/cfi_cmdset_0002.c ppc-linux-kernel/drivers/mtd/chips/cfi_cmdset_0002.c
--- ppc-linux-kernel.org/drivers/mtd/chips/cfi_cmdset_0002.c SatJul 12 01:08:17 2003
+++ ppc-linux-kernel/drivers/mtd/chips/cfi_cmdset_0002.c Thu Feb 2312:50:34 2006
@@ -10,6 +10,15 @@ * * $Id: cfi_cmdset_0002.c,v 1.1.1.1 2003/07/12 08:08:17 dean Exp $ * + * - 2006/02/23 : Dean Matsen (dean.matsen@honeywell.com) Fixed write + * timeout bug: timeout was based on HZ/1000 before (which is equal
to + * zero in my system), also the exit path unlocked the spinlock twice. + * Increased timeout from 1mS to 100mS, because new 100K write flashes + * such as 29LV641MH say "TBD" in the data sheet for worst case programming + * time. Problem was detected due to the really slow 29LV641MH-120 part, + * which erases and programs 10 times slower than any other flash we've + * ever encountered (including the 29LV641MH-90, which is in the same + * 100K write family of parts!). */ #include <linux/module.h>
@@ -511,7 +520,7 @@ or tells us why it failed. */ dq6 = CMD(1<<6); dq5 = CMD(1<<5); - timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */ + timeo = jiffies + (HZ/10); /* setting timeout to 100ms for now */ oldstatus = cfi_read(map, adr); status = cfi_read(map, adr);
@@ -532,10 +541,10 @@ } if( (status & dq6) != (oldstatus & dq6) ) { - /* The erasing didn't stop?? */ + /* The writing didn't stop?? */ if( (status & dq5) == dq5 ) { /* When DQ5 raises, we must check once again - if DQ6 is toggling. If not, the erase has been + if DQ6 is toggling. If not, the write has been completed OK. If not, reset chip. */ oldstatus = cfi_read(map, adr); status = cfi_read(map, adr);
@@ -543,7 +552,7 @@ if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) { printk(KERN_WARNING "Warning: DQ5 raised while
program operation was in progress, however operation completed OK\n" );
} else {
- /* DQ5 is active so we can do a reset and stop
the erase */
+ /* DQ5 is active so we can do a reset and stop
the write */
cfi_write(map, CMD(0xF0), chip->start);
printk(KERN_WARNING "Internal flash device
timeout occurred or write operation was performed while flash was
programming.\n" );
}
@@ -554,7 +563,7 @@ wake_up(&chip->wq); cfi_spin_unlock(chip->mutex); DISABLE_VPP(map); - ret = -EIO; + return -EIO; } } ------------------------------------------------------------------------ -----------------------------------