mtd: OneNAND: move erase method to a separate function

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>
This commit is contained in:
Mika Korhonen 2009-10-23 07:50:42 +02:00 committed by David Woodhouse
parent 7126bd8be4
commit 73885aeaca
1 changed files with 76 additions and 56 deletions

View 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;
}
instr->state = MTD_ERASE_DONE;
if (FLEXONENAND(this)) {
/* Find the eraseregion of this address */
int i = flexonenand_region(mtd, addr);
erase_exit:
region = &mtd->eraseregions[i];
block_size = region->erasesize;
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
/* 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->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_ERASING);
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;
}