public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
From: Joakim Tjernlund <Joakim.Tjernlund@lumentis.se>
To: linux-mtd@lists.infradead.org
Subject: cfi_cmdset0001.c: bug fixes and new features.
Date: Thu, 14 Feb 2002 15:05:34 +0100	[thread overview]
Message-ID: <02021415053402.15969@jocke.lumentis.se> (raw)
In-Reply-To: <02012911331100.15969@jocke.lumentis.se>

Hi again

I hve fixed a few minor bugs:
1)  
-               extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
-               extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
-               extp->ProtRegAddr = cfi32_to_cpu(extp->ProtRegAddr);
+               extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+               extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
+               extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);

This flash always reports these in litte endian. This corrects things on a BE CPU. Not sure if this
is the correct fix though.

2)
-               if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+               if (! (extp->FeatureSupport & 2))

was doing if ( (!*p) & 2), should be if (! (*p &2))

New features:
3)
+#ifdef CONFIG_BUGGY_CMDSET001_CHIPS
+               /* Disable Erase Suspend function in flash, needed by early revisions of Intel Strata chips */
+               extp->FeatureSupport &= ~2;
+#endif
No explanation needed :-)

4)
    Rest of the patch:
         improves suspending erase to do a read.
         adds suspending erase to do a write.

The path is against: $Id: cfi_cmdset_0001.c,v 1.91 2002/01/10 20:27:40 eric Exp $
since thats what I am using.

Comments?

             Jocke

Patch follows:
I--- /usr/local/src/MTD/mtd/drivers/mtd/chips/cfi_cmdset_0001.c	Mon Jan 21 14:06:02 2002
+++ drivers/mtd/chips/cfi_cmdset_0001.c	Thu Feb 14 15:02:15 2002
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.91 2002/01/10 20:27:40 eric Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.4 2002/01/31 13:56:10 jocke Exp $
  *
  * 
  * 10/10/2000	Nicolas Pitre <nico@cam.org>
@@ -61,6 +61,8 @@
 #ifdef DEBUG_CFI_FEATURES
 static void cfi_tell_features(struct cfi_pri_intelext *extp)
 {
+	int i;
+
 	printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
 	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
 	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
@@ -151,15 +153,20 @@
 		}
 		
 		/* Do some byteswapping if necessary */
-		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
-		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
-		extp->ProtRegAddr = cfi32_to_cpu(extp->ProtRegAddr);
+		extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+		extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
+		extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
 			
 #ifdef DEBUG_CFI_FEATURES
 		/* Tell the user about it in lots of lovely detail */
 		cfi_tell_features(extp);
 #endif	
 
+#ifdef CONFIG_BUGGY_CMDSET001_CHIPS
+		/* Disable Erase Suspend function in flash, needed by early revisions of Intel Strata chips */
+		extp->FeatureSupport &= ~2;
+#endif	
+
 		/* Install our own private info structure */
 		cfi->cmdset_priv = extp;	
 	}
@@ -213,7 +220,7 @@
 		unsigned long ernum, ersize;
 		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
 		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
-
+		
 		if (mtd->erasesize < ersize) {
 			mtd->erasesize = ersize;
 		}
@@ -223,25 +230,25 @@
 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
 		}
 		offset += (ersize * ernum);
-		}
-
-		if (offset != devsize) {
-			/* Argh */
-			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
-			kfree(mtd->eraseregions);
-			kfree(cfi->cmdset_priv);
-			return NULL;
-		}
-
-		for (i=0; i<mtd->numeraseregions;i++){
-			printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
-			       i,mtd->eraseregions[i].offset,
-			       mtd->eraseregions[i].erasesize,
-			       mtd->eraseregions[i].numblocks);
-		}
+	}
+	
+	if (offset != devsize) {
+		/* Argh */
+		printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+		kfree(mtd->eraseregions);
+		kfree(cfi->cmdset_priv);
+		return NULL;
+	}
+	
+	for (i=0; i<mtd->numeraseregions;i++){
+		printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+		       i,mtd->eraseregions[i].offset,
+		       mtd->eraseregions[i].erasesize,
+		       mtd->eraseregions[i].numblocks);
+	}
 
 	/* Also select the correct geometry setup too */ 
-		mtd->erase = cfi_intelext_erase_varsize;
+	mtd->erase = cfi_intelext_erase_varsize;
 	mtd->read = cfi_intelext_read;
 	if ( cfi->cfiq->BufWriteTimeoutTyp ) {
 		//printk(KERN_INFO "Using buffer write method\n" );
@@ -273,6 +280,7 @@
 	int suspended = 0;
 	unsigned long cmd_addr;
 	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 
 	adr += chip->start;
 
@@ -291,7 +299,7 @@
 	 */
 	switch (chip->state) {
 	case FL_ERASING:
-		if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+		if (! (extp->FeatureSupport & 2))
 			goto sleep; /* We don't support erase suspend */
 		
 		cfi_write (map, CMD(0xb0), cmd_addr);
@@ -325,8 +333,10 @@
 			cfi_udelay(1);
 			spin_lock_bh(chip->mutex);
 		}
+		/* see if chip was suspended or if it completed the erase cycle */
+		if (status & CMD(0x40))
+			suspended = 1; 	/* at least one chip has been suspended */
 		
-		suspended = 1;
 		cfi_write(map, CMD(0xff), cmd_addr);
 		chip->state = FL_READY;
 		break;
@@ -551,10 +561,11 @@
 static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 	__u32 status, status_OK;
 	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
-	int z;
+	int z, suspended=0;
 
 	adr += chip->start;
 
@@ -565,11 +576,6 @@
  retry:
 	spin_lock_bh(chip->mutex);
 
-	/* Check that the chip's ready to talk to us.
-	 * Later, we can actually think about interrupting it
-	 * if it's in FL_ERASING state.
-	 * Not just yet, though.
-	 */
 	switch (chip->state) {
 	case FL_READY:
 		break;
@@ -596,7 +602,52 @@
 		cfi_udelay(1);
 		goto retry;
 
+	case FL_ERASING:
+		if (! ((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
+			goto sleep; /* We don't support program in erase suspend */
+		
+		cfi_write (map, CMD(0xb0), adr);
+
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), adr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		//printk("Erase suspending at 0x%lx\n", adr);
+		for (;;) {
+			status = cfi_read(map, adr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), adr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), adr);
+				chip->state = FL_ERASING;
+				spin_unlock_bh(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock_bh(chip->mutex);
+			cfi_udelay(1);
+			spin_lock_bh(chip->mutex);
+		}
+		/* see if chip(s) was suspended or if it completed the erase cycle */
+		if (status & CMD(0x40)){
+			suspended = 1; 	/* at least one chip has been suspended */
+			//printk("Erase was suspended at 0x%lx\n", adr);
+		}
+		chip->state = FL_STATUS;
+		break;
+
 	default:
+	sleep:
 		/* Stick ourselves on a wait queue to be woken when
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
@@ -661,20 +712,33 @@
 
 	/* Done and happy. */
 	DISABLE_VPP(map);
-	chip->state = FL_STATUS;
+
 	/* check for lock bit */
 	if (status & CMD(0x02)) {
-		/* clear status */
-		cfi_write(map, CMD(0x50), adr);
-		/* put back into read status register mode */
+		cfi_write(map, CMD(0x50), adr); /* clear status */
+	}
+
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), adr);
 		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+	} else {
+                /* Must be leave with FL_READY since we may have suspended an erase which compleated during suspend */
+		cfi_write(map, CMD(0xff), adr);
+		chip->state = FL_READY;
 	}
 	wake_up(&chip->wq);
 	spin_unlock_bh(chip->mutex);
-	return 0;
+	return (status & CMD(0x02) ? -EROFS : 0);
 }
 
 
@@ -798,10 +862,11 @@
 				  unsigned long adr, const u_char *buf, int len)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
 	__u32 status, status_OK;
 	unsigned long cmd_adr, timeo;
 	DECLARE_WAITQUEUE(wait, current);
-	int wbufsize, z;
+	int wbufsize, z, suspended=0;
 
 	wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
 	adr += chip->start;
@@ -814,11 +879,6 @@
  retry:
 	spin_lock_bh(chip->mutex);
 
-	/* Check that the chip's ready to talk to us.
-	 * Later, we can actually think about interrupting it
-	 * if it's in FL_ERASING state.
-	 * Not just yet, though.
-	 */
 	switch (chip->state) {
 	case FL_READY:
 	case FL_CFI_QUERY:
@@ -842,7 +902,53 @@
 		cfi_udelay(1);
 		goto retry;
 
+	case FL_ERASING:
+		if (! ((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), adr);
+
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), adr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		//printk("Erase suspending at 0x%lx\n", adr);
+		for (;;) {
+			status = cfi_read(map, adr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), adr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), adr);
+				chip->state = FL_ERASING;
+				spin_unlock_bh(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock_bh(chip->mutex);
+			cfi_udelay(1);
+			spin_lock_bh(chip->mutex);
+		}
+		/* see if chip was suspended or if it completed the erase cycle */
+		if (status & CMD(0x40)){
+			suspended = 1; 	/* at least one chip has been suspended */
+			//printk("Erase was suspended at 0x%lx\n", adr);
+		}
+		
+		chip->state = FL_STATUS;
+		break;
+
 	default:
