aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKyungmin Park <kmpark@infradead.org>2008-11-17 03:54:28 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-03-23 11:14:46 -0400
commit9ce969082e490d0a5a81862b364337c93dc3482a (patch)
treed5cec57f918b38062496162f362e727a6da0043e /drivers
parenta29f280b739985a9e829d67af4d08e6584153495 (diff)
[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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/onenand/onenand_base.c145
1 files changed, 96 insertions, 49 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 529af271db17..30d6999e5f9f 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,
1455 struct mtd_oob_ops *ops) 1455 struct mtd_oob_ops *ops)
1456{ 1456{
1457 struct onenand_chip *this = mtd->priv; 1457 struct onenand_chip *this = mtd->priv;
1458 int written = 0, column, thislen, subpage; 1458 int written = 0, column, thislen = 0, subpage = 0;
1459 int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
1459 int oobwritten = 0, oobcolumn, thisooblen, oobsize; 1460 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1460 size_t len = ops->len; 1461 size_t len = ops->len;
1461 size_t ooblen = ops->ooblen; 1462 size_t ooblen = ops->ooblen;
@@ -1482,6 +1483,10 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1482 return -EINVAL; 1483 return -EINVAL;
1483 } 1484 }
1484 1485
1486 /* Check zero length */
1487 if (!len)
1488 return 0;
1489
1485 if (ops->mode == MTD_OOB_AUTO) 1490 if (ops->mode == MTD_OOB_AUTO)
1486 oobsize = this->ecclayout->oobavail; 1491 oobsize = this->ecclayout->oobavail;
1487 else 1492 else
@@ -1492,79 +1497,121 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1492 column = to & (mtd->writesize - 1); 1497 column = to & (mtd->writesize - 1);
1493 1498
1494 /* Loop until all data write */ 1499 /* Loop until all data write */
1495 while (written < len) { 1500 while (1) {
1496 u_char *wbuf = (u_char *) buf; 1501 if (written < len) {
1502 u_char *wbuf = (u_char *) buf;
1497 1503
1498 thislen = min_t(int, mtd->writesize - column, len - written); 1504 thislen = min_t(int, mtd->writesize - column, len - written);
1499 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); 1505 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
1500 1506
1501 cond_resched(); 1507 cond_resched();
1502 1508
1503 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); 1509 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1504 1510
1505 /* Partial page write */ 1511 /* Partial page write */
1506 subpage = thislen < mtd->writesize; 1512 subpage = thislen < mtd->writesize;
1507 if (subpage) { 1513 if (subpage) {
1508 memset(this->page_buf, 0xff, mtd->writesize); 1514 memset(this->page_buf, 0xff, mtd->writesize);
1509 memcpy(this->page_buf + column, buf, thislen); 1515 memcpy(this->page_buf + column, buf, thislen);
1510 wbuf = this->page_buf; 1516 wbuf = this->page_buf;
1511 } 1517 }
1512 1518
1513 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); 1519 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1514 1520
1515 if (oob) { 1521 if (oob) {
1516 oobbuf = this->oob_buf; 1522 oobbuf = this->oob_buf;
1517 1523
1518 /* We send data to spare ram with oobsize 1524 /* We send data to spare ram with oobsize
1519 * to prevent byte access */ 1525 * to prevent byte access */
1520 memset(oobbuf, 0xff, mtd->oobsize); 1526 memset(oobbuf, 0xff, mtd->oobsize);
1521 if (ops->mode == MTD_OOB_AUTO) 1527 if (ops->mode == MTD_OOB_AUTO)
1522 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); 1528 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1523 else 1529 else
1524 memcpy(oobbuf + oobcolumn, oob, thisooblen); 1530 memcpy(oobbuf + oobcolumn, oob, thisooblen);
1525 1531
1526 oobwritten += thisooblen; 1532 oobwritten += thisooblen;
1527 oob += thisooblen; 1533 oob += thisooblen;
1528 oobcolumn = 0; 1534 oobcolumn = 0;
1535 } else
1536 oobbuf = (u_char *) ffchars;
1537
1538 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1529 } else 1539 } else
1530 oobbuf = (u_char *) ffchars; 1540 ONENAND_SET_NEXT_BUFFERRAM(this);
1531 1541
1532 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); 1542 /*
1543 * 2 PLANE, MLC, and Flex-OneNAND doesn't support
1544 * write-while-programe feature.
1545 */
1546 if (!ONENAND_IS_2PLANE(this) && !first) {
1547 ONENAND_SET_PREV_BUFFERRAM(this);
1533 1548
1534 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); 1549 ret = this->wait(mtd, FL_WRITING);
1535 1550
1536 ret = this->wait(mtd, FL_WRITING); 1551 /* In partial page write we don't update bufferram */
1552 onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
1553 if (ret) {
1554 written -= prevlen;
1555 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1556 break;
1557 }
1537 1558
1538 /* In partial page write we don't update bufferram */ 1559 if (written == len) {
1539 onenand_update_bufferram(mtd, to, !ret && !subpage); 1560 /* Only check verify write turn on */
1540 if (ONENAND_IS_2PLANE(this)) { 1561 ret = onenand_verify(mtd, buf - len, to - len, len);
1541 ONENAND_SET_BUFFERRAM1(this); 1562 if (ret)
1542 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); 1563 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1543 } 1564 break;
1565 }
1544 1566
1545 if (ret) { 1567 ONENAND_SET_NEXT_BUFFERRAM(this);
1546 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1547 break;
1548 } 1568 }
1549 1569
1550 /* Only check verify write turn on */ 1570 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1551 ret = onenand_verify(mtd, buf, to, thislen);
1552 if (ret) {
1553 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1554 break;
1555 }
1556 1571
1557 written += thislen; 1572 /*
1573 * 2 PLANE, MLC, and Flex-OneNAND wait here
1574 */
1575 if (ONENAND_IS_2PLANE(this)) {
1576 ret = this->wait(mtd, FL_WRITING);
1558 1577
1559 if (written == len) 1578 /* In partial page write we don't update bufferram */
1560 break; 1579 onenand_update_bufferram(mtd, to, !ret && !subpage);
1580 if (ret) {
1581 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1582 break;
1583 }
1584
1585 /* Only check verify write turn on */
1586 ret = onenand_verify(mtd, buf, to, thislen);
1587 if (ret) {
1588 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1589 break;
1590 }
1591
1592 written += thislen;
1593
1594 if (written == len)
1595 break;
1596
1597 } else
1598 written += thislen;
1561 1599
1562 column = 0; 1600 column = 0;
1601 prev_subpage = subpage;
1602 prev = to;
1603 prevlen = thislen;
1563 to += thislen; 1604 to += thislen;
1564 buf += thislen; 1605 buf += thislen;
1606 first = 0;
1565 } 1607 }
1566 1608
1609 /* In error case, clear all bufferrams */
1610 if (written != len)
1611 onenand_invalidate_bufferram(mtd, 0, -1);
1612
1567 ops->retlen = written; 1613 ops->retlen = written;
1614 ops->oobretlen = oobwritten;
1568 1615
1569 return ret; 1616 return ret;
1570} 1617}