1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 #include <linux/init.h>
4 #include <linux/list.h>
5 #include <linux/module.h>
7 #include <linux/slab.h>
8 #include <linux/vmalloc.h>
9 #include <linux/random.h>
10 #include <linux/mtd/mtd.h>
11 #include <linux/moduleparam.h>
15 struct mtd_info *master;
17 struct list_head list;
20 #define CBIT(v, n) ((v) & (1 << (n)))
21 #define BCLR(v, n) ((v) = (v) & ~(1 << (n)))
23 static struct mtd_info *mtd = NULL;
25 module_param(dev, int, S_IRUGO);
26 MODULE_PARM_DESC(dev, "MTD device number to use");
28 static int insert_biterror(unsigned char *buf)
31 unsigned int byte = 0;
33 while (byte < mtd->writesize) {
34 for (bit = 0; bit <= 7; bit++) {
35 if (CBIT(buf[byte], bit)) {
37 pr_info("Inserted biterror @ %u/%u\n", byte, bit);
43 pr_err("biterror: Failed to find a '1' bit\n");
47 static int erase_eraseblock(unsigned int ebnum)
50 struct erase_info ei = {0};
53 ei.addr = ebnum * mtd->erasesize;
54 ei.len = mtd->erasesize;
56 err = mtd_erase(mtd, &ei);
58 pr_err("err %d while erasing EB %d\n", err, ebnum);
62 if (ei.state == MTD_ERASE_FAILED) {
63 pr_err("some erase error occurred at EB %d\n", ebnum);
70 static int write_oob(loff_t offset, unsigned char *databuf, unsigned int len, unsigned char *oobbuf, unsigned int ooblen, unsigned int mode)
72 struct mtd_oob_ops ops = {0};
83 err = mtd->_write_oob(mtd, offset, &ops);
84 if (err || ops.oobretlen != ops.ooblen || ops.retlen != ops.len) {
85 pr_err("write address: 0x%.8x's failed, err:%d!", (unsigned int)offset, err);
87 pr_err("expect:%d , %d real:%d, %d\n", ops.len, ops.ooblen, ops.retlen, ops.oobretlen);
95 static int read_oob(loff_t offset, unsigned char *databuf, unsigned int len, unsigned char *oobbuf, unsigned int ooblen, unsigned int mode)
97 struct mtd_oob_ops ops = {0};
106 ops.datbuf = databuf;
108 err = mtd->_read_oob(mtd, offset, &ops);
109 if (err || ops.oobretlen != ops.ooblen || ops.retlen != ops.len) {
110 pr_err("read address: 0x%.8x failed, err:%d!\n", (unsigned int)offset, err);
112 pr_err("expect:%d , %d real:%d, %d\n", ops.len, ops.ooblen, ops.retlen, ops.oobretlen);
114 } else if(err == -EUCLEAN) {
122 static int __init nandflash_ecctest_init(void)
124 unsigned int read_len = 0;
128 struct rnd_state rnd_state;
129 unsigned int corrected_num = 0;
130 unsigned char *oobbuf_w = NULL;
131 unsigned char *oobbuf_r = NULL;
132 unsigned char *pagebuf_r = NULL;
133 unsigned char *pagebuf_w = NULL;
134 unsigned char *pagebuf_v = NULL;
135 struct mtd_ecc_stats stats = {0};
136 struct mtd_part *mtd_part = NULL;
139 pr_info("--------------------------------------------------------------------------\n");
141 mtd = get_mtd_device(NULL, 4);
144 pr_err("Cannot get MTD device\n");
148 mtd_part = (struct mtd_part *)mtd;
150 if(!mtd->_block_isbad || !mtd->_block_markbad || !mtd->_read_oob || !mtd->_write_oob ||
151 !mtd->_read || !mtd->_write) {
152 pr_err("Some mtd's method may be NULL!");
156 pagebuf_r = vmalloc(mtd->writesize);
157 oobbuf_r = vmalloc(mtd->oobsize);
158 pagebuf_w = vmalloc(mtd->writesize);
159 pagebuf_v = vmalloc(mtd->writesize);
160 oobbuf_w = vmalloc(mtd->oobsize);
161 if(!pagebuf_r || !oobbuf_r || !pagebuf_w || !pagebuf_v || !oobbuf_w) {
162 pr_err("Alloc buf failed!");
166 //find a vailid block
167 while(offset < mtd->size) {
168 if(mtd->_block_isbad(mtd, offset)) {
169 offset += mtd->erasesize;
175 if(offset >= mtd->size) {
176 pr_err("The whole mtd_partion are bad!\n");
180 err = erase_eraseblock(((long)offset)/mtd->erasesize);
182 pr_err("Erase failed at EB: %d\n", ((unsigned int)offset)/mtd->erasesize);
185 pr_info("Erase block %d successfully!\n", ((unsigned int)offset)/mtd->erasesize);
188 prandom_seed_state(&rnd_state, 1);
189 prandom_bytes_state(&rnd_state, oobbuf_w, mtd->oobsize);
190 prandom_bytes_state(&rnd_state, pagebuf_w, mtd->writesize);
191 memcpy(pagebuf_v, pagebuf_w, mtd->writesize);
193 err = write_oob(offset, pagebuf_w, mtd->writesize, oobbuf_w, mtd->oobsize, MTD_OPS_PLACE_OOB);
195 pr_err("1.1 write failed!\n");
199 err = read_oob(offset, pagebuf_r, mtd->writesize, oobbuf_r, mtd->oobsize, MTD_OPS_PLACE_OOB);
201 pr_err("1.1 read failed!\n");
205 if(memcmp(pagebuf_v, pagebuf_r, mtd->writesize) != 0) {
206 pr_err("1.1 compare page failed!\n");
209 memcpy(oobbuf_w, oobbuf_r, mtd->oobsize);
211 for(j = 0; j < mtd->writesize * 8; j ++)
213 offset += mtd->writesize;
214 err = insert_biterror(pagebuf_w);
216 pr_err("Insert biterror failed!\n");
219 pr_info("Insert %d bit-flip sucessfully!\n", j + 1);
221 err = write_oob(offset, pagebuf_w, mtd->writesize, oobbuf_w, mtd->oobsize, MTD_OPS_RAW);
223 pr_err("2.1 write failed!\n");
227 stats = mtd_part->master->ecc_stats;
228 err = read_oob(offset, pagebuf_r, mtd->writesize, oobbuf_r, mtd->oobsize, MTD_OPS_PLACE_OOB);
230 pr_err("2.1 read failed!\n");
234 if(memcmp(pagebuf_v, pagebuf_r, mtd->writesize) != 0) {
235 pr_err("2.2 compare page failed!\n");
239 corrected_num = mtd_part->master->ecc_stats.corrected - stats.corrected;
240 if(corrected_num != (j + 1)) {
241 pr_err("Bit-flip num is not match, expected:%d, really:%d\n", j + 1, corrected_num);
246 pr_info("Test successfully, this system can corrected %d bit-flip at most!\n", j);
248 err = erase_eraseblock(((unsigned int)offset)/mtd->erasesize);
250 pr_err("1.3 erase failed at EB: %d\n", ((unsigned int)offset)/mtd->erasesize);
258 pr_info("--------------------------------------------------------------------------\n");
262 static void __exit nandflash_ecctest_exit(void)
268 module_init(nandflash_ecctest_init);
269 module_exit(nandflash_ecctest_exit);
271 MODULE_DESCRIPTION("Test ecc strength");
272 MODULE_AUTHOR("ming.tang");
273 MODULE_LICENSE("GPL");