[MTD] [OneNAND] Add write-while-program support
OneNAND write-while-program method of writing improves performance, compared with ordinary writes, by transferring data to OneNAND's RAM buffers atthe same time as programming the NAND core. When writing several NAND pages at a time, an improvement of 12% to 25% is seen. Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
a29f280b73
commit
9ce969082e
@ -1455,7 +1455,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
|||||||
struct mtd_oob_ops *ops)
|
struct mtd_oob_ops *ops)
|
||||||
{
|
{
|
||||||
struct onenand_chip *this = mtd->priv;
|
struct onenand_chip *this = mtd->priv;
|
||||||
int written = 0, column, thislen, subpage;
|
int written = 0, column, thislen = 0, subpage = 0;
|
||||||
|
int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
|
||||||
int oobwritten = 0, oobcolumn, thisooblen, oobsize;
|
int oobwritten = 0, oobcolumn, thisooblen, oobsize;
|
||||||
size_t len = ops->len;
|
size_t len = ops->len;
|
||||||
size_t ooblen = ops->ooblen;
|
size_t ooblen = ops->ooblen;
|
||||||
@ -1482,6 +1483,10 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check zero length */
|
||||||
|
if (!len)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (ops->mode == MTD_OOB_AUTO)
|
if (ops->mode == MTD_OOB_AUTO)
|
||||||
oobsize = this->ecclayout->oobavail;
|
oobsize = this->ecclayout->oobavail;
|
||||||
else
|
else
|
||||||
@ -1492,7 +1497,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
|||||||
column = to & (mtd->writesize - 1);
|
column = to & (mtd->writesize - 1);
|
||||||
|
|
||||||
/* Loop until all data write */
|
/* Loop until all data write */
|
||||||
while (written < len) {
|
while (1) {
|
||||||
|
if (written < len) {
|
||||||
u_char *wbuf = (u_char *) buf;
|
u_char *wbuf = (u_char *) buf;
|
||||||
|
|
||||||
thislen = min_t(int, mtd->writesize - column, len - written);
|
thislen = min_t(int, mtd->writesize - column, len - written);
|
||||||
@ -1530,18 +1536,47 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
|||||||
oobbuf = (u_char *) ffchars;
|
oobbuf = (u_char *) ffchars;
|
||||||
|
|
||||||
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
|
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
|
||||||
|
} else
|
||||||
|
ONENAND_SET_NEXT_BUFFERRAM(this);
|
||||||
|
|
||||||
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
|
/*
|
||||||
|
* 2 PLANE, MLC, and Flex-OneNAND doesn't support
|
||||||
|
* write-while-programe feature.
|
||||||
|
*/
|
||||||
|
if (!ONENAND_IS_2PLANE(this) && !first) {
|
||||||
|
ONENAND_SET_PREV_BUFFERRAM(this);
|
||||||
|
|
||||||
ret = this->wait(mtd, FL_WRITING);
|
ret = this->wait(mtd, FL_WRITING);
|
||||||
|
|
||||||
/* In partial page write we don't update bufferram */
|
/* In partial page write we don't update bufferram */
|
||||||
onenand_update_bufferram(mtd, to, !ret && !subpage);
|
onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
|
||||||
if (ONENAND_IS_2PLANE(this)) {
|
if (ret) {
|
||||||
ONENAND_SET_BUFFERRAM1(this);
|
written -= prevlen;
|
||||||
onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
|
printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (written == len) {
|
||||||
|
/* Only check verify write turn on */
|
||||||
|
ret = onenand_verify(mtd, buf - len, to - len, len);
|
||||||
|
if (ret)
|
||||||
|
printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ONENAND_SET_NEXT_BUFFERRAM(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 2 PLANE, MLC, and Flex-OneNAND wait here
|
||||||
|
*/
|
||||||
|
if (ONENAND_IS_2PLANE(this)) {
|
||||||
|
ret = this->wait(mtd, FL_WRITING);
|
||||||
|
|
||||||
|
/* In partial page write we don't update bufferram */
|
||||||
|
onenand_update_bufferram(mtd, to, !ret && !subpage);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
|
printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
|
||||||
break;
|
break;
|
||||||
@ -1559,12 +1594,24 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
|
|||||||
if (written == len)
|
if (written == len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
} else
|
||||||
|
written += thislen;
|
||||||
|
|
||||||
column = 0;
|
column = 0;
|
||||||
|
prev_subpage = subpage;
|
||||||
|
prev = to;
|
||||||
|
prevlen = thislen;
|
||||||
to += thislen;
|
to += thislen;
|
||||||
buf += thislen;
|
buf += thislen;
|
||||||
|
first = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In error case, clear all bufferrams */
|
||||||
|
if (written != len)
|
||||||
|
onenand_invalidate_bufferram(mtd, 0, -1);
|
||||||
|
|
||||||
ops->retlen = written;
|
ops->retlen = written;
|
||||||
|
ops->oobretlen = oobwritten;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user