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:
committed by
David Woodhouse
parent
7126bd8be4
commit
73885aeaca
@@ -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 mtd MTD device structure
|
||||||
* @param instr erase instruction
|
* @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;
|
struct onenand_chip *this = mtd->priv;
|
||||||
unsigned int block_size;
|
|
||||||
loff_t addr = instr->addr;
|
loff_t addr = instr->addr;
|
||||||
loff_t len = instr->len;
|
int len = instr->len;
|
||||||
int ret = 0, i;
|
|
||||||
struct mtd_erase_region_info *region = NULL;
|
|
||||||
loff_t region_end = 0;
|
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);
|
if (region) {
|
||||||
|
/* region is set for Flex-OneNAND */
|
||||||
/* 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;
|
|
||||||
region_end = region->offset + region->erasesize * region->numblocks;
|
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;
|
instr->state = MTD_ERASING;
|
||||||
|
|
||||||
|
/* Loop through the blocks */
|
||||||
while (len) {
|
while (len) {
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
|
||||||
@@ -2255,7 +2219,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|||||||
"at addr 0x%012llx\n",
|
"at addr 0x%012llx\n",
|
||||||
__func__, (unsigned long long) addr);
|
__func__, (unsigned long long) addr);
|
||||||
instr->state = MTD_ERASE_FAILED;
|
instr->state = MTD_ERASE_FAILED;
|
||||||
goto erase_exit;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
|
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));
|
__func__, onenand_block(this, addr));
|
||||||
instr->state = MTD_ERASE_FAILED;
|
instr->state = MTD_ERASE_FAILED;
|
||||||
instr->fail_addr = addr;
|
instr->fail_addr = addr;
|
||||||
goto erase_exit;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
len -= block_size;
|
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. */
|
/* FIXME: This should be handled at MTD partitioning level. */
|
||||||
printk(KERN_ERR "%s: Unaligned address\n",
|
printk(KERN_ERR "%s: Unaligned address\n",
|
||||||
__func__);
|
__func__);
|
||||||
goto erase_exit;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
instr->state = MTD_ERASE_DONE;
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
erase_exit:
|
DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__,
|
||||||
|
(unsigned long long) instr->addr, (unsigned long long) instr->len);
|
||||||
|
|
||||||
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
|
/* 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->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 */
|
/* Deselect and wake up anyone waiting on the device */
|
||||||
onenand_release_device(mtd);
|
onenand_release_device(mtd);
|
||||||
|
|
||||||
/* Do call back function */
|
/* Do call back function */
|
||||||
if (!ret)
|
if (!ret) {
|
||||||
|
instr->state = MTD_ERASE_DONE;
|
||||||
mtd_erase_callback(instr);
|
mtd_erase_callback(instr);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user