+	sleep:
 		/* Stick ourselves on a wait queue to be woken when
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
@@ -959,20 +1065,33 @@
 
 	/* Done and happy. */
 	DISABLE_VPP(map);
-	chip->state = FL_STATUS;
-	/* check for lock bit */
+	
+        /* check for lock bit */
 	if (status & CMD(0x02)) {
-		/* clear status */
-		cfi_write(map, CMD(0x50), cmd_adr);
-		/* put back into read status register mode */
-		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+		cfi_write(map, CMD(0x50), adr); /* clear status */
+	}
+	if (suspended) {
+		//printk("Erase resumed at 0x%lx\n", adr);
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), adr);
+		cfi_write(map, CMD(0x70), adr);		
+	} else {
+		/* Must be leave with FL_READY since we may have suspended an erase which compleated during suspend */
+		cfi_write(map, CMD(0xff), adr);
+		chip->state = FL_READY;
 	}
 	wake_up(&chip->wq);
 	spin_unlock_bh(chip->mutex);
-	return 0;
+	return (status & CMD(0x02) ? -EROFS : 0);
 }
 
 static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, 
@@ -1126,6 +1245,8 @@
 
 	timeo = jiffies + (HZ*20);
 	for (;;) {
+		if(chip->state == FL_READY)
+			break; /* erase has compleated and someone put the chip into ready state */ 
 		if (chip->state != FL_ERASING) {
 			/* Someone's suspended the erase. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1151,7 +1272,7 @@
 		if (time_after(jiffies, timeo)) {
 			cfi_write(map, CMD(0x70), adr);
 			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for erase at %08x to complete timed out. Xstatus = %x, status = %x.\n", adr, status, cfi_read(map, adr));
+			printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %x, status = %x.\n", adr, status, cfi_read(map, adr));
 			/* Clear status bits */
 			cfi_write(map, CMD(0x50), adr);
 			cfi_write(map, CMD(0x70), adr);

  parent reply	other threads:[~2002-02-14 13:54 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-11-12 12:14 Cache mappings and invalidate Joakim Tjernlund
2001-11-12 17:44 ` Joakim Tjernlund
2001-12-17 13:08 ` Burst read and other improvements Joakim Tjernlund
2002-03-11  8:56   ` compr_zlib.c Joakim Tjernlund
2002-03-19 12:03   ` compr_zlib.c Joakim Tjernlund
2002-03-19 12:24     ` compr_zlib.c David Woodhouse
2002-01-04  8:59 ` CLEANMARKER question Joakim Tjernlund
2002-01-04  9:42   ` David Woodhouse
2002-01-04 10:33     ` Joakim Tjernlund
2002-01-04 10:41       ` David Woodhouse
2002-01-29 10:33   ` MTD/CFI probe broken? Joakim Tjernlund
2002-01-29 18:09     ` Joakim Tjernlund
2002-02-14 14:05     ` Joakim Tjernlund [this message]
2002-02-26 13:42     ` scan.c & ACCURATE Joakim Tjernlund
2002-02-26 15:52       ` David Woodhouse
2002-02-27  7:34         ` Joakim Tjernlund
2002-02-27  8:17           ` David Woodhouse
2002-02-27 12:29             ` Joakim Tjernlund
2002-02-26 15:53       ` David Woodhouse
2002-02-27  7:43         ` Joakim Tjernlund
2002-06-17  9:24       ` point()/unpoint() questions + small cfi_cmdset_0001.c patch Joakim Tjernlund
2002-06-17  9:56         ` David Woodhouse
2002-06-17 13:37           ` David Woodhouse
2002-06-17 15:41           ` Joakim Tjernlund
2002-06-17 15:56             ` David Woodhouse
2002-06-17 16:22               ` Joakim Tjernlund
2002-06-18 14:11                 ` David Woodhouse
2002-06-17  9:48       ` [PATCH] scan.c Joakim Tjernlund
2002-06-17  9:54       ` Joakim Tjernlund
2002-06-17 10:15         ` David Woodhouse
2002-06-17 12:16           ` Joakim Tjernlund
2002-06-17 12:45             ` David Woodhouse
2002-06-17 15:12               ` Joakim Tjernlund
2002-06-17 16:00                 ` David Woodhouse
2002-06-17 16:51                   ` Joakim Tjernlund
2002-06-17 22:59                     ` David Woodhouse

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=02021415053402.15969@jocke.lumentis.se \
    --to=joakim.tjernlund@lumentis.se \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox