[MTD] [OneNAND] Add write-while-program support
Linux-MTD Mailing List
linux-mtd at lists.infradead.org
Mon Mar 23 11:59:01 EDT 2009
Gitweb: http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=9ce969082e490d0a5a81862b364337c93dc3482a
Commit: 9ce969082e490d0a5a81862b364337c93dc3482a
Parent: a29f280b739985a9e829d67af4d08e6584153495
Author: Kyungmin Park <kmpark at infradead.org>
AuthorDate: Mon Nov 17 17:54:28 2008 +0900
Committer: David Woodhouse <David.Woodhouse at intel.com>
CommitDate: Mon Mar 23 15:14:46 2009 +0000
[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 at samsung.com>
Signed-off-by: Adrian Hunter <adrian.hunter at nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
---
drivers/mtd/onenand/onenand_base.c | 145 ++++++++++++++++++++++++------------
1 files changed, 96 insertions(+), 49 deletions(-)
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 529af27..30d6999 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -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;
}
More information about the linux-mtd-cvs
mailing list