Commit 9ce96908 authored by Kyungmin Park's avatar Kyungmin Park Committed by 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: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@nokia.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent a29f280b
...@@ -1455,7 +1455,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ...@@ -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, ...@@ -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,79 +1497,121 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ...@@ -1492,79 +1497,121 @@ 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) {
u_char *wbuf = (u_char *) buf; if (written < len) {
u_char *wbuf = (u_char *) buf;
thislen = min_t(int, mtd->writesize - column, len - written); thislen = min_t(int, mtd->writesize - column, len - written);
thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); 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 */ /* Partial page write */
subpage = thislen < mtd->writesize; subpage = thislen < mtd->writesize;
if (subpage) { if (subpage) {
memset(this->page_buf, 0xff, mtd->writesize); memset(this->page_buf, 0xff, mtd->writesize);
memcpy(this->page_buf + column, buf, thislen); memcpy(this->page_buf + column, buf, thislen);
wbuf = this->page_buf; 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) { if (oob) {
oobbuf = this->oob_buf; oobbuf = this->oob_buf;
/* We send data to spare ram with oobsize /* We send data to spare ram with oobsize
* to prevent byte access */ * to prevent byte access */
memset(oobbuf, 0xff, mtd->oobsize); memset(oobbuf, 0xff, mtd->oobsize);
if (ops->mode == MTD_OOB_AUTO) if (ops->mode == MTD_OOB_AUTO)
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
else else
memcpy(oobbuf + oobcolumn, oob, thisooblen); memcpy(oobbuf + oobcolumn, oob, thisooblen);
oobwritten += thisooblen; oobwritten += thisooblen;
oob += thisooblen; oob += thisooblen;
oobcolumn = 0; oobcolumn = 0;
} else
oobbuf = (u_char *) ffchars;
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
} else } 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 */ if (written == len) {
onenand_update_bufferram(mtd, to, !ret && !subpage); /* Only check verify write turn on */
if (ONENAND_IS_2PLANE(this)) { ret = onenand_verify(mtd, buf - len, to - len, len);
ONENAND_SET_BUFFERRAM1(this); if (ret)
onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
} break;
}
if (ret) { ONENAND_SET_NEXT_BUFFERRAM(this);
printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
break;
} }
/* Only check verify write turn on */ this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
ret = onenand_verify(mtd, buf, to, thislen);
if (ret) {
printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
break;
}
written += thislen; /*
* 2 PLANE, MLC, and Flex-OneNAND wait here
*/
if (ONENAND_IS_2PLANE(this)) {
ret = this->wait(mtd, FL_WRITING);
if (written == len) /* In partial page write we don't update bufferram */
break; 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; 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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment