[PATCH] Bugfix: -ETIMEO errors in CFI driver

Alexey Korolev akorolev at infradead.org
Wed Jul 16 10:28:56 EDT 2008


Hi,

Existing CFI driver has problems with excessive writes during erase. 
If CFI driver does many writes during one erase cycle we may face the 
messages with -ETIMEO error on erase operation.  It may cause the
following data corruption and kernel panics.

The reason of the issue is related to specifics of suspend operation: 
if we write to flash during erase, suspend operation will cost some time 
to erase procedure (for P30 it could be significant). In current version of 
cfi driver the problem of many suspends is partially workarounded by adding 
some time reserv to any operation (8xerase_time) but if we have many writes 
during one erase the problem appears. 
 
This patch detects the suspend and resets timer if suspend occured. It
has been well verified on different chips. No problems were found.
Could you please include the patch as it is simple and fixes bad issue.

Signed-off-by: Alexey Korolev <akorolev at infradead.org> 
------------------
diff -aurp linux-2.6.25.4/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.6.25.4/drivers/mtd/chips/cfi_cmdset_0001.c
--- linux-2.6.25.4/drivers/mtd/chips/cfi_cmdset_0001.c	2008-05-15 19:00:12.000000000 +0400
+++ linux-2.6.25.4/drivers/mtd/chips/cfi_cmdset_0001.c	2008-07-16 18:06:27.000000000 +0400
@@ -1145,7 +1145,7 @@ static int inval_cache_and_wait_for_oper
 	struct cfi_private *cfi = map->fldrv_priv;
 	map_word status, status_OK = CMD(0x80);
 	int chip_state = chip->state;
-	unsigned int timeo, sleep_time;
+	unsigned int timeo, sleep_time, reset_timeo;
 
 	spin_unlock(chip->mutex);
 	if (inval_len)
@@ -1156,6 +1156,7 @@ static int inval_cache_and_wait_for_oper
 	timeo = chip_op_time * 8;
 	if (!timeo)
 		timeo = 500000;
+	reset_timeo = timeo;
 	sleep_time = chip_op_time / 2;
 
 	for (;;) {
@@ -1197,6 +1198,12 @@ static int inval_cache_and_wait_for_oper
 			remove_wait_queue(&chip->wq, &wait);
 			spin_lock(chip->mutex);
 		}
+		if (chip->erase_suspended || chip->write_suspended)  {
+			/* Suspend has occured while sleep: reset timeout */
+			timeo = reset_timeo;
+			chip->erase_suspended = 0;
+			chip->write_suspended = 0;
+		}
 	}
 
 	/* Done and happy. */

------------------
Thanks,
Alexey



More information about the linux-mtd mailing list