public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* RFC: [PATCH] MTD OneNAND: multiblock erase support
@ 2009-06-15  7:03 Mika Korhonen
  2009-06-15  7:29 ` Artem Bityutskiy
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Mika Korhonen @ 2009-06-15  7:03 UTC (permalink / raw)
  To: linux-mtd Mailing List

[-- Attachment #1: Type: text/plain, Size: 452 bytes --]

Hi,

I wrote an initial support for OneNAND multiblock erase feature.  When
done in maximum 64 eraseblock batches multiblock erase is up to 30x
faster than block-by-block erase (not including erase verify, though).

However, I only had possibility to test this with an OMAP board, so I
don't know if e.g. the default onenand_wait needs adjustment. Also for
Flex-OneNAND the support goes off. Does Flex even have mb erase?

What do you think?

br,
Mika

[-- Attachment #2: 0001-MTD-OneNAND-multiblock-erase-support.patch --]
[-- Type: text/x-diff, Size: 6845 bytes --]

From 71ebb2166f129824ad3b82ba3372d104b98fb3a6 Mon Sep 17 00:00:00 2001
From: Mika Korhonen <mika.j.korhonen@gmail.com>
Date: Mon, 15 Jun 2009 09:48:36 +0300
Subject: [PATCH] MTD OneNAND: multiblock erase support

Add support for multiblock erase command. OneNAND is capable of
simultaneous erase of up to 64 eraseblocks. In case this kernel
option is enabled the erase requests for regions of size 2..64
eraseblocks are performed using multiblock erase.

Signed-off-by: Mika Korhonen <mika.j.korhonen@gmail.com>
---
 drivers/mtd/onenand/Kconfig        |    9 ++++
 drivers/mtd/onenand/omap2.c        |    6 +++
 drivers/mtd/onenand/onenand_base.c |   84 ++++++++++++++++++++++++++++++++++++
 include/linux/mtd/onenand.h        |    2 +
 include/linux/mtd/onenand_regs.h   |    2 +
 5 files changed, 103 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index 79fa79e..f7037c3 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -64,6 +64,15 @@ config MTD_ONENAND_2X_PROGRAM
 
 	  And more recent chips
 
+config MTD_ONENAND_MULTIBLOCK_ERASE
+	bool "OneNAND multiblock erase support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  Support for multiblock erase command. OneNAND is capable of
+	  simultaneous erase of up to 64 eraseblocks. If this option is
+	  enabled the erase requests for regions of size 2..64 eraseblocks
+	  are performed using multiblock erase.
+
 config MTD_ONENAND_SIM
 	tristate "OneNAND simulator support"
 	depends on MTD_PARTITIONS
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index df26db8..cc2b48b 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -255,6 +255,12 @@ retry:
 		return -EIO;
 	}
 
+#ifdef CONFIG_MTD_ONENAND_MULTIBLOCK_ERASE
+	/* multiblock erase command: ONGO | ERASE (0x8800) */
+	if (state == FL_PREPARING_ERASE && !(ctrl & 0x769F)) {
+		return 0;
+	}
+#endif
 	if (ctrl & 0xFE9F)
 		wait_warn("unexpected controller status", state, ctrl, intr);
 
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 864327e..1525fd7 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -31,9 +31,15 @@
 
 #include <asm/io.h>
 
+/* Multiblock erase if number of blocks to erase is 2..64 */
+#define MB_ERASE_MIN_BLK_COUNT 2
+#define MB_ERASE_MAX_BLK_COUNT 64
+
+
 /* Default Flex-OneNAND boundary and lock respectively */
 static int flex_bdry[MAX_DIES * 2] = { -1, 0, -1, 0 };
 
+
 /**
  *  onenand_oob_128 - oob info for Flex-Onenand with 4KB page
  *  For now, we expose only 64 out of 80 ecc bytes
@@ -330,6 +336,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
 		break;
 
 	case ONENAND_CMD_ERASE:
+	case ONENAND_CMD_MULTIBLOCK_ERASE:
+	case ONENAND_CMD_ERASE_VERIFY:
 	case ONENAND_CMD_BUFFERRAM:
 	case ONENAND_CMD_OTP_ACCESS:
 		block = onenand_block(this, addr);
@@ -2147,6 +2155,9 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
 	int ret = 0, i;
 	struct mtd_erase_region_info *region = NULL;
 	loff_t region_end = 0;
+#ifdef CONFIG_MTD_ONENAND_MULTIBLOCK_ERASE
+	int do_mb_erase = 0;
+#endif
 
 	DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len);
 
@@ -2193,6 +2204,52 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
 	onenand_get_device(mtd, FL_ERASING);
 
 	/* Loop throught the pages */
+#ifdef CONFIG_MTD_ONENAND_MULTIBLOCK_ERASE
+
+	instr->state = MTD_ERASING;
+	if (!FLEXONENAND(this) &&
+	    (len >= MB_ERASE_MIN_BLK_COUNT * block_size)) {
+		if (len <= MB_ERASE_MAX_BLK_COUNT * block_size) {
+			do_mb_erase = 1;
+		} else {
+			/* OneNAND would seem capable of handling more than
+			   64 blocks (how much more?) with multiblock erase
+			   command. However, 64 is the max for simultaneous
+			   erase */
+			printk(KERN_WARNING "onenand_erase: performance warning: "
+                               "erase over %d blocks\n", MB_ERASE_MAX_BLK_COUNT);
+			do_mb_erase = 0;
+		}
+	}
+
+	while (do_mb_erase && len > block_size) {
+		/* Check if we have a bad block, we do not erase bad blocks */
+		if (onenand_block_isbad_nolock(mtd, addr, 0)) {
+			printk(KERN_WARNING "onenand_erase: attempt to erase "
+			       "a bad block at addr 0x%08x\n", (unsigned int) addr);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+
+		this->command(mtd, ONENAND_CMD_MULTIBLOCK_ERASE, addr, block_size);
+
+		onenand_invalidate_bufferram(mtd, addr, block_size);
+
+		ret = this->wait(mtd, FL_PREPARING_ERASE);
+		/* Check, if it is write protected */
+		if (ret) {
+			printk(KERN_ERR "onenand_erase: Failed multiblock erase, "
+                               "block %d\n", (unsigned) (addr >> this->erase_shift));
+			instr->state = MTD_ERASE_FAILED;
+			instr->fail_addr = addr;
+			goto erase_exit;
+		}
+		len -= block_size;
+		addr += block_size;
+	}
+#endif /* CONFIG_MTD_ONENAND_MULTIBLOCK_ERASE */
+
+	/* single block erase, also called for the last block of multiblock erase */
 	instr->state = MTD_ERASING;
 
 	while (len) {
@@ -2239,6 +2296,33 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
 
 	}
 
+
+#ifdef CONFIG_MTD_ONENAND_MULTIBLOCK_ERASE
+
+	/* multiblock erase verify */
+	if (do_mb_erase) {
+		/* Loop through the blocks */
+		len = instr->len;
+		addr = instr->addr;
+
+		while (len) {
+			this->command(mtd, ONENAND_CMD_ERASE_VERIFY, addr, block_size);
+			ret = this->wait(mtd, FL_VERIFYING_ERASE);
+			if (ret) {
+				printk(KERN_ERR "onenand_erase: Failed verify, "
+					"block %d\n", (unsigned) (addr >> this->erase_shift));
+				instr->state = MTD_ERASE_FAILED;
+				instr->fail_addr = addr;
+				goto erase_exit;
+			}
+
+			len -= block_size;
+			addr += block_size;
+		}
+	}
+
+#endif /* CONFIG_MTD_ONENAND_MULTIBLOCK_ERASE */
+
 	instr->state = MTD_ERASE_DONE;
 
 erase_exit:
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 8ed8733..42384f3 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -39,6 +39,8 @@ typedef enum {
 	FL_RESETING,
 	FL_OTPING,
 	FL_PM_SUSPENDED,
+	FL_PREPARING_ERASE,
+	FL_VERIFYING_ERASE
 } onenand_state_t;
 
 /**
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index 86a6bbe..bd346e5 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -131,6 +131,8 @@
 #define ONENAND_CMD_LOCK_TIGHT		(0x2C)
 #define ONENAND_CMD_UNLOCK_ALL		(0x27)
 #define ONENAND_CMD_ERASE		(0x94)
+#define ONENAND_CMD_MULTIBLOCK_ERASE	(0x95)
+#define ONENAND_CMD_ERASE_VERIFY	(0x71)
 #define ONENAND_CMD_RESET		(0xF0)
 #define ONENAND_CMD_OTP_ACCESS		(0x65)
 #define ONENAND_CMD_READID		(0x90)
-- 
1.5.6.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-06-18  7:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-06-15  7:03 RFC: [PATCH] MTD OneNAND: multiblock erase support Mika Korhonen
2009-06-15  7:29 ` Artem Bityutskiy
2009-06-15  7:54 ` Kyungmin Park
2009-06-15  8:20   ` Mika Korhonen
2009-06-15 10:11 ` Adrian Hunter
2009-06-15 11:02   ` Mika Korhonen
2009-06-18  7:01     ` Kyungmin Park

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox