Patchwork RFC: [PATCH] MTD OneNAND: multiblock erase support

login
register
mail settings
Submitter Mika Korhonen
Date June 15, 2009, 7:03 a.m.
Message ID <7948530906150003g365c8af3g9a9aaf8c8b985aa7@mail.gmail.com>
Download mbox | patch
Permalink /patch/28691/
State RFC
Headers show

Comments

Mika Korhonen - June 15, 2009, 7:03 a.m.
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
Artem Bityutskiy - June 15, 2009, 7:29 a.m.
On Mon, 2009-06-15 at 10:03 +0300, Mika Korhonen wrote:
> 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?

Would it be please possible to send the patch inlined?

Also, I suggest you to CC:

Adrian Hunter <adrian.hunter@nokia.com>
Kyungmin Park <kyungmin.park@samsung.com>
Amul Saha <amul.saha@samsung.com>

because they are OneNAND-relevent.
Kyungmin Park - June 15, 2009, 7:54 a.m.
On Mon, Jun 15, 2009 at 4:03 PM, Mika Korhonen<mika.j.korhonen@gmail.com> wrote:
> 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?
>

Hi,

I think you should also modify onenand_wait. and Flex-OneNAND supports
the multi-block erase.

Do you consider the exception case if the multi-block erase failed?

I think you don't consider the bad block handling in case of multi-block erase

You first check the there's no bad block in multi-block erase. the
following code only exit. it means we never erase if we have bad
block.

+	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;
+	}

Thank you,
Kyungmin Park
Mika Korhonen - June 15, 2009, 8:20 a.m.
2009/6/15 Kyungmin Park <kyungmin78@gmail.com>:
> On Mon, Jun 15, 2009 at 4:03 PM, Mika Korhonen<mika.j.korhonen@gmail.com> wrote:
>> 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?
>>
>
> Hi,
>
> I think you should also modify onenand_wait. and Flex-OneNAND supports
> the multi-block erase.

Ok, could I actually test the default onenand_wait() by not overriding
them in OMAP-specific side? Is there anything special that should be
considered with Flex? Likely just removing the if condition would not
work, would it? :)

> Do you consider the exception case if the multi-block erase failed?
>
> I think you don't consider the bad block handling in case of multi-block erase
>
> You first check the there's no bad block in multi-block erase. the
> following code only exit. it means we never erase if we have bad
> block.

You're right but that's also how the current implementation works in
case the area to be erased contains multiple eraseblocks and a bad one
is encountered. I tried to keep the behaviour the same. To change that
for better would require some way to inform the caller which eb's were
bad. New ioctl()?

Thank you for the good comments!
Mika
Adrian Hunter - June 15, 2009, 10:11 a.m.
Mika Korhonen wrote:
> 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?

I expect all OneNAND support multiblock erase, so the config should
go away.  Kyungmin can probably comment on that.

Waiting for multiblock-erase, you should probably spin, not use the
interrupt line.  You should change the wait function in
onenand_base and omap2.c.

You should handle multiple multiblock erases.

You should check for bad blocks *before* doing command 0x95

Waiting for erase-verify, you should probably spin too.
Mika Korhonen - June 15, 2009, 11:02 a.m.
2009/6/15 Adrian Hunter <adrian.hunter@nokia.com>:
> Mika Korhonen wrote:
>>
>> 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?
>
> I expect all OneNAND support multiblock erase, so the config should
> go away.  Kyungmin can probably comment on that.

Yes, I was thinking about that as well. Is it included in all chips?

> Waiting for multiblock-erase, you should probably spin, not use the
> interrupt line.  You should change the wait function in
> onenand_base and omap2.c.
>
> You should handle multiple multiblock erases.
>
> You should check for bad blocks *before* doing command 0x95

Ok

> Waiting for erase-verify, you should probably spin too.
>
I just tried that and it looks like spinning in verify read makes a
difference as I got 30% faster total time for 1600 block erase.

Thanks for good advice!
Mika
Kyungmin Park - June 18, 2009, 7:01 a.m.
On Mon, Jun 15, 2009 at 8:02 PM, Mika Korhonen<mika.j.korhonen@gmail.com> wrote:
> 2009/6/15 Adrian Hunter <adrian.hunter@nokia.com>:
>> Mika Korhonen wrote:
>>>
>>> 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?
>>
>> I expect all OneNAND support multiblock erase, so the config should
>> go away.  Kyungmin can probably comment on that.
>
> Yes, I was thinking about that as well. Is it included in all chips?

So I got mistake, the Flex-OneNAND don't support the multi-block
erase. Instead it support the erase suspend & resume

Thank you,
Kyungmin Park

Patch

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