mtd/drivers/mtd/chips cfi_cmdset_0002.c,1.76,1.77

Thayne Harbaugh tharbaugh at lnxi.com
Wed Sep 17 18:18:00 EDT 2003


Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv6645/drivers/mtd/chips

Modified Files:
	cfi_cmdset_0002.c 
Log Message:
command sequences should attempt to be atomic - wrap with cli()/sti()
Some flash chips are sensitive to these sequences being interlaced
with other LPC activity - even activity that isn't addressed for
the flash device.  At times other LPC activity can cause an LPC
bus reset which may cause some flash devices to abort command
sequences.

Index: cfi_cmdset_0002.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0002.c,v
retrieving revision 1.76
retrieving revision 1.77
diff -u -r1.76 -r1.77
--- cfi_cmdset_0002.c	22 Jul 2003 13:23:38 -0000	1.76
+++ cfi_cmdset_0002.c	17 Sep 2003 22:17:57 -0000	1.77
@@ -588,6 +588,23 @@
 	       __func__, adr, datum );
 
 	ENABLE_VPP(map);
+	/*
+	 * This sequence needs to be atomic - or as near as can be (SMP may
+	 * have problems here).  If the sequence isn't atomic then some
+	 * other LPC access may occur which can cause some flash chips to
+	 * abort the operation.
+	 * What has been identified is that __SLOW_DOWN_IO from
+	 * include/asm-i386/io.h writes to port 0x80, nothing is at 0x80
+	 * and an LPC reset is generated.  When this traffic is during
+	 * a setup sequence for an erase or program then the SST49LF040
+	 * aborts the operation.  It's most likely that the SST49LF040
+	 * is sensitive to the LPC reset rather than the port 0x80 write.
+	 * It is unknown if other flash chips behave in the same manner.
+	 * It is known that some flash chips ignore the LPC traffic
+	 * that is destined for other devices - the Pm49FL004 is known
+	 * to ignore the extra traffic and LPC reset.
+	 */
+	cli();
 	if (fast) { /* Unlock bypass */
 		cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);
 	}
@@ -597,6 +614,7 @@
 	        cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	}
 	cfi_write(map, datum, adr);
+	sti();
 
 	cfi_spin_unlock(chip->mutex);
 	cfi_udelay(chip->word_write_time);
@@ -795,9 +813,12 @@
 	
 	if (cfi->fast_prog) {
 		/* Go into unlock bypass mode */
+		/* This sequence needs to be atomic */
+		cli();
 		cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
 		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
 		cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		sti();
 	}
 
 	/* We are now aligned, write as much as possible */
@@ -818,8 +839,11 @@
 		if (ret) {
 			if (cfi->fast_prog){
 				/* Get out of unlock bypass mode */
+				/* This sequence needs to be atomic */
+				cli();
 				cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
 				cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
+				sti();
 			}
 			return ret;
 		}
@@ -832,8 +856,11 @@
 		if (ofs >> cfi->chipshift) {
 			if (cfi->fast_prog){
 				/* Get out of unlock bypass mode */
+				/* This sequence needs to be atomic */
+				cli();
 				cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
 				cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
+				sti();
 			}
 
 			chipnum ++; 
@@ -843,17 +870,23 @@
 			chipstart = cfi->chips[chipnum].start;
 			if (cfi->fast_prog){
 				/* Go into unlock bypass mode for next set of chips */
+				/* This sequence needs to be atomic */
+				cli();
 				cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
 				cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
 				cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+				sti();
 			}
 		}
 	}
 
 	if (cfi->fast_prog){
 		/* Get out of unlock bypass mode */
+		/* This sequence needs to be atomic */
+		cli();
 		cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
 		cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
+		sti();
 	}
 
 	/* Write the trailing bytes if any */
@@ -925,12 +958,15 @@
 	 * the chip erase command.
 	 */
 	ENABLE_VPP(map);
+	/* This sequence needs to be atomic */
+	cli();
 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	sti();
 	timeo = jiffies + (HZ*20);
 	adr = cfi->addr_unlock1;
 
@@ -1104,6 +1140,8 @@
 	       __func__, adr );
 
 	ENABLE_VPP(map);
+	/* This sequence needs to be atomic */
+	cli();
 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
@@ -1111,6 +1149,7 @@
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 
 	cfi_write(map, CMD(0x30), adr);
+	sti();
 	
 	timeo = jiffies + (HZ*20);
 




More information about the linux-mtd-cvs mailing list