[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>
此提交包含在:
Kyungmin Park
2008-11-17 17:54:28 +09:00
提交者 David Woodhouse
父節點 a29f280b73
當前提交 9ce969082e

查看文件

@@ -1455,7 +1455,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
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;
size_t len = ops->len;
size_t ooblen = ops->ooblen;
@@ -1482,6 +1483,10 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
return -EINVAL;
}
/* Check zero length */
if (!len)
return 0;
if (ops->mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
else
@@ -1492,79 +1497,121 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
column = to & (mtd->writesize - 1);
/* Loop until all data write */
while (written < len) {
u_char *wbuf = (u_char *) buf;
while (1) {
if (written < len) {
u_char *wbuf = (u_char *) buf;
thislen = min_t(int, mtd->writesize - column, len - written);
thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
thislen = min_t(int, mtd->writesize - column, len - written);
thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
cond_resched();
cond_resched();
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
/* Partial page write */
subpage = thislen < mtd->writesize;
if (subpage) {
memset(this->page_buf, 0xff, mtd->writesize);
memcpy(this->page_buf + column, buf, thislen);
wbuf = this->page_buf;
}
/* Partial page write */
subpage = thislen < mtd->writesize;
if (subpage) {
memset(this->page_buf, 0xff, mtd->writesize);
memcpy(this->page_buf + column, buf, thislen);
wbuf = this->page_buf;
}
this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
if (oob) {
oobbuf = this->oob_buf;
if (oob) {
oobbuf = this->oob_buf;
/* We send data to spare ram with oobsize
* to prevent byte access */
memset(oobbuf, 0xff, mtd->oobsize);
if (ops->mode == MTD_OOB_AUTO)
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob, thisooblen);
/* We send data to spare ram with oobsize
* to prevent byte access */
memset(oobbuf, 0xff, mtd->oobsize);
if (ops->mode == MTD_OOB_AUTO)
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
else
memcpy(oobbuf + oobcolumn, oob, thisooblen);
oobwritten += thisooblen;
oob += thisooblen;
oobcolumn = 0;
oobwritten += thisooblen;
oob += thisooblen;
oobcolumn = 0;
} else
oobbuf = (u_char *) ffchars;
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
} else
oobbuf = (u_char *) ffchars;
ONENAND_SET_NEXT_BUFFERRAM(this);
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
/*
* 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);
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
if (ret) {
written -= prevlen;
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);
ret = this->wait(mtd, FL_WRITING);
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, to, !ret && !subpage);
/*
* 2 PLANE, MLC, and Flex-OneNAND wait here
*/
if (ONENAND_IS_2PLANE(this)) {
ONENAND_SET_BUFFERRAM1(this);
onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
}
ret = this->wait(mtd, FL_WRITING);
if (ret) {
printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
break;
}
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, to, !ret && !subpage);
if (ret) {
printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
break;
}
/* Only check verify write turn on */
ret = onenand_verify(mtd, buf, to, thislen);
if (ret) {
printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
break;
}
/* Only check verify write turn on */
ret = onenand_verify(mtd, buf, to, thislen);
if (ret) {
printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
break;
}
written += thislen;
written += thislen;
if (written == len)
break;
if (written == len)
break;
} else
written += thislen;
column = 0;
prev_subpage = subpage;
prev = to;
prevlen = thislen;
to += thislen;
buf += thislen;
first = 0;
}
/* In error case, clear all bufferrams */
if (written != len)
onenand_invalidate_bufferram(mtd, 0, -1);
ops->retlen = written;
ops->oobretlen = oobwritten;
return ret;
}