mtd: OneNAND: move erase method to a separate function
authorMika Korhonen <ext-mika.2.korhonen@nokia.com>
Fri, 23 Oct 2009 05:50:42 +0000 (07:50 +0200)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Mon, 30 Nov 2009 09:42:55 +0000 (09:42 +0000)
Separate the actual execution of erase to a new function:
onenand_block_by_block_erase(). This is done in preparation for
the multiblock erase support.

Signed-off-by: Mika Korhonen <ext-mika.2.korhonen@nokia.com>
Reviewed-by: Adrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
drivers/mtd/onenand/onenand_base.c

index 7bd6ad3ff30a8e3a36fad91f364c0a6a86395b35..894ebadc3e692c4180605be35432bf2aeeac3084 100644 (file)
@@ -2183,69 +2183,33 @@ static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allo
 }
 
 /**
- * onenand_erase - [MTD Interface] erase block(s)
+ * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase
  * @param mtd          MTD device structure
  * @param instr                erase instruction
+ * @param region       erase region
+ * @param block_size   erase block size
  *
- * Erase one ore more blocks
+ * Erase one or more blocks one block at a time
  */
-static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int onenand_block_by_block_erase(struct mtd_info *mtd,
+                                       struct erase_info *instr,
+                                       struct mtd_erase_region_info *region,
+                                       unsigned int block_size)
 {
        struct onenand_chip *this = mtd->priv;
-       unsigned int block_size;
        loff_t addr = instr->addr;
-       loff_t len = instr->len;
-       int ret = 0, i;
-       struct mtd_erase_region_info *region = NULL;
+       int len = instr->len;
        loff_t region_end = 0;
+       int ret = 0;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len);
-
-       /* Do not allow erase past end of device */
-       if (unlikely((len + addr) > mtd->size)) {
-               printk(KERN_ERR "%s: Erase past end of device\n", __func__);
-               return -EINVAL;
-       }
-
-       if (FLEXONENAND(this)) {
-               /* Find the eraseregion of this address */
-               i = flexonenand_region(mtd, addr);
-               region = &mtd->eraseregions[i];
-
-               block_size = region->erasesize;
+       if (region) {
+               /* region is set for Flex-OneNAND */
                region_end = region->offset + region->erasesize * region->numblocks;
-
-               /* Start address within region must align on block boundary.
-                * Erase region's start offset is always block start address.
-                */
-               if (unlikely((addr - region->offset) & (block_size - 1))) {
-                       printk(KERN_ERR "%s: Unaligned address\n", __func__);
-                       return -EINVAL;
-               }
-       } else {
-               block_size = 1 << this->erase_shift;
-
-               /* Start address must align on block boundary */
-               if (unlikely(addr & (block_size - 1))) {
-                       printk(KERN_ERR "%s: Unaligned address\n", __func__);
-                       return -EINVAL;
-               }
-       }
-
-       /* Length must align on block boundary */
-       if (unlikely(len & (block_size - 1))) {
-               printk(KERN_ERR "%s: Length not block aligned\n", __func__);
-               return -EINVAL;
        }
 
-       instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
-
-       /* Grab the lock and see if the device is available */
-       onenand_get_device(mtd, FL_ERASING);
-
-       /* Loop through the blocks */
        instr->state = MTD_ERASING;
 
+       /* Loop through the blocks */
        while (len) {
                cond_resched();
 
@@ -2255,7 +2219,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                                        "at addr 0x%012llx\n",
                                        __func__, (unsigned long long) addr);
                        instr->state = MTD_ERASE_FAILED;
-                       goto erase_exit;
+                       return -EIO;
                }
 
                this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
@@ -2269,7 +2233,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                                __func__, onenand_block(this, addr));
                        instr->state = MTD_ERASE_FAILED;
                        instr->fail_addr = addr;
-                       goto erase_exit;
+                       return -EIO;
                }
 
                len -= block_size;
@@ -2287,24 +2251,80 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
                                /* FIXME: This should be handled at MTD partitioning level. */
                                printk(KERN_ERR "%s: Unaligned address\n",
                                        __func__);
-                               goto erase_exit;
+                               return -EIO;
                        }
                }
+       }
+       return 0;
+}
+
+/**
+ * onenand_erase - [MTD Interface] erase block(s)
+ * @param mtd          MTD device structure
+ * @param instr                erase instruction
+ *
+ * Erase one or more blocks
+ */
+static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct onenand_chip *this = mtd->priv;
+       unsigned int block_size;
+       loff_t addr = instr->addr;
+       loff_t len = instr->len;
+       int ret = 0;
+       struct mtd_erase_region_info *region = NULL;
+       loff_t region_offset = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__,
+             (unsigned long long) instr->addr, (unsigned long long) instr->len);
+
+       /* Do not allow erase past end of device */
+       if (unlikely((len + addr) > mtd->size)) {
+               printk(KERN_ERR "%s: Erase past end of device\n", __func__);
+               return -EINVAL;
+       }
+
+       if (FLEXONENAND(this)) {
+               /* Find the eraseregion of this address */
+               int i = flexonenand_region(mtd, addr);
+
+               region = &mtd->eraseregions[i];
+               block_size = region->erasesize;
+
+               /* Start address within region must align on block boundary.
+                * Erase region's start offset is always block start address.
+                */
+               region_offset = region->offset;
+       } else
+               block_size = 1 << this->erase_shift;
+
+       /* Start address must align on block boundary */
+       if (unlikely((addr - region_offset) & (block_size - 1))) {
+               printk(KERN_ERR "%s: Unaligned address\n", __func__);
+               return -EINVAL;
+       }
 
+       /* Length must align on block boundary */
+       if (unlikely(len & (block_size - 1))) {
+               printk(KERN_ERR "%s: Length not block aligned\n", __func__);
+               return -EINVAL;
        }
 
-       instr->state = MTD_ERASE_DONE;
+       instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
 
-erase_exit:
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_ERASING);
 
-       ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+       ret = onenand_block_by_block_erase(mtd, instr, region, block_size);
 
        /* Deselect and wake up anyone waiting on the device */
        onenand_release_device(mtd);
 
        /* Do call back function */
-       if (!ret)
+       if (!ret) {
+               instr->state = MTD_ERASE_DONE;
                mtd_erase_callback(instr);
+       }
 
        return ret;
 }