public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* cfi_cmd0001.c broken w.r.t Erase Suspend
@ 2006-11-12 16:28 Joakim Tjernlund
  2006-11-13 12:02 ` cfi_cmd0001.c broken w.r.t Erase Suspend solved, patch included Joakim Tjernlund
  0 siblings, 1 reply; 3+ messages in thread
From: Joakim Tjernlund @ 2006-11-12 16:28 UTC (permalink / raw)
  To: linux-mtd

[-- Attachment #1: Type: text/plain, Size: 1323 bytes --]

Hi List

I found some problems that I think is flash driver
related(cfi_cmd0001.c). Somehow the
flash is in Erase suspend when do_erase_oneblock has returned from
INVAL_CACHE_AND_WAIT
I have tried lots of "fixes" but the only one that works is to detect
the Suspend in do_erase_oneblock
and issue a new resume and go back to INVAL_CAHCE_AND_WAIT, see attached
patch.
I am uing Intel P30 flash and 2.6.19-rc3 on powerpc

How to reproduce:
apply patch to kernel

boot to userspace and do:
cp -a /bin /root/tt1
cp -a /bin /root/tt2
cp -a /bin /root/tt3
cp -a /bin /root/tt4
cp -a /bin /root/tt5

Fill up the rest JFFS2 FS to it is full using dd to create an huge file
until the FS is full.
make sure syslog and klogd is running and is logging to file on the
JFFS2 FS.

Now do
1)
rm -rf /root/tt5
cp -a /root/tt1 /root/tt5

wait a few secs to a minute, then go to 1)

a few other observations:

It is very hard to trigger a erase, seems like the gc daemon uses that
as its last resort. Why not
erase blocks as soon they are ready to be erased?

I have seen cp consume 100% CPU sevral times

Also noticed gc sleeping whil cp is running and making no progress.
had to kick gc with a kill -HUP <gc pid> to make it run to make room for
the cp.

The above observations makes me think there is a bug or two in JFFS2 as
well.

 Jocke

[-- Attachment #2: cfi_cmd0001.patch --]
[-- Type: text/x-patch, Size: 2370 bytes --]

diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 2fd5cef..6f2d2d9 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -751,6 +751,8 @@ static int get_chip(struct map_info *map
 		map_write(map, CMD(0x70), adr);
 		chip->oldstate = FL_ERASING;
 		chip->state = FL_ERASE_SUSPENDING;
+		if (chip->erase_suspended)
+		   printk("chip already suspended");
 		chip->erase_suspended = 1;
 		for (;;) {
 			status = map_read(map, adr);
@@ -775,6 +777,9 @@ static int get_chip(struct map_info *map
 			/* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
 			   So we can just loop here. */
 		}
+		if (chip->erase_suspended != 1)
+		   printk("SUSPEND: chip not suspended");
+
 		chip->state = FL_STATUS;
 		return 0;
 
@@ -854,10 +859,15 @@ static void put_chip(struct map_info *ma
 		   sending the 0x70 (Read Status) command to an erasing
 		   chip and expecting it to be ignored, that's what we
 		   do. */
+		if (chip->erase_suspended != 1)
+		   printk("RESUME: chip not suspended");
+		chip->erase_suspended = 0;
 		map_write(map, CMD(0xd0), adr);
 		map_write(map, CMD(0x70), adr);
 		chip->oldstate = FL_READY;
 		chip->state = FL_ERASING;
+		if (chip->erase_suspended)
+		   printk("RESUME: chip suspended");
 		break;
 
 	case FL_XIP_WHILE_ERASING:
@@ -1718,7 +1728,7 @@ static int __xipram do_erase_oneblock(st
 	map_write(map, CMD(0xD0), adr);
 	chip->state = FL_ERASING;
 	chip->erase_suspended = 0;
-
+ again:
 	ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
 				   adr, len,
 				   chip->erase_time);
@@ -1734,6 +1744,15 @@ static int __xipram do_erase_oneblock(st
 	map_write(map, CMD(0x70), adr);
 	chip->state = FL_STATUS;
 	status = map_read(map, adr);
+#if 1
+	if (map_word_bitsset(map, status, CMD(0x40))) {
+		printk("resume again:%lx\n", MERGESTATUS(status));
+		chip->state = FL_ERASING;
+		map_write(map, CMD(0x50), adr); /* reset status */
+		map_write(map, CMD(0xd0), adr); /* resume */
+		goto again;
+	}
+#endif
 
 	/* check for errors */
 	if (map_word_bitsset(map, status, CMD(0x3a))) {
@@ -1770,6 +1789,7 @@ static int __xipram do_erase_oneblock(st
 	xip_enable(map, chip, adr);
  out:	put_chip(map, chip, adr);
 	spin_unlock(chip->mutex);
+	printk("ERASE DONE: chip:%p adr:%x, status 0x%lx\n", chip, adr, MERGESTATUS(status));
 	return ret;
 }
 

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-11-16 15:06 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-12 16:28 cfi_cmd0001.c broken w.r.t Erase Suspend Joakim Tjernlund
2006-11-13 12:02 ` cfi_cmd0001.c broken w.r.t Erase Suspend solved, patch included Joakim Tjernlund
2006-11-16 14:46   ` Artem Bityutskiy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox