分类: LINUX
2009-07-26 12:10:11
Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv12948/drivers/mtd/chips
Modified Files:
cfi_cmdset_0002.c
Log Message:
Fixes erase-suspend on AMD command set chips:
- Erase suspend resume command must be written to the block to be resumed.
- When erasing DQ2 must a) be read from the erase in progress block
b) doesn't indicate that an erase has been suspended. DQ6 is the toggle
bit to check.
- Currently erase-suspend-program does work. It sometimes fails to erase
the block completely. So erase-suspend-program has been disabled for now.
Note that this severly reduces write performance when used with (for
example) JFFS2 but at least it works.
Index: cfi_cmdset_0002.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0002.c,v
retrieving revision 1.93
retrieving revision 1.94
diff -u -r1.93 -r1.94
--- cfi_cmdset_0002.c 20 Nov 2003 08:39:35 -0000 1.93
+++ cfi_cmdset_0002.c 27 Jan 2004 10:16:20 -0000 1.94
@@ -375,6 +375,9 @@
printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
cfi->fast_prog = 0;
}
+ /* FIXME: erase-suspend-program is broken. See
+ */
+ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
/* does this chip have a secsi area? */
@@ -499,27 +502,37 @@
return 0;
case FL_ERASING:
+ if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
+ goto sleep;
+
if (!(mode == FL_READY || mode == FL_POINT
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
goto sleep;
+ oldstatus = cfi_read(map, adr);
+ status = cfi_read(map, adr);
+ if ((oldstatus ^ status) & dq2) {
+ printk(KERN_ERR "Can't suspend erase -- block in progress\n");
+ goto sleep;
+ }
+
/* Erase suspend */
/* FIXME - is there a way to verify suspend? */
- cfi_write(map, CMD(0xB0), adr);
+ cfi_write(map, CMD(0xB0), chip->in_progress_block_addr);
chip->oldstate = FL_ERASING;
chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1;
for (;;) {
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- if (((oldstatus ^ status) & dq2) == dq2)
+ oldstatus = cfi_read(map, chip->in_progress_block_addr);
+ status = cfi_read(map, chip->in_progress_block_addr);
+ if (((oldstatus ^ status) & dq6) == 0)
break;
if (time_after(jiffies, timeo)) {
/* Urgh. Resume and pretend we weren't here. */
/* FIXME - is there a way to verify resume? */
- cfi_write(map, CMD(0x30), adr);
+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr);
chip->state = FL_ERASING;
chip->oldstate = FL_READY;
printk(KERN_ERR "Chip not ready after erase "
@@ -533,7 +546,7 @@
/* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
So we can just loop here. */
}
- chip->state = FL_STATUS;
+ chip->state = FL_READY;
return 0;
case FL_POINT:
@@ -561,7 +574,7 @@
switch(chip->oldstate) {
case FL_ERASING:
chip->state = chip->oldstate;
- cfi_write(map, CMD(0x30), adr);
+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr);
chip->oldstate = FL_READY;
chip->state = FL_ERASING;
break;
@@ -1506,7 +1519,8 @@
chip->state = FL_ERASING;
chip->erase_suspended = 0;
-
+ chip->in_progress_block_addr = adr;
+
cfi_spin_unlock(chip->mutex);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((chip->erase_time*HZ)/(2*1000));
@@ -1738,6 +1752,7 @@
chip->state = FL_ERASING;
chip->erase_suspended = 0;
+ chip->in_progress_block_addr = adr;
cfi_spin_unlock(chip->mutex);
set_current_state(TASK_UNINTERRUPTIBLE);