aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/nand/Kconfig15
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/nand_base.c40
-rw-r--r--drivers/mtd/nand/nand_bch.c243
-rw-r--r--include/linux/mtd/nand.h3
-rw-r--r--include/linux/mtd/nand_bch.h72
6 files changed, 373 insertions, 1 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index c89592239bc7..78205ac2b10f 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -31,6 +31,21 @@ config MTD_NAND_VERIFY_WRITE
31 device thinks the write was successful, a bit could have been 31 device thinks the write was successful, a bit could have been
32 flipped accidentally due to device wear or something else. 32 flipped accidentally due to device wear or something else.
33 33
34config MTD_NAND_BCH
35 tristate
36 select BCH
37 depends on MTD_NAND_ECC_BCH
38 default MTD_NAND
39
40config MTD_NAND_ECC_BCH
41 bool "Support software BCH ECC"
42 default n
43 help
44 This enables support for software BCH error correction. Binary BCH
45 codes are more powerful and cpu intensive than traditional Hamming
46 ECC codes. They are used with NAND devices requiring more than 1 bit
47 of error correction.
48
34config MTD_SM_COMMON 49config MTD_SM_COMMON
35 tristate 50 tristate
36 default n 51 default n
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 8ad6faec72cb..5745d831168e 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -4,6 +4,7 @@
4 4
5obj-$(CONFIG_MTD_NAND) += nand.o 5obj-$(CONFIG_MTD_NAND) += nand.o
6obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o 6obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
7obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
7obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o 8obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
8obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o 9obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
9 10
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index da7604050347..85cfc061d41c 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -42,6 +42,7 @@
42#include <linux/mtd/mtd.h> 42#include <linux/mtd/mtd.h>
43#include <linux/mtd/nand.h> 43#include <linux/mtd/nand.h>
44#include <linux/mtd/nand_ecc.h> 44#include <linux/mtd/nand_ecc.h>
45#include <linux/mtd/nand_bch.h>
45#include <linux/interrupt.h> 46#include <linux/interrupt.h>
46#include <linux/bitops.h> 47#include <linux/bitops.h>
47#include <linux/leds.h> 48#include <linux/leds.h>
@@ -3248,7 +3249,7 @@ int nand_scan_tail(struct mtd_info *mtd)
3248 /* 3249 /*
3249 * If no default placement scheme is given, select an appropriate one 3250 * If no default placement scheme is given, select an appropriate one
3250 */ 3251 */
3251 if (!chip->ecc.layout) { 3252 if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
3252 switch (mtd->oobsize) { 3253 switch (mtd->oobsize) {
3253 case 8: 3254 case 8:
3254 chip->ecc.layout = &nand_oob_8; 3255 chip->ecc.layout = &nand_oob_8;
@@ -3351,6 +3352,40 @@ int nand_scan_tail(struct mtd_info *mtd)
3351 chip->ecc.bytes = 3; 3352 chip->ecc.bytes = 3;
3352 break; 3353 break;
3353 3354
3355 case NAND_ECC_SOFT_BCH:
3356 if (!mtd_nand_has_bch()) {
3357 printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n");
3358 BUG();
3359 }
3360 chip->ecc.calculate = nand_bch_calculate_ecc;
3361 chip->ecc.correct = nand_bch_correct_data;
3362 chip->ecc.read_page = nand_read_page_swecc;
3363 chip->ecc.read_subpage = nand_read_subpage;
3364 chip->ecc.write_page = nand_write_page_swecc;
3365 chip->ecc.read_page_raw = nand_read_page_raw;
3366 chip->ecc.write_page_raw = nand_write_page_raw;
3367 chip->ecc.read_oob = nand_read_oob_std;
3368 chip->ecc.write_oob = nand_write_oob_std;
3369 /*
3370 * Board driver should supply ecc.size and ecc.bytes values to
3371 * select how many bits are correctable; see nand_bch_init()
3372 * for details.
3373 * Otherwise, default to 4 bits for large page devices
3374 */
3375 if (!chip->ecc.size && (mtd->oobsize >= 64)) {
3376 chip->ecc.size = 512;
3377 chip->ecc.bytes = 7;
3378 }
3379 chip->ecc.priv = nand_bch_init(mtd,
3380 chip->ecc.size,
3381 chip->ecc.bytes,
3382 &chip->ecc.layout);
3383 if (!chip->ecc.priv) {
3384 printk(KERN_WARNING "BCH ECC initialization failed!\n");
3385 BUG();
3386 }
3387 break;
3388
3354 case NAND_ECC_NONE: 3389 case NAND_ECC_NONE:
3355 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " 3390 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
3356 "This is not recommended !!\n"); 3391 "This is not recommended !!\n");
@@ -3501,6 +3536,9 @@ void nand_release(struct mtd_info *mtd)
3501{ 3536{
3502 struct nand_chip *chip = mtd->priv; 3537 struct nand_chip *chip = mtd->priv;
3503 3538
3539 if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
3540 nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
3541
3504#ifdef CONFIG_MTD_PARTITIONS 3542#ifdef CONFIG_MTD_PARTITIONS
3505 /* Deregister partitions */ 3543 /* Deregister partitions */
3506 del_mtd_partitions(mtd); 3544 del_mtd_partitions(mtd);
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
new file mode 100644
index 000000000000..0f931e757116
--- /dev/null
+++ b/drivers/mtd/nand/nand_bch.c
@@ -0,0 +1,243 @@
1/*
2 * This file provides ECC correction for more than 1 bit per block of data,
3 * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
4 *
5 * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
6 *
7 * This file is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 or (at your option) any
10 * later version.
11 *
12 * This file is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this file; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 */
21
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/slab.h>
26#include <linux/bitops.h>
27#include <linux/mtd/mtd.h>
28#include <linux/mtd/nand.h>
29#include <linux/mtd/nand_bch.h>
30#include <linux/bch.h>
31
32/**
33 * struct nand_bch_control - private NAND BCH control structure
34 * @bch: BCH control structure
35 * @ecclayout: private ecc layout for this BCH configuration
36 * @errloc: error location array
37 * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
38 */
39struct nand_bch_control {
40 struct bch_control *bch;
41 struct nand_ecclayout ecclayout;
42 unsigned int *errloc;
43 unsigned char *eccmask;
44};
45
46/**
47 * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
48 * @mtd: MTD block structure
49 * @buf: input buffer with raw data
50 * @code: output buffer with ECC
51 */
52int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
53 unsigned char *code)
54{
55 const struct nand_chip *chip = mtd->priv;
56 struct nand_bch_control *nbc = chip->ecc.priv;
57 unsigned int i;
58
59 memset(code, 0, chip->ecc.bytes);
60 encode_bch(nbc->bch, buf, chip->ecc.size, code);
61
62 /* apply mask so that an erased page is a valid codeword */
63 for (i = 0; i < chip->ecc.bytes; i++)
64 code[i] ^= nbc->eccmask[i];
65
66 return 0;
67}
68EXPORT_SYMBOL(nand_bch_calculate_ecc);
69
70/**
71 * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
72 * @mtd: MTD block structure
73 * @buf: raw data read from the chip
74 * @read_ecc: ECC from the chip
75 * @calc_ecc: the ECC calculated from raw data
76 *
77 * Detect and correct bit errors for a data byte block
78 */
79int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
80 unsigned char *read_ecc, unsigned char *calc_ecc)
81{
82 const struct nand_chip *chip = mtd->priv;
83 struct nand_bch_control *nbc = chip->ecc.priv;
84 unsigned int *errloc = nbc->errloc;
85 int i, count;
86
87 count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
88 NULL, errloc);
89 if (count > 0) {
90 for (i = 0; i < count; i++) {
91 if (errloc[i] < (chip->ecc.size*8))
92 /* error is located in data, correct it */
93 buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
94 /* else error in ecc, no action needed */
95
96 DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n",
97 __func__, errloc[i]);
98 }
99 } else if (count < 0) {
100 printk(KERN_ERR "ecc unrecoverable error\n");
101 count = -1;
102 }
103 return count;
104}
105EXPORT_SYMBOL(nand_bch_correct_data);
106
107/**
108 * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
109 * @mtd: MTD block structure
110 * @eccsize: ecc block size in bytes
111 * @eccbytes: ecc length in bytes
112 * @ecclayout: output default layout
113 *
114 * Returns:
115 * a pointer to a new NAND BCH control structure, or NULL upon failure
116 *
117 * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
118 * are used to compute BCH parameters m (Galois field order) and t (error
119 * correction capability). @eccbytes should be equal to the number of bytes
120 * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
121 *
122 * Example: to configure 4 bit correction per 512 bytes, you should pass
123 * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
124 * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
125 */
126struct nand_bch_control *
127nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
128 struct nand_ecclayout **ecclayout)
129{
130 unsigned int m, t, eccsteps, i;
131 struct nand_ecclayout *layout;
132 struct nand_bch_control *nbc = NULL;
133 unsigned char *erased_page;
134
135 if (!eccsize || !eccbytes) {
136 printk(KERN_WARNING "ecc parameters not supplied\n");
137 goto fail;
138 }
139
140 m = fls(1+8*eccsize);
141 t = (eccbytes*8)/m;
142
143 nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
144 if (!nbc)
145 goto fail;
146
147 nbc->bch = init_bch(m, t, 0);
148 if (!nbc->bch)
149 goto fail;
150
151 /* verify that eccbytes has the expected value */
152 if (nbc->bch->ecc_bytes != eccbytes) {
153 printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
154 eccbytes, nbc->bch->ecc_bytes);
155 goto fail;
156 }
157
158 eccsteps = mtd->writesize/eccsize;
159
160 /* if no ecc placement scheme was provided, build one */
161 if (!*ecclayout) {
162
163 /* handle large page devices only */
164 if (mtd->oobsize < 64) {
165 printk(KERN_WARNING "must provide an oob scheme for "
166 "oobsize %d\n", mtd->oobsize);
167 goto fail;
168 }
169
170 layout = &nbc->ecclayout;
171 layout->eccbytes = eccsteps*eccbytes;
172
173 /* reserve 2 bytes for bad block marker */
174 if (layout->eccbytes+2 > mtd->oobsize) {
175 printk(KERN_WARNING "no suitable oob scheme available "
176 "for oobsize %d eccbytes %u\n", mtd->oobsize,
177 eccbytes);
178 goto fail;
179 }
180 /* put ecc bytes at oob tail */
181 for (i = 0; i < layout->eccbytes; i++)
182 layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
183
184 layout->oobfree[0].offset = 2;
185 layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
186
187 *ecclayout = layout;
188 }
189
190 /* sanity checks */
191 if (8*(eccsize+eccbytes) >= (1 << m)) {
192 printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
193 goto fail;
194 }
195 if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
196 printk(KERN_WARNING "invalid ecc layout\n");
197 goto fail;
198 }
199
200 nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
201 nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
202 if (!nbc->eccmask || !nbc->errloc)
203 goto fail;
204 /*
205 * compute and store the inverted ecc of an erased ecc block
206 */
207 erased_page = kmalloc(eccsize, GFP_KERNEL);
208 if (!erased_page)
209 goto fail;
210
211 memset(erased_page, 0xff, eccsize);
212 memset(nbc->eccmask, 0, eccbytes);
213 encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
214 kfree(erased_page);
215
216 for (i = 0; i < eccbytes; i++)
217 nbc->eccmask[i] ^= 0xff;
218
219 return nbc;
220fail:
221 nand_bch_free(nbc);
222 return NULL;
223}
224EXPORT_SYMBOL(nand_bch_init);
225
226/**
227 * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
228 * @nbc: NAND BCH control structure
229 */
230void nand_bch_free(struct nand_bch_control *nbc)
231{
232 if (nbc) {
233 free_bch(nbc->bch);
234 kfree(nbc->errloc);
235 kfree(nbc->eccmask);
236 kfree(nbc);
237 }
238}
239EXPORT_SYMBOL(nand_bch_free);
240
241MODULE_LICENSE("GPL");
242MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
243MODULE_DESCRIPTION("NAND software BCH ECC support");
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 1f489b247a29..ae67ef56a8f5 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -140,6 +140,7 @@ typedef enum {
140 NAND_ECC_HW, 140 NAND_ECC_HW,
141 NAND_ECC_HW_SYNDROME, 141 NAND_ECC_HW_SYNDROME,
142 NAND_ECC_HW_OOB_FIRST, 142 NAND_ECC_HW_OOB_FIRST,
143 NAND_ECC_SOFT_BCH,
143} nand_ecc_modes_t; 144} nand_ecc_modes_t;
144 145
145/* 146/*
@@ -339,6 +340,7 @@ struct nand_hw_control {
339 * @prepad: padding information for syndrome based ecc generators 340 * @prepad: padding information for syndrome based ecc generators
340 * @postpad: padding information for syndrome based ecc generators 341 * @postpad: padding information for syndrome based ecc generators
341 * @layout: ECC layout control struct pointer 342 * @layout: ECC layout control struct pointer
343 * @priv: pointer to private ecc control data
342 * @hwctl: function to control hardware ecc generator. Must only 344 * @hwctl: function to control hardware ecc generator. Must only
343 * be provided if an hardware ECC is available 345 * be provided if an hardware ECC is available
344 * @calculate: function for ecc calculation or readback from ecc hardware 346 * @calculate: function for ecc calculation or readback from ecc hardware
@@ -362,6 +364,7 @@ struct nand_ecc_ctrl {
362 int prepad; 364 int prepad;
363 int postpad; 365 int postpad;
364 struct nand_ecclayout *layout; 366 struct nand_ecclayout *layout;
367 void *priv;
365 void (*hwctl)(struct mtd_info *mtd, int mode); 368 void (*hwctl)(struct mtd_info *mtd, int mode);
366 int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, 369 int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
367 uint8_t *ecc_code); 370 uint8_t *ecc_code);
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
new file mode 100644
index 000000000000..74acf5367556
--- /dev/null
+++ b/include/linux/mtd/nand_bch.h
@@ -0,0 +1,72 @@
1/*
2 * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This file is the header for the NAND BCH ECC implementation.
9 */
10
11#ifndef __MTD_NAND_BCH_H__
12#define __MTD_NAND_BCH_H__
13
14struct mtd_info;
15struct nand_bch_control;
16
17#if defined(CONFIG_MTD_NAND_ECC_BCH)
18
19static inline int mtd_nand_has_bch(void) { return 1; }
20
21/*
22 * Calculate BCH ecc code
23 */
24int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
25 u_char *ecc_code);
26
27/*
28 * Detect and correct bit errors
29 */
30int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
31 u_char *calc_ecc);
32/*
33 * Initialize BCH encoder/decoder
34 */
35struct nand_bch_control *
36nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
37 unsigned int eccbytes, struct nand_ecclayout **ecclayout);
38/*
39 * Release BCH encoder/decoder resources
40 */
41void nand_bch_free(struct nand_bch_control *nbc);
42
43#else /* !CONFIG_MTD_NAND_ECC_BCH */
44
45static inline int mtd_nand_has_bch(void) { return 0; }
46
47static inline int
48nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
49 u_char *ecc_code)
50{
51 return -1;
52}
53
54static inline int
55nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
56 unsigned char *read_ecc, unsigned char *calc_ecc)
57{
58 return -1;
59}
60
61static inline struct nand_bch_control *
62nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
63 unsigned int eccbytes, struct nand_ecclayout **ecclayout)
64{
65 return NULL;
66}
67
68static inline void nand_bch_free(struct nand_bch_control *nbc) {}
69
70#endif /* CONFIG_MTD_NAND_ECC_BCH */
71
72#endif /* __MTD_NAND_BCH_H__ */