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