mtd/drivers/mtd/chips Config.in,1.17,1.18
cfi_cmdset_0002.c,1.94,1.95
dvrabel at infradead.org
dvrabel at infradead.org
Tue Feb 17 10:42:15 EST 2004
Update of /home/cvs/mtd/drivers/mtd/chips
In directory phoenix.infradead.org:/tmp/cvs-serv29302
Modified Files:
Config.in cfi_cmdset_0002.c
Log Message:
Clean up of the CFI command set 0002 (AMD/Fujitsu) drivers.
- All the chip status checking has be refactored into the single function
chip_status(..).
- The horrible hack for retrying erases and programs for the very broken
non-compliant SST chips has been removed.
Index: Config.in
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/Config.in,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- Config.in 25 Sep 2003 14:40:34 -0000 1.17
+++ Config.in 17 Feb 2004 15:42:12 -0000 1.18
@@ -43,13 +43,6 @@
fi
dep_tristate ' Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE
dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE
-if [ "$CONFIG_MTD_CFI_AMDSTD" = "y" -o "$CONFIG_MTD_CFI_AMDSTD" = "m" ]; then
- bool ' Retry failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY n
- if [ "$CONFIG_MTD_CFI_AMDSTD_RETRY" = "y" ]; then
- int ' Max retries of failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0
- fi
-fi
-
dep_tristate ' Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE
if [ "$CONFIG_MTD_CFI_INTELEXT" = "y" \
Index: cfi_cmdset_0002.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/chips/cfi_cmdset_0002.c,v
retrieving revision 1.94
retrieving revision 1.95
diff -u -r1.94 -r1.95
--- cfi_cmdset_0002.c 27 Jan 2004 10:16:20 -0000 1.94
+++ cfi_cmdset_0002.c 17 Feb 2004 15:42:12 -0000 1.95
@@ -3,6 +3,7 @@
* AMD & Fujitsu Standard Vendor Command Set (ID 0x0002)
*
* Copyright (C) 2000 Crossnet Co. <info at crossnet.co.jp>
+ * Copyright (C) 2004 Arcom Control Systems Ltd <linux at arcom.com>
*
* 2_by_8 routines added by Simon Munton
*
@@ -37,33 +38,13 @@
#define AMD_BOOTLOC_BUG
#define FORCE_WORD_WRITE 0
-
-/*
- * This is an attempt to coalesce the retry logic in one place - that way
- * there aren't #ifdefs scattered throughout.
- */
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-
-#ifndef CONFIG_MTD_CFI_AMDSTD_RETRY_MAX
-#define CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0
-#endif
-
-#define RETRY_CMD_LABEL retry_cmd: do {} while (0)
-#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, retry_cmd_cnt, adr, datum, prev_oldstatus, prev_status, oldstatus, status)
-static int retry_cmd_max = CONFIG_MTD_CFI_AMDSTD_RETRY_MAX;
-#define DECLARE_RETRY_CMD_CNT() int retry_cmd_cnt = 0
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-#define CHECK_RETRIES() do { if (++retry_cmd_cnt <= retry_cmd_max) goto retry_cmd; } while (0)
-#endif
-
-#else
-
-#define RETRY_CMD_LABEL do {} while (0)
-#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, adr, datum, prev_oldstatus, prev_status, oldstatus, status)
-#define DECLARE_RETRY_CMD_CNT()
-#define CHECK_RETRIES()
-
-#endif /* !defined(CONFIG_MTD_CFI_AMDSTD_RETRY) */
+/* The status (from the various toggle/status bits) of a chip as returned by
+ * chip_status(..). */
+#define CHIP_READY 0
+#define CHIP_BUSY 1
+#define CHIP_TIMEDOUT 2
+#define CHIP_ERASE_SUSP 3
+#define CHIP_ERROR 4
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
@@ -159,9 +140,9 @@
/* CFI version 1.0 => don't trust bootloc */
if (cfi->id & 0x80) {
printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
- extp->TopBottom = 3; /* top boot */
+ extp->TopBottom = 3; /* top boot */
} else {
- extp->TopBottom = 2; /* bottom boot */
+ extp->TopBottom = 2; /* bottom boot */
}
}
}
@@ -362,7 +343,7 @@
break;
default:
- printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
__func__, CFIDEV_BUSWIDTH);
goto setup_err;
break;
@@ -375,12 +356,12 @@
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
- http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
- printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
+ /* FIXME: erase-suspend-program is broken. See
+ http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
+ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
- /* does this chip have a secsi area? */
+ /* does this chip have a secsi area? */
if(cfi->mfr==1){
switch(cfi->id){
@@ -420,54 +401,68 @@
}
-/* This is more work to coalesce the retry #ifdefs in one location */
-static inline void handle_wacky_state(const char *func,
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
- int retry_cmd_cnt,
-#endif
- unsigned long adr,
- cfi_word datum,
- cfi_word prev_oldstatus,
- cfi_word prev_status,
- cfi_word oldstatus,
- cfi_word status)
+/*
+ * Get the status of the chip using the various toggle bits.
+ *
+ * Conditions checked for are:
+ * CHIP_READY: no bits are toggling -- Read or Erase-Suspend-Read (in non erasing sector) mode.
+ * CHIP_ERASE_SUSP: only DQ2 is toggling -- Erase-Suspend-Read (in erasing sector) mode.
+ * CHIP_BUSY: DQ6 toggling and DQ5 == 0 -- programming or erasing.
+ * CHIP_TIMEDOUT: DQ6 toggling and DQ5 == 1 -- program or erase timed out.
+ * CHIP_ERROR: Any other condition (shouldn't happen).
+ *
+ * For interleaved chips we return:
+ * CHIP_READY if all chips are in Read or Erase-Suspend-Read (non-erasing sector).
+ * CHIP_ERASE_SUSP if all chips are in Erase-Suspend-Read (any sector) or Read.
+ * CHIP_BUSY if any chip is busy and no DQ5 bits are set.
+ * CHIP_TIMEDOUT if any chip is busy and has its DQ5 bit set.
+ *
+ * The retries when checking DQ5 are required due to the asynchronous nature
+ * of the internal state machine. Refer to the chip datasheets for details.
+ *
+ * The other retries are because it is possible for bits to appear to toggle
+ * when in fact what's happened is that the chip has switched from providing
+ * status to providing data.
+ */
+static int chip_status(struct map_info *map, unsigned long addr)
{
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
- if ( retry_cmd_cnt == retry_cmd_max ) {
-#endif
- printk(KERN_WARNING
- "MTD %s(): Wacky! Unable to decode failure status\n"
- "Possible buggy device - try "
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
- "increasing retry_cmd_max from %d\n"
-#else
- "enabling CONFIG_MTD_CFI_AMDSTD_RETRY\n"
- "in your kernel config and setting driver retry_cmd_max\n"
-#endif
- , func
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
- , retry_cmd_max
-#endif
- );
+ struct cfi_private *cfi = map->fldrv_priv;
+ cfi_word dq6 = CMD(1<<6);
+ cfi_word dq5 = CMD(1<<5);
+ cfi_word dq2 = CMD(1<<2);
- printk(KERN_WARNING
- "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
- func, adr, datum,
- prev_oldstatus, prev_status,
- oldstatus, status);
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
- }
-#endif
-}
+ cfi_word d, t;
+ int retry = 1;
+ do {
+ d = cfi_read(map, addr);
+ t = d ^ cfi_read(map, addr);
+
+ if (t == 0) /* no toggles -- Read or Erase-Suspend-Read mode */
+ return CHIP_READY;
+ if (!(t & ~dq2) && (t & dq2)) { /* only DQ2 toggling -- this sector is erase suspended */
+ if (retry)
+ continue; /* program/erase may just have finished */
+ return CHIP_ERASE_SUSP;
+ }
+ if (t & dq6) { /* programming or erasing */
+ if (d & dq5) { /* internal timeout */
+ if (retry)
+ continue;
+ return CHIP_TIMEDOUT;
+ }
+ return CHIP_BUSY;
+ }
+ /* some other bits toggled -- probably a program/erase just finished */
+ } while(retry--);
+
+ return CHIP_ERROR;
+}
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
DECLARE_WAITQUEUE(wait, current);
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word status, oldstatus;
- cfi_word dq6 = CMD(1<<6);
- cfi_word dq2 = CMD(1<<2);
unsigned long timeo;
struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
@@ -478,14 +473,11 @@
case FL_STATUS:
for (;;) {
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- if (((oldstatus ^ status) & (dq6 | dq2)) == 0)
+ if (chip_status(map, adr) == CHIP_READY)
break;
if (time_after(jiffies, timeo)) {
- printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n",
- (long long)status);
+ printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
cfi_spin_unlock(chip->mutex);
return -EIO;
}
@@ -502,44 +494,42 @@
return 0;
case FL_ERASING:
- if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
- goto sleep;
+ 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;
- }
+ /* We could check to see if we're trying to access the sector
+ * that is currently being erased. However, no user will try
+ * anything like that so we just wait for the timeout. */
/* Erase suspend */
- /* FIXME - is there a way to verify suspend? */
+ /* It's harmless to issue the Erase-Suspend and Erase-Resume
+ * commands when the erase algorithm isn't in progress. */
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, chip->in_progress_block_addr);
- status = cfi_read(map, chip->in_progress_block_addr);
- if (((oldstatus ^ status) & dq6) == 0)
- break;
+ if (chip_status(map, adr) == CHIP_READY)
+ break;
if (time_after(jiffies, timeo)) {
- /* Urgh. Resume and pretend we weren't here. */
- /* FIXME - is there a way to verify resume? */
+ /* Should have suspended the erase by now.
+ * Send an Erase-Resume command as either
+ * there was an error (so leave the erase
+ * routine to recover from it) or we trying to
+ * use the erase-in-progress sector. */
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 "
- "suspended: status = 0x%x\n", status);
+ printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
return -EIO;
}
-
+
cfi_spin_unlock(chip->mutex);
cfi_udelay(1);
cfi_spin_lock(chip->mutex);
@@ -676,11 +666,11 @@
if (chip->state != FL_READY){
#if 0
- printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
+ printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
#endif
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
-
+
cfi_spin_unlock(chip->mutex);
schedule();
@@ -765,21 +755,19 @@
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ;
- cfi_word oldstatus, status, prev_oldstatus, prev_status;
- cfi_word dq6 = CMD(1<<6);
/*
* We use a 1ms + 1 jiffies generic timeout for writes (most devices
* have a max write time of a few hundreds usec). However, we should
* use the maximum timeout value given by the chip at probe time
* instead. Unfortunately, struct flchip does have a field for
* maximum timeout, only for typical which can be far too short
- * depending of the conditions. The ' + 1' is to avoid having a
+ * depending of the conditions. The ' + 1' is to avoid having a
* timeout of 0 jiffies if HZ is smaller than 1000.
*/
unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
int ret = 0;
int ta = 0;
- DECLARE_RETRY_CMD_CNT();
+ int status;
adr += chip->start;
@@ -790,7 +778,6 @@
return ret;
}
- RETRY_CMD_LABEL;
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",
__func__, adr, datum );
@@ -800,10 +787,9 @@
* data at other locations when 0xff is written to a location that
* already contains 0xff.
*/
- status = cfi_read(map, adr);
- if (status == datum) {
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP 0x%.8x == 0x%.8x\n",
- __func__, status, datum );
+ if (cfi_read(map, adr) == datum) {
+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n"
+ __func__);
goto op_done;
}
@@ -830,37 +816,6 @@
cfi_udelay(chip->word_write_time);
cfi_spin_lock(chip->mutex);
- /*
- * Polling toggle bits instead of reading back many times This ensures
- * that write operation is really completed, or tells us why it
- * failed.
- *
- * It may appear that the polling and decoding of error state might be
- * simplified. Don't do it unless you really know what you are doing.
- *
- * You must remember that JESD21-C 3.5.3 states that the status must
- * be read back an _additional_ two times before a failure is
- * determined. This is because these devices have internal state
- * machines that are asynchronous to the external data bus. During an
- * erase or write the read-back status of the polling bits might be
- * transitioning internaly when the external read-back occurs. This
- * means that the bits aren't in the final state and they might appear
- * to report an error as they are in a transient state: dq7 is
- * asynchronous with dq6 and other status bits.
- *
- * This asynchronous behaviour can cause infrequent errors that will
- * usually disappear the next time an erase or write happens (Try
- * tracking those errors down!). To ensure that the bits are not in
- * transition, the location must be read-back two more times and
- * compared against what was written - BOTH reads MUST match what was
- * written. Don't think this can be simplified to only the last read
- * matching the datum written: status bits *can* match the datum
- * written.
- *
- * If the final comparison fails, error state can *then* be decoded.
- *
- * - Thayne Harbaugh
- */
/* See comment above for timeout value. */
timeo = jiffies + uWriteTimeout;
for (;;) {
@@ -878,32 +833,7 @@
continue;
}
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- /*
- * This only checks if dq6 is still toggling and that our
- * timer hasn't expired. We purposefully ignore the chip's
- * internal timer that will assert dq5 and leave dq6 toggling.
- * This is done for a variety of reasons:
- *
- * 1) Not all chips support dq5.
- *
- * 2) Dealing with asynchronous status bit and data updates
- * and reading a device two more times creates _messy_ logic
- * when trying to deal with interleaved devices - some may be
- * changing while others are still busy.
- *
- * 3) Checking dq5 only helps to optimize an error case that
- * should at worst be infrequent and at best non-existent.
- *
- * If our timeout occurs _then_ we will check dq5 to see if
- * the device also had an internal timeout.
- */
- if ( (((status ^ oldstatus) & dq6) == 0)
- || ( ta = time_after(jiffies, timeo)) )
+ if ((status = chip_status(map, adr)) != CHIP_BUSY)
break;
/* Latency issues. Drop the lock, wait a while and retry */
@@ -912,69 +842,23 @@
cfi_spin_lock(chip->mutex);
}
- /*
- * Something kicked us out of the read-back loop. We'll check success
- * befor checking failure. Even though dq6 might be true data, it is
- * unkown if all of the other bits have changed to true data due to
- * the asynchronous nature of the internal state machine. We will
- * read two more times and use this to either verify that the write
- * completed successfully or that something really went wrong. BOTH
- * reads must match what was written - this certifies that bits aren't
- * still changing and that the status bits erroneously match the datum
- * that was written.
- */
- prev_oldstatus = oldstatus;
- prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- if ( oldstatus == datum && status == datum ) {
- /* success - do nothing */
+ if (status == CHIP_READY)
goto op_done;
- }
- if ( ta ) {
- /* Only check dq5 on the chips that are still toggling. */
- cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
- if ( status & dq5mask ) {
- /* dq5 asserted - decode interleave chips */
- printk( KERN_WARNING
- "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n",
- __func__,
- status & dq5mask, status, datum );
- } else {
- printk( KERN_WARNING
- "MTD %s(): Software timed out during write.\n",
- __func__ );
- }
- goto op_failed;
- }
-
- /*
- * If we get to here then it means that something
- * is wrong and it's not a timeout. Something
- * is seriously wacky! Dump some debug info.
- */
- /*
- * Found a clue about the chips that reach this state.
- * Some flash chips (SST >cough<)
- * are horribly broken. They do not ignore traffic that is
- * destined to other devices. This happens because some solutions
- * are on shared busses, the erase and program sequences have
- * have multiple commands, and the sequence is interspersed with
- * commands destined to other devices. A good flash chip will
- * examine the command and destination address and will ignore
- * commands that are for other devices.
- */
- HANDLE_WACKY_STATE();
+ if (status == CHIP_TIMEDOUT)
+ printk(KERN_WARNING "MTD %s(): flash internal timeout\n",
+ __func__);
+ else if (ta)
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
+ else
+ printk(KERN_WARNING "MTD %s(): unexpected failure. status = %d\n",
+ __func__, status);
op_failed:
/* reset on all failures. */
cfi_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
- CHECK_RETRIES();
ret = -EIO;
op_done:
@@ -1039,8 +923,8 @@
while (len && i < CFIDEV_BUSWIDTH) {
tmp_buf[i++] = buf[n++];
- len--;
- }
+ len--;
+ }
/* already know that buswidth > 1 */
if (cfi_buswidth_is_2()) {
@@ -1211,8 +1095,6 @@
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ;
- cfi_word oldstatus, status, prev_oldstatus, prev_status;
- cfi_word dq6 = CMD(1<<6);
/* see comments in do_write_oneword() regarding uWriteTimeo. */
static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
int ret = -EIO;
@@ -1220,7 +1102,7 @@
unsigned long cmd_adr;
int z, bytes, words;
cfi_word datum;
- DECLARE_RETRY_CMD_CNT();
+ int status;
adr += chip->start;
cmd_adr = adr;
@@ -1248,8 +1130,7 @@
return -EINVAL;
}
- RETRY_CMD_LABEL;
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",
+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",
__func__, adr, datum );
ENABLE_VPP(map);
@@ -1347,14 +1228,8 @@
continue;
}
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- /* See comments in do_write_oneword() about checking status */
- if ( (((status ^ oldstatus) & dq6) == 0)
- || ( ta = time_after(jiffies, timeo)) ) {
+ if( (status = chip_status(map, adr)) != CHIP_BUSY
+ || ( ta = time_after(jiffies, timeo)) ) {
break;
}
@@ -1364,43 +1239,25 @@
cfi_spin_lock(chip->mutex);
}
- /* See comments in do_write_oneword() about "two more checks" */
- prev_oldstatus = oldstatus;
- prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
- if ( oldstatus == datum && status == datum ) {
- /* success - do nothing */
+ if (status == CHIP_READY)
goto op_done;
- }
- if ( ta ) {
- /* Only check dq5 on the chips that are still toggling. */
- cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
- if ( status & dq5mask ) {
- /* dq5 asserted - decode interleave chips */
- printk( KERN_WARNING
- "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n",
- __func__,
- status & dq5mask, status, datum );
- } else {
- printk( KERN_WARNING
- "MTD %s(): Software timed out during write.\n",
- __func__ );
- }
- goto op_failed;
- }
-
- HANDLE_WACKY_STATE();
+ if (status == CHIP_TIMEDOUT) {
+ printk(KERN_WARNING "MTD %s(): flash internal timeout\n",
+ __func__);
+ }
+ else if (ta)
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
+ else
+ printk(KERN_WARNING "MTD %s(): unexpected failure. status = %d\n",
+ __func__, status);
op_failed:
/* reset on all failures. */
cfi_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
- CHECK_RETRIES();
ret = -EIO;
op_done:
@@ -1486,15 +1343,12 @@
static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
{
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word oldstatus, status, prev_oldstatus, prev_status;
- cfi_word dq6 = CMD(1<<6);
unsigned long timeo = jiffies + HZ;
unsigned long int adr;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
int ta = 0;
- cfi_word datum = 0;
- DECLARE_RETRY_CMD_CNT();
+ int status;
adr = cfi->addr_unlock1;
@@ -1505,7 +1359,6 @@
return ret;
}
- RETRY_CMD_LABEL;
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
__func__, chip->start );
@@ -1546,12 +1399,8 @@
chip->erase_suspended = 0;
}
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
- if ( (((status ^ oldstatus) & dq6) == 0)
- || ( ta = time_after(jiffies, timeo)) )
+ if ((status = chip_status(map, adr)) != CHIP_BUSY
+ || ( ta = time_after(jiffies, timeo)) )
break;
/* Latency issues. Drop the lock, wait a while and retry */
@@ -1561,58 +1410,23 @@
cfi_spin_lock(chip->mutex);
}
- prev_oldstatus = oldstatus;
- prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- if ( cfi_buswidth_is_1() ) {
- datum = (__u8)~0;
- } else if ( cfi_buswidth_is_2() ) {
- datum = (__u16)~0;
- } else if ( cfi_buswidth_is_4() ) {
- datum = (__u32)~0;
-#ifdef CFI_WORD_64
- } else if ( cfi_buswidth_is_8() ) {
- datum = (__u64)~0;
-#endif
- } else {
- printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
- __func__, CFIDEV_BUSWIDTH);
- goto op_failed;
- }
-
- if ( oldstatus == datum && status == datum ) {
- /* success - do nothing */
+ if (status == CHIP_READY)
goto op_done;
- }
- if ( ta ) {
- /* Only check dq5 on the chips that are still toggling. */
- cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
- if ( status & dq5mask ) {
- /* dq5 asserted - decode interleave chips */
- printk( KERN_WARNING
- "MTD %s(): FLASH internal timeout: 0x%.8x\n",
- __func__,
- status & dq5mask );
- } else {
- printk( KERN_WARNING
- "MTD %s(): Software timed out during write.\n",
- __func__ );
- }
- goto op_failed;
- }
-
- HANDLE_WACKY_STATE();
+ if (status == CHIP_TIMEDOUT)
+ printk(KERN_WARNING "MTD %s(): flash internal timeout\n",
+ __func__);
+ else if (ta)
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
+ else
+ printk(KERN_WARNING "MTD %s(): unexpected failure. status = %d\n",
+ __func__, status);
op_failed:
/* reset on all failures. */
cfi_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
- CHECK_RETRIES();
ret = -EIO;
op_done:
@@ -1720,14 +1534,11 @@
static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
- cfi_word oldstatus, status, prev_oldstatus, prev_status;
- cfi_word dq6 = CMD(1<<6);
unsigned long timeo = jiffies + HZ;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
int ta = 0;
- cfi_word datum = 0;
- DECLARE_RETRY_CMD_CNT();
+ int status;
adr += chip->start;
@@ -1738,7 +1549,6 @@
return ret;
}
- RETRY_CMD_LABEL;
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
__func__, adr );
@@ -1761,17 +1571,6 @@
timeo = jiffies + (HZ*20);
- /* Wait for the end of programing/erasure by using the toggle method.
- * As long as there is a programming procedure going on, bit 6 is
- * toggling its state with each consecutive read. The toggling stops
- * as soon as the procedure is completed.
- *
- * If the process has gone on for too long on the chip, bit 5 gets
- * set. After bit5 is set you can kill the operation by sending a
- * reset command to the chip.
- */
- /* See comments in do_write_oneword(). */
-
for (;;) {
if (chip->state != FL_ERASING) {
/* Someone's suspended the erase. Sleep */
@@ -1790,12 +1589,8 @@
chip->erase_suspended = 0;
}
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
- if ( (((status ^ oldstatus) & dq6) == 0)
- || ( ta = time_after(jiffies, timeo)) )
+ if ((status = chip_status(map, adr)) != CHIP_BUSY
+ || ( ta = time_after(jiffies, timeo)) )
break;
/* Latency issues. Drop the lock, wait a while and retry */
@@ -1805,58 +1600,23 @@
cfi_spin_lock(chip->mutex);
}
- prev_oldstatus = oldstatus;
- prev_status = status;
- oldstatus = cfi_read(map, adr);
- status = cfi_read(map, adr);
- DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
- __func__, oldstatus, status );
-
- if ( cfi_buswidth_is_1() ) {
- datum = (__u8)~0;
- } else if ( cfi_buswidth_is_2() ) {
- datum = (__u16)~0;
- } else if ( cfi_buswidth_is_4() ) {
- datum = (__u32)~0;
-#ifdef CFI_WORD_64
- } else if ( cfi_buswidth_is_8() ) {
- datum = (__u64)~0;
-#endif
- } else {
- printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n",
- __func__, CFIDEV_BUSWIDTH);
- goto op_failed;
- }
-
- if ( oldstatus == datum && status == datum ) {
- /* success - do nothing */
+ if (status == CHIP_READY)
goto op_done;
- }
-
- if ( ta ) {
- /* Only check dq5 on the chips that are still toggling. */
- cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
- if ( status & dq5mask ) {
- /* dq5 asserted - decode interleave chips */
- printk( KERN_WARNING
- "MTD %s(): FLASH internal timeout: 0x%.8x\n",
- __func__,
- status & dq5mask );
- } else {
- printk( KERN_WARNING
- "MTD %s(): Software timed out during write.\n",
- __func__ );
- }
- goto op_failed;
- }
- HANDLE_WACKY_STATE();
+ if (status == CHIP_TIMEDOUT)
+ printk(KERN_WARNING "MTD %s(): flash internal timeout\n",
+ __func__);
+ else if (ta)
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
+ else
+ printk(KERN_WARNING "MTD %s(): unexpected failure. status = %d\n",
+ __func__, status);
op_failed:
/* reset on all failures. */
cfi_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
- CHECK_RETRIES();
ret = -EIO;
op_done:
@@ -1949,7 +1709,7 @@
schedule();
- remove_wait_queue(&chip->wq, &wait);
+ remove_wait_queue(&chip->wq, &wait);
goto retry;
}
@@ -2008,7 +1768,7 @@
/* Unlock the chips again */
if (ret) {
- for (i--; i >=0; i--) {
+ for (i--; i >=0; i--) {
chip = &cfi->chips[i];
cfi_spin_lock(chip->mutex);
@@ -2213,8 +1973,3 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Crossnet Co. <info at crossnet.co.jp> et al.");
MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
-
-#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY
-MODULE_PARM(retry_cmd_max, "i");
-MODULE_PARM_DESC(retry_cmd_max, "Number of times to retry an erase or program command if it fails - should only be needed by buggy hardware: default 0");
-#endif
More information about the linux-mtd-cvs
mailing list