[PATCH 5/6] nor m25p80: optimize erase

Sascha Hauer s.hauer at pengutronix.de
Tue Jul 31 13:59:15 EDT 2012


The driver currently erases blocks in 4kb chunks if 4kb support is
available. This patch uses bigger blocks for suitable areas to speed
up erasing areas.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/nor/m25p80.c |   59 +++++++++++++++++++++++++++++++++++---------------
 drivers/nor/m25p80.h |    2 ++
 2 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/drivers/nor/m25p80.c b/drivers/nor/m25p80.c
index 7ff4546..4b62e93 100644
--- a/drivers/nor/m25p80.c
+++ b/drivers/nor/m25p80.c
@@ -168,7 +168,7 @@ static int m25p_cmdsz(struct m25p *flash)
  *
  * Returns 0 if successful, non-zero otherwise.
  */
-static int erase_sector(struct m25p *flash, u32 offset)
+static int erase_sector(struct m25p *flash, u32 offset, u32 command)
 {
 	dev_dbg(&flash->spi->dev, "%s %dKiB at 0x%08x\n",
 		__func__, flash->erasesize / 1024, offset);
@@ -181,7 +181,7 @@ static int erase_sector(struct m25p *flash, u32 offset)
 	write_enable(flash);
 
 	/* Set up command buffer. */
-	flash->command[0] = flash->erase_opcode;
+	flash->command[0] = command;
 	m25p_addr2cmd(flash, offset, flash->command);
 
 	spi_write(flash->spi, flash->command, m25p_cmdsz(flash));
@@ -216,22 +216,45 @@ static ssize_t m25p80_erase(struct cdev *cdev, size_t count, loff_t offset)
 		return 0;
 	}
 
-	/* REVISIT in some cases we could speed up erasing large regions
-	 * by using OPCODE_SE instead of OPCODE_BE_4K.  We may have set up
-	 * to use "small sector erase", but that's not always optimal.
-	 */
+	if (flash->erase_opcode_4k) {
+		while (len && (addr & (flash->sector_size - 1))) {
+			if (ctrlc())
+				return -EINTR;
+			if (erase_sector(flash, addr, flash->erase_opcode_4k))
+				return -EIO;
+			addr += flash->erasesize;
+			len -= flash->erasesize;
+		}
 
-	/* "sector"-at-a-time erase */
-	while (len) {
-		if (ctrlc())
-			return -EINTR;
-		if (erase_sector(flash, addr))
-			return -EIO;
+		while (len >= flash->sector_size) {
+			if (ctrlc())
+				return -EINTR;
+			if (erase_sector(flash, addr, flash->erase_opcode))
+				return -EIO;
+			addr += flash->sector_size;
+			len -= flash->sector_size;
+		}
 
-		if (len <= flash->erasesize)
-			break;
-		addr += flash->erasesize;
-		len -= flash->erasesize;
+		while (len) {
+			if (ctrlc())
+				return -EINTR;
+			if (erase_sector(flash, addr, flash->erase_opcode_4k))
+				return -EIO;
+			addr += flash->erasesize;
+			len -= flash->erasesize;
+		}
+	} else {
+		while (len) {
+			if (ctrlc())
+				return -EINTR;
+			if (erase_sector(flash, addr, flash->erase_opcode))
+				return -EIO;
+
+			if (len <= flash->erasesize)
+				break;
+			addr += flash->erasesize;
+			len -= flash->erasesize;
+		}
 	}
 
 	return 0;
@@ -753,6 +776,7 @@ static int m25p_probe(struct device_d *dev)
 	flash->info = info;
 	flash->size = info->sector_size * info->n_sectors;
 	flash->erasesize = info->sector_size;
+	flash->sector_size = info->sector_size;
 	flash->cdev.size = info->sector_size * info->n_sectors;
 	flash->cdev.dev = dev;
 	flash->cdev.ops = &m25p80_ops;
@@ -773,7 +797,8 @@ static int m25p_probe(struct device_d *dev)
 
 	/* prefer "small sector" erase if possible */
 	if (info->flags & SECT_4K) {
-		flash->erase_opcode = OPCODE_BE_4K;
+		flash->erase_opcode_4k = OPCODE_BE_4K;
+		flash->erase_opcode = OPCODE_SE;
 		flash->erasesize = 4096;
 	} else {
 		flash->erase_opcode = OPCODE_SE;
diff --git a/drivers/nor/m25p80.h b/drivers/nor/m25p80.h
index 3f9dd9c..ce48ba7 100644
--- a/drivers/nor/m25p80.h
+++ b/drivers/nor/m25p80.h
@@ -58,9 +58,11 @@ struct m25p {
 	struct cdev		cdev;
 	char			*name;
 	u32			erasesize;
+	u32			sector_size;
 	u16			page_size;
 	u16			addr_width;
 	u8			erase_opcode;
+	u8			erase_opcode_4k;
 	u8			*command;
 	u32			size;
 };
-- 
1.7.10.4




More information about the barebox mailing list