aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorRobert Jarzmik <robert.jarzmik@free.fr>2011-11-19 10:02:55 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-01-09 13:07:26 -0500
commitd13d19ece39f20bf097782e1812a9c31a5a4fcf1 (patch)
tree8ea5f606a95f7e3761e55945f247c818dfb0dfc0 /drivers/mtd
parent7a7fcf14021bc0f0728dd0aaa2635475de0db54c (diff)
mtd: docg3: add ECC correction code
Credit for discovering the BCH algorith parameters, and bit reversing algorithm is to be give to Mike Dunn and Ivan Djelic. The BCH correction code relied upon the BCH library, where all data and ECC is bit-reversed. The BCH library works correctly when each input byte is bit-reversed, and accordingly ECC output is also bit-reversed. Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Reviewed-by: Ivan Djelic <ivan.djelic@parrot.com> Reviewed-by: Mike Dunn <mikedunn@newsguy.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/Kconfig9
-rw-r--r--drivers/mtd/devices/docg3.c116
-rw-r--r--drivers/mtd/devices/docg3.h11
3 files changed, 113 insertions, 23 deletions
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 283d887f7825..952e956ef01d 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -251,6 +251,8 @@ config MTD_DOC2001PLUS
251 251
252config MTD_DOCG3 252config MTD_DOCG3
253 tristate "M-Systems Disk-On-Chip G3" 253 tristate "M-Systems Disk-On-Chip G3"
254 select BCH
255 select BCH_CONST_PARAMS
254 ---help--- 256 ---help---
255 This provides an MTD device driver for the M-Systems DiskOnChip 257 This provides an MTD device driver for the M-Systems DiskOnChip
256 G3 devices. 258 G3 devices.
@@ -259,6 +261,13 @@ config MTD_DOCG3
259 M-Systems and now Sandisk. The support is very experimental, 261 M-Systems and now Sandisk. The support is very experimental,
260 and doesn't give access to any write operations. 262 and doesn't give access to any write operations.
261 263
264if MTD_DOCG3
265config BCH_CONST_M
266 default 14
267config BCH_CONST_T
268 default 4
269endif
270
262config MTD_DOCPROBE 271config MTD_DOCPROBE
263 tristate 272 tristate
264 select MTD_DOCECC 273 select MTD_DOCECC
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 1f949eac6351..26cc17909b16 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -29,6 +29,9 @@
29#include <linux/delay.h> 29#include <linux/delay.h>
30#include <linux/mtd/mtd.h> 30#include <linux/mtd/mtd.h>
31#include <linux/mtd/partitions.h> 31#include <linux/mtd/partitions.h>
32#include <linux/bitmap.h>
33#include <linux/bitrev.h>
34#include <linux/bch.h>
32 35
33#include <linux/debugfs.h> 36#include <linux/debugfs.h>
34#include <linux/seq_file.h> 37#include <linux/seq_file.h>
@@ -42,7 +45,6 @@
42 * As no specification is available from M-Systems/Sandisk, this drivers lacks 45 * As no specification is available from M-Systems/Sandisk, this drivers lacks
43 * several functions available on the chip, as : 46 * several functions available on the chip, as :
44 * - IPL write 47 * - IPL write
45 * - ECC fixing (lack of BCH algorith understanding)
46 * - powerdown / powerup 48 * - powerdown / powerup
47 * 49 *
48 * The bus data width (8bits versus 16bits) is not handled (if_cfg flag), and 50 * The bus data width (8bits versus 16bits) is not handled (if_cfg flag), and
@@ -51,8 +53,7 @@
51 * DocG3 relies on 2 ECC algorithms, which are handled in hardware : 53 * DocG3 relies on 2 ECC algorithms, which are handled in hardware :
52 * - a 1 byte Hamming code stored in the OOB for each page 54 * - a 1 byte Hamming code stored in the OOB for each page
53 * - a 7 bytes BCH code stored in the OOB for each page 55 * - a 7 bytes BCH code stored in the OOB for each page
54 * The BCH part is only used for check purpose, no correction is available as 56 * The BCH ECC is :
55 * some information is missing. What is known is that :
56 * - BCH is in GF(2^14) 57 * - BCH is in GF(2^14)
57 * - BCH is over data of 520 bytes (512 page + 7 page_info bytes 58 * - BCH is over data of 520 bytes (512 page + 7 page_info bytes
58 * + 1 hamming byte) 59 * + 1 hamming byte)
@@ -75,6 +76,11 @@ static struct nand_ecclayout docg3_oobinfo = {
75 .oobavail = 8, 76 .oobavail = 8,
76}; 77};
77 78
79/**
80 * struct docg3_bch - BCH engine
81 */
82static struct bch_control *docg3_bch;
83
78static inline u8 doc_readb(struct docg3 *docg3, u16 reg) 84static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
79{ 85{
80 u8 val = readb(docg3->base + reg); 86 u8 val = readb(docg3->base + reg);
@@ -582,6 +588,54 @@ static void doc_hamming_ecc_init(struct docg3 *docg3, int nb_bytes)
582} 588}
583 589
584/** 590/**
591 * doc_correct_data - Fix if need be read data from flash
592 * @docg3: the device
593 * @buf: the buffer of read data (512 + 7 + 1 bytes)
594 * @hwecc: the hardware calculated ECC.
595 * It's in fact recv_ecc ^ calc_ecc, where recv_ecc was read from OOB
596 * area data, and calc_ecc the ECC calculated by the hardware generator.
597 *
598 * Checks if the received data matches the ECC, and if an error is detected,
599 * tries to fix the bit flips (at most 4) in the buffer buf. As the docg3
600 * understands the (data, ecc, syndroms) in an inverted order in comparison to
601 * the BCH library, the function reverses the order of bits (ie. bit7 and bit0,
602 * bit6 and bit 1, ...) for all ECC data.
603 *
604 * The hardware ecc unit produces oob_ecc ^ calc_ecc. The kernel's bch
605 * algorithm is used to decode this. However the hw operates on page
606 * data in a bit order that is the reverse of that of the bch alg,
607 * requiring that the bits be reversed on the result. Thanks to Ivan
608 * Djelic for his analysis.
609 *
610 * Returns number of fixed bits (0, 1, 2, 3, 4) or -EBADMSG if too many bit
611 * errors were detected and cannot be fixed.
612 */
613static int doc_ecc_bch_fix_data(struct docg3 *docg3, void *buf, u8 *hwecc)
614{
615 u8 ecc[DOC_ECC_BCH_SIZE];
616 int errorpos[DOC_ECC_BCH_T], i, numerrs;
617
618 for (i = 0; i < DOC_ECC_BCH_SIZE; i++)
619 ecc[i] = bitrev8(hwecc[i]);
620 numerrs = decode_bch(docg3_bch, NULL, DOC_ECC_BCH_COVERED_BYTES,
621 NULL, ecc, NULL, errorpos);
622 BUG_ON(numerrs == -EINVAL);
623 if (numerrs < 0)
624 goto out;
625
626 for (i = 0; i < numerrs; i++)
627 errorpos[i] = (errorpos[i] & ~7) | (7 - (errorpos[i] & 7));
628 for (i = 0; i < numerrs; i++)
629 if (errorpos[i] < DOC_ECC_BCH_COVERED_BYTES*8)
630 /* error is located in data, correct it */
631 change_bit(errorpos[i], buf);
632out:
633 doc_dbg("doc_ecc_bch_fix_data: flipped %d bits\n", numerrs);
634 return numerrs;
635}
636
637
638/**
585 * doc_read_page_prepare - Prepares reading data from a flash page 639 * doc_read_page_prepare - Prepares reading data from a flash page
586 * @docg3: the device 640 * @docg3: the device
587 * @block0: the first plane block index on flash memory 641 * @block0: the first plane block index on flash memory
@@ -762,7 +816,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
762 u8 *oobbuf = ops->oobbuf; 816 u8 *oobbuf = ops->oobbuf;
763 u8 *buf = ops->datbuf; 817 u8 *buf = ops->datbuf;
764 size_t len, ooblen, nbdata, nboob; 818 size_t len, ooblen, nbdata, nboob;
765 u8 calc_ecc[DOC_ECC_BCH_SIZE], eccconf1; 819 u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1;
766 820
767 if (buf) 821 if (buf)
768 len = ops->len; 822 len = ops->len;
@@ -797,7 +851,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
797 ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); 851 ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
798 if (ret < 0) 852 if (ret < 0)
799 goto err; 853 goto err;
800 ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_COVERED_BYTES); 854 ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
801 if (ret < 0) 855 if (ret < 0)
802 goto err_in_read; 856 goto err_in_read;
803 ret = doc_read_page_getbytes(docg3, nbdata, buf, 1); 857 ret = doc_read_page_getbytes(docg3, nbdata, buf, 1);
@@ -811,7 +865,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
811 doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, 865 doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob,
812 NULL, 0); 866 NULL, 0);
813 867
814 doc_get_hw_bch_syndroms(docg3, calc_ecc); 868 doc_get_hw_bch_syndroms(docg3, hwecc);
815 eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); 869 eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1);
816 870
817 if (nboob >= DOC_LAYOUT_OOB_SIZE) { 871 if (nboob >= DOC_LAYOUT_OOB_SIZE) {
@@ -825,18 +879,28 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
825 doc_dbg("OOB - UNUSED: %02x\n", oobbuf[15]); 879 doc_dbg("OOB - UNUSED: %02x\n", oobbuf[15]);
826 } 880 }
827 doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1); 881 doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1);
828 doc_dbg("ECC CALC_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 882 doc_dbg("ECC HW_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
829 calc_ecc[0], calc_ecc[1], calc_ecc[2], 883 hwecc[0], hwecc[1], hwecc[2], hwecc[3], hwecc[4],
830 calc_ecc[3], calc_ecc[4], calc_ecc[5], 884 hwecc[5], hwecc[6]);
831 calc_ecc[6]); 885
832 886 ret = -EIO;
833 ret = -EBADMSG; 887 if (is_prot_seq_error(docg3))
834 if (block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) { 888 goto err_in_read;
835 if ((eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) && 889 ret = 0;
836 (eccconf1 & DOC_ECCCONF1_PAGE_IS_WRITTEN)) 890 if ((block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) &&
837 goto err_in_read; 891 (eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) &&
838 if (is_prot_seq_error(docg3)) 892 (eccconf1 & DOC_ECCCONF1_PAGE_IS_WRITTEN) &&
839 goto err_in_read; 893 (ops->mode != MTD_OPS_RAW) &&
894 (nbdata == DOC_LAYOUT_PAGE_SIZE)) {
895 ret = doc_ecc_bch_fix_data(docg3, buf, hwecc);
896 if (ret < 0) {
897 mtd->ecc_stats.failed++;
898 ret = -EBADMSG;
899 }
900 if (ret > 0) {
901 mtd->ecc_stats.corrected += ret;
902 ret = -EUCLEAN;
903 }
840 } 904 }
841 905
842 doc_read_page_finish(docg3); 906 doc_read_page_finish(docg3);
@@ -849,7 +913,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
849 from += DOC_LAYOUT_PAGE_SIZE; 913 from += DOC_LAYOUT_PAGE_SIZE;
850 } 914 }
851 915
852 return 0; 916 return ret;
853err_in_read: 917err_in_read:
854 doc_read_page_finish(docg3); 918 doc_read_page_finish(docg3);
855err: 919err:
@@ -1158,7 +1222,7 @@ static int doc_write_page(struct docg3 *docg3, loff_t to, const u_char *buf,
1158 if (ret) 1222 if (ret)
1159 goto err; 1223 goto err;
1160 1224
1161 doc_write_page_ecc_init(docg3, DOC_ECC_BCH_COVERED_BYTES); 1225 doc_write_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
1162 doc_delay(docg3, 2); 1226 doc_delay(docg3, 2);
1163 doc_write_page_putbytes(docg3, DOC_LAYOUT_PAGE_SIZE, buf); 1227 doc_write_page_putbytes(docg3, DOC_LAYOUT_PAGE_SIZE, buf);
1164 1228
@@ -1721,7 +1785,11 @@ static int __init docg3_probe(struct platform_device *pdev)
1721 docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS, 1785 docg3_floors = kzalloc(sizeof(*docg3_floors) * DOC_MAX_NBFLOORS,
1722 GFP_KERNEL); 1786 GFP_KERNEL);
1723 if (!docg3_floors) 1787 if (!docg3_floors)
1724 goto nomem; 1788 goto nomem1;
1789 docg3_bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
1790 DOC_ECC_BCH_PRIMPOLY);
1791 if (!docg3_bch)
1792 goto nomem2;
1725 1793
1726 ret = 0; 1794 ret = 0;
1727 for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { 1795 for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
@@ -1751,10 +1819,13 @@ notfound:
1751 ret = -ENODEV; 1819 ret = -ENODEV;
1752 dev_info(dev, "No supported DiskOnChip found\n"); 1820 dev_info(dev, "No supported DiskOnChip found\n");
1753err_probe: 1821err_probe:
1822 free_bch(docg3_bch);
1754 for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) 1823 for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
1755 if (docg3_floors[floor]) 1824 if (docg3_floors[floor])
1756 doc_release_device(docg3_floors[floor]); 1825 doc_release_device(docg3_floors[floor]);
1757nomem: 1826nomem2:
1827 kfree(docg3_floors);
1828nomem1:
1758 iounmap(base); 1829 iounmap(base);
1759noress: 1830noress:
1760 return ret; 1831 return ret;
@@ -1779,6 +1850,7 @@ static int __exit docg3_release(struct platform_device *pdev)
1779 doc_release_device(docg3_floors[floor]); 1850 doc_release_device(docg3_floors[floor]);
1780 1851
1781 kfree(docg3_floors); 1852 kfree(docg3_floors);
1853 free_bch(docg3_bch);
1782 iounmap(base); 1854 iounmap(base);
1783 return 0; 1855 return 0;
1784} 1856}
diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h
index 397e4616796e..33db7272c460 100644
--- a/drivers/mtd/devices/docg3.h
+++ b/drivers/mtd/devices/docg3.h
@@ -51,10 +51,19 @@
51#define DOC_LAYOUT_WEAR_OFFSET (DOC_LAYOUT_PAGE_OOB_SIZE * 2) 51#define DOC_LAYOUT_WEAR_OFFSET (DOC_LAYOUT_PAGE_OOB_SIZE * 2)
52#define DOC_LAYOUT_BLOCK_SIZE \ 52#define DOC_LAYOUT_BLOCK_SIZE \
53 (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_PAGE_SIZE) 53 (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_PAGE_SIZE)
54
55/*
56 * ECC related constants
57 */
58#define DOC_ECC_BCH_M 14
59#define DOC_ECC_BCH_T 4
60#define DOC_ECC_BCH_PRIMPOLY 0x4443
54#define DOC_ECC_BCH_SIZE 7 61#define DOC_ECC_BCH_SIZE 7
55#define DOC_ECC_BCH_COVERED_BYTES \ 62#define DOC_ECC_BCH_COVERED_BYTES \
56 (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_PAGEINFO_SZ + \ 63 (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_PAGEINFO_SZ + \
57 DOC_LAYOUT_OOB_HAMMING_SZ + DOC_LAYOUT_OOB_BCH_SZ) 64 DOC_LAYOUT_OOB_HAMMING_SZ)
65#define DOC_ECC_BCH_TOTAL_BYTES \
66 (DOC_ECC_BCH_COVERED_BYTES + DOC_LAYOUT_OOB_BCH_SZ)
58 67
59/* 68/*
60 * Blocks distribution 69 * Blocks distribution