aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-03-04 15:01:36 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-03-20 08:27:43 -0400
commit52ff49df7fab18e56fa31b43143c4150c2547836 (patch)
treed796944bf50cec952789ae384f7ea3247d691634 /drivers/mtd
parentc6d59cdd412e1ae34ad9c8dc69eaabada792f7ae (diff)
[MTD] [NAND] fix "raw" reads with ECC syndrome layouts
The syndrome based page read/write routines store ECC, and possibly other "OOB" data, right after each chunk of ECC'd data. With ECC chunk size of 512 bytes and a large page (2KiB) NAND, the layout is: data-0 OOB-0 data-1 OOB-1 data-2 OOB-2 data-3 OOB-3 OOB-leftover Where OOBx is (prepad, ECC, postpad). However, the current "raw" routines use a traditional layout -- data OOB, disregarding the prepad and postpad values -- so when they're used with that type of ECC hardware, those calls mix up the data and OOB. Which means, in particular, that bad block tables won't be found on startup, with data corruption and related chaos ensuing. The current syndrome-based drivers in mainline all seem to use one chunk per page; presumably they haven't noticed such bugs. Fix this, by adding read/write page_raw_syndrome() routines as siblings of the existing non-raw routines; "raw" just means to bypass the ECC computations, not change data and OOB layout. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/nand_base.c99
1 files changed, 95 insertions, 4 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0c3afccde8a2..d902370df3e0 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -748,6 +748,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
748 * @mtd: mtd info structure 748 * @mtd: mtd info structure
749 * @chip: nand chip info structure 749 * @chip: nand chip info structure
750 * @buf: buffer to store read data 750 * @buf: buffer to store read data
751 *
752 * Not for syndrome calculating ecc controllers, which use a special oob layout
751 */ 753 */
752static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, 754static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
753 uint8_t *buf) 755 uint8_t *buf)
@@ -758,6 +760,47 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
758} 760}
759 761
760/** 762/**
763 * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc
764 * @mtd: mtd info structure
765 * @chip: nand chip info structure
766 * @buf: buffer to store read data
767 *
768 * We need a special oob layout and handling even when OOB isn't used.
769 */
770static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
771 uint8_t *buf)
772{
773 int eccsize = chip->ecc.size;
774 int eccbytes = chip->ecc.bytes;
775 uint8_t *oob = chip->oob_poi;
776 int steps, size;
777
778 for (steps = chip->ecc.steps; steps > 0; steps--) {
779 chip->read_buf(mtd, buf, eccsize);
780 buf += eccsize;
781
782 if (chip->ecc.prepad) {
783 chip->read_buf(mtd, oob, chip->ecc.prepad);
784 oob += chip->ecc.prepad;
785 }
786
787 chip->read_buf(mtd, oob, eccbytes);
788 oob += eccbytes;
789
790 if (chip->ecc.postpad) {
791 chip->read_buf(mtd, oob, chip->ecc.postpad);
792 oob += chip->ecc.postpad;
793 }
794 }
795
796 size = mtd->oobsize - (oob - chip->oob_poi);
797 if (size)
798 chip->read_buf(mtd, oob, size);
799
800 return 0;
801}
802
803/**
761 * nand_read_page_swecc - [REPLACABLE] software ecc based page read function 804 * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
762 * @mtd: mtd info structure 805 * @mtd: mtd info structure
763 * @chip: nand chip info structure 806 * @chip: nand chip info structure
@@ -1482,6 +1525,8 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
1482 * @mtd: mtd info structure 1525 * @mtd: mtd info structure
1483 * @chip: nand chip info structure 1526 * @chip: nand chip info structure
1484 * @buf: data buffer 1527 * @buf: data buffer
1528 *
1529 * Not for syndrome calculating ecc controllers, which use a special oob layout
1485 */ 1530 */
1486static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, 1531static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
1487 const uint8_t *buf) 1532 const uint8_t *buf)
@@ -1491,6 +1536,44 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
1491} 1536}
1492 1537
1493/** 1538/**
1539 * nand_write_page_raw_syndrome - [Intern] raw page write function
1540 * @mtd: mtd info structure
1541 * @chip: nand chip info structure
1542 * @buf: data buffer
1543 *
1544 * We need a special oob layout and handling even when ECC isn't checked.
1545 */
1546static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
1547 const uint8_t *buf)
1548{
1549 int eccsize = chip->ecc.size;
1550 int eccbytes = chip->ecc.bytes;
1551 uint8_t *oob = chip->oob_poi;
1552 int steps, size;
1553
1554 for (steps = chip->ecc.steps; steps > 0; steps--) {
1555 chip->write_buf(mtd, buf, eccsize);
1556 buf += eccsize;
1557
1558 if (chip->ecc.prepad) {
1559 chip->write_buf(mtd, oob, chip->ecc.prepad);
1560 oob += chip->ecc.prepad;
1561 }
1562
1563 chip->read_buf(mtd, oob, eccbytes);
1564 oob += eccbytes;
1565
1566 if (chip->ecc.postpad) {
1567 chip->write_buf(mtd, oob, chip->ecc.postpad);
1568 oob += chip->ecc.postpad;
1569 }
1570 }
1571
1572 size = mtd->oobsize - (oob - chip->oob_poi);
1573 if (size)
1574 chip->write_buf(mtd, oob, size);
1575}
1576/**
1494 * nand_write_page_swecc - [REPLACABLE] software ecc based page write function 1577 * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
1495 * @mtd: mtd info structure 1578 * @mtd: mtd info structure
1496 * @chip: nand chip info structure 1579 * @chip: nand chip info structure
@@ -2569,10 +2652,6 @@ int nand_scan_tail(struct mtd_info *mtd)
2569 * check ECC mode, default to software if 3byte/512byte hardware ECC is 2652 * check ECC mode, default to software if 3byte/512byte hardware ECC is
2570 * selected and we have 256 byte pagesize fallback to software ECC 2653 * selected and we have 256 byte pagesize fallback to software ECC
2571 */ 2654 */
2572 if (!chip->ecc.read_page_raw)
2573 chip->ecc.read_page_raw = nand_read_page_raw;
2574 if (!chip->ecc.write_page_raw)
2575 chip->ecc.write_page_raw = nand_write_page_raw;
2576 2655
2577 switch (chip->ecc.mode) { 2656 switch (chip->ecc.mode) {
2578 case NAND_ECC_HW: 2657 case NAND_ECC_HW:
@@ -2581,6 +2660,10 @@ int nand_scan_tail(struct mtd_info *mtd)
2581 chip->ecc.read_page = nand_read_page_hwecc; 2660 chip->ecc.read_page = nand_read_page_hwecc;
2582 if (!chip->ecc.write_page) 2661 if (!chip->ecc.write_page)
2583 chip->ecc.write_page = nand_write_page_hwecc; 2662 chip->ecc.write_page = nand_write_page_hwecc;
2663 if (!chip->ecc.read_page_raw)
2664 chip->ecc.read_page_raw = nand_read_page_raw;
2665 if (!chip->ecc.write_page_raw)
2666 chip->ecc.write_page_raw = nand_write_page_raw;
2584 if (!chip->ecc.read_oob) 2667 if (!chip->ecc.read_oob)
2585 chip->ecc.read_oob = nand_read_oob_std; 2668 chip->ecc.read_oob = nand_read_oob_std;
2586 if (!chip->ecc.write_oob) 2669 if (!chip->ecc.write_oob)
@@ -2602,6 +2685,10 @@ int nand_scan_tail(struct mtd_info *mtd)
2602 chip->ecc.read_page = nand_read_page_syndrome; 2685 chip->ecc.read_page = nand_read_page_syndrome;
2603 if (!chip->ecc.write_page) 2686 if (!chip->ecc.write_page)
2604 chip->ecc.write_page = nand_write_page_syndrome; 2687 chip->ecc.write_page = nand_write_page_syndrome;
2688 if (!chip->ecc.read_page_raw)
2689 chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
2690 if (!chip->ecc.write_page_raw)
2691 chip->ecc.write_page_raw = nand_write_page_raw_syndrome;
2605 if (!chip->ecc.read_oob) 2692 if (!chip->ecc.read_oob)
2606 chip->ecc.read_oob = nand_read_oob_syndrome; 2693 chip->ecc.read_oob = nand_read_oob_syndrome;
2607 if (!chip->ecc.write_oob) 2694 if (!chip->ecc.write_oob)
@@ -2620,6 +2707,8 @@ int nand_scan_tail(struct mtd_info *mtd)
2620 chip->ecc.read_page = nand_read_page_swecc; 2707 chip->ecc.read_page = nand_read_page_swecc;
2621 chip->ecc.read_subpage = nand_read_subpage; 2708 chip->ecc.read_subpage = nand_read_subpage;
2622 chip->ecc.write_page = nand_write_page_swecc; 2709 chip->ecc.write_page = nand_write_page_swecc;
2710 chip->ecc.read_page_raw = nand_read_page_raw;
2711 chip->ecc.write_page_raw = nand_write_page_raw;
2623 chip->ecc.read_oob = nand_read_oob_std; 2712 chip->ecc.read_oob = nand_read_oob_std;
2624 chip->ecc.write_oob = nand_write_oob_std; 2713 chip->ecc.write_oob = nand_write_oob_std;
2625 chip->ecc.size = 256; 2714 chip->ecc.size = 256;
@@ -2632,6 +2721,8 @@ int nand_scan_tail(struct mtd_info *mtd)
2632 chip->ecc.read_page = nand_read_page_raw; 2721 chip->ecc.read_page = nand_read_page_raw;
2633 chip->ecc.write_page = nand_write_page_raw; 2722 chip->ecc.write_page = nand_write_page_raw;
2634 chip->ecc.read_oob = nand_read_oob_std; 2723 chip->ecc.read_oob = nand_read_oob_std;
2724 chip->ecc.read_page_raw = nand_read_page_raw;
2725 chip->ecc.write_page_raw = nand_write_page_raw;
2635 chip->ecc.write_oob = nand_write_oob_std; 2726 chip->ecc.write_oob = nand_write_oob_std;
2636 chip->ecc.size = mtd->writesize; 2727 chip->ecc.size = mtd->writesize;
2637 chip->ecc.bytes = 0; 2728 chip->ecc.bytes = 0;