提交 9ce96908 编写于 作者: K Kyungmin Park 提交者: David Woodhouse

[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: NKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: NAdrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: NDavid Woodhouse <David.Woodhouse@intel.com>
上级 a29f280b
......@@ -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);
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
ret = this->wait(mtd, FL_WRITING);
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;
}
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, to, !ret && !subpage);
if (ONENAND_IS_2PLANE(this)) {
ONENAND_SET_BUFFERRAM1(this);
onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
}
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;
}
if (ret) {
printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
break;
ONENAND_SET_NEXT_BUFFERRAM(this);
}
/* 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;
}
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
written += thislen;
/*
* 2 PLANE, MLC, and Flex-OneNAND wait here
*/
if (ONENAND_IS_2PLANE(this)) {
ret = this->wait(mtd, FL_WRITING);
if (written == len)
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;
}
written += thislen;
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;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册