xref: /linux/drivers/mtd/tests/subpagetest.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*4cd10358SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bf60862aSArtem Bityutskiy /*
3bf60862aSArtem Bityutskiy  * Copyright (C) 2006-2007 Nokia Corporation
4bf60862aSArtem Bityutskiy  *
5bf60862aSArtem Bityutskiy  * Test sub-page read and write on MTD device.
6bf60862aSArtem Bityutskiy  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
7bf60862aSArtem Bityutskiy  */
8bf60862aSArtem Bityutskiy 
9cd66a2dfSVikram Narayanan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10cd66a2dfSVikram Narayanan 
11bf60862aSArtem Bityutskiy #include <linux/init.h>
12bf60862aSArtem Bityutskiy #include <linux/module.h>
13bf60862aSArtem Bityutskiy #include <linux/moduleparam.h>
14bf60862aSArtem Bityutskiy #include <linux/err.h>
15bf60862aSArtem Bityutskiy #include <linux/mtd/mtd.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
17bf60862aSArtem Bityutskiy #include <linux/sched.h>
18a312b78bSAkinobu Mita #include <linux/random.h>
19bf60862aSArtem Bityutskiy 
20725cd71cSAkinobu Mita #include "mtd_test.h"
21725cd71cSAkinobu Mita 
227406060eSWolfram Sang static int dev = -EINVAL;
23bf60862aSArtem Bityutskiy module_param(dev, int, S_IRUGO);
24bf60862aSArtem Bityutskiy MODULE_PARM_DESC(dev, "MTD device number to use");
25bf60862aSArtem Bityutskiy 
26bf60862aSArtem Bityutskiy static struct mtd_info *mtd;
27bf60862aSArtem Bityutskiy static unsigned char *writebuf;
28bf60862aSArtem Bityutskiy static unsigned char *readbuf;
29bf60862aSArtem Bityutskiy static unsigned char *bbt;
30bf60862aSArtem Bityutskiy 
31bf60862aSArtem Bityutskiy static int subpgsize;
32bf60862aSArtem Bityutskiy static int bufsize;
33bf60862aSArtem Bityutskiy static int ebcnt;
34bf60862aSArtem Bityutskiy static int pgcnt;
35bf60862aSArtem Bityutskiy static int errcnt;
36a312b78bSAkinobu Mita static struct rnd_state rnd_state;
37bf60862aSArtem Bityutskiy 
38bf60862aSArtem Bityutskiy static inline void clear_data(unsigned char *buf, size_t len)
39bf60862aSArtem Bityutskiy {
40bf60862aSArtem Bityutskiy 	memset(buf, 0, len);
41bf60862aSArtem Bityutskiy }
42bf60862aSArtem Bityutskiy 
43bf60862aSArtem Bityutskiy static int write_eraseblock(int ebnum)
44bf60862aSArtem Bityutskiy {
4530fa9848SArtem Bityutskiy 	size_t written;
46bf60862aSArtem Bityutskiy 	int err = 0;
471001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
48bf60862aSArtem Bityutskiy 
49a312b78bSAkinobu Mita 	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
50eda95cbfSArtem Bityutskiy 	err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
51bf60862aSArtem Bityutskiy 	if (unlikely(err || written != subpgsize)) {
52cd66a2dfSVikram Narayanan 		pr_err("error: write failed at %#llx\n",
53bf60862aSArtem Bityutskiy 		       (long long)addr);
54bf60862aSArtem Bityutskiy 		if (written != subpgsize) {
55cd66a2dfSVikram Narayanan 			pr_err("  write size: %#x\n", subpgsize);
56cd66a2dfSVikram Narayanan 			pr_err("  written: %#zx\n", written);
57bf60862aSArtem Bityutskiy 		}
58bf60862aSArtem Bityutskiy 		return err ? err : -1;
59bf60862aSArtem Bityutskiy 	}
60bf60862aSArtem Bityutskiy 
61bf60862aSArtem Bityutskiy 	addr += subpgsize;
62bf60862aSArtem Bityutskiy 
63a312b78bSAkinobu Mita 	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
64eda95cbfSArtem Bityutskiy 	err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
65bf60862aSArtem Bityutskiy 	if (unlikely(err || written != subpgsize)) {
66cd66a2dfSVikram Narayanan 		pr_err("error: write failed at %#llx\n",
67bf60862aSArtem Bityutskiy 		       (long long)addr);
68bf60862aSArtem Bityutskiy 		if (written != subpgsize) {
69cd66a2dfSVikram Narayanan 			pr_err("  write size: %#x\n", subpgsize);
70cd66a2dfSVikram Narayanan 			pr_err("  written: %#zx\n", written);
71bf60862aSArtem Bityutskiy 		}
72bf60862aSArtem Bityutskiy 		return err ? err : -1;
73bf60862aSArtem Bityutskiy 	}
74bf60862aSArtem Bityutskiy 
75bf60862aSArtem Bityutskiy 	return err;
76bf60862aSArtem Bityutskiy }
77bf60862aSArtem Bityutskiy 
78bf60862aSArtem Bityutskiy static int write_eraseblock2(int ebnum)
79bf60862aSArtem Bityutskiy {
8030fa9848SArtem Bityutskiy 	size_t written;
81bf60862aSArtem Bityutskiy 	int err = 0, k;
821001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
83bf60862aSArtem Bityutskiy 
84bf60862aSArtem Bityutskiy 	for (k = 1; k < 33; ++k) {
85b9da8baeSBrian Norris 		if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
86bf60862aSArtem Bityutskiy 			break;
87a312b78bSAkinobu Mita 		prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
88eda95cbfSArtem Bityutskiy 		err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
89bf60862aSArtem Bityutskiy 		if (unlikely(err || written != subpgsize * k)) {
90cd66a2dfSVikram Narayanan 			pr_err("error: write failed at %#llx\n",
91bf60862aSArtem Bityutskiy 			       (long long)addr);
92c46adf09SXiaolei Li 			if (written != subpgsize * k) {
93cd66a2dfSVikram Narayanan 				pr_err("  write size: %#x\n",
94bf60862aSArtem Bityutskiy 				       subpgsize * k);
95cd66a2dfSVikram Narayanan 				pr_err("  written: %#08zx\n",
96bf60862aSArtem Bityutskiy 				       written);
97bf60862aSArtem Bityutskiy 			}
98bf60862aSArtem Bityutskiy 			return err ? err : -1;
99bf60862aSArtem Bityutskiy 		}
100bf60862aSArtem Bityutskiy 		addr += subpgsize * k;
101bf60862aSArtem Bityutskiy 	}
102bf60862aSArtem Bityutskiy 
103bf60862aSArtem Bityutskiy 	return err;
104bf60862aSArtem Bityutskiy }
105bf60862aSArtem Bityutskiy 
106bf60862aSArtem Bityutskiy static void print_subpage(unsigned char *p)
107bf60862aSArtem Bityutskiy {
108bf60862aSArtem Bityutskiy 	int i, j;
109bf60862aSArtem Bityutskiy 
110bf60862aSArtem Bityutskiy 	for (i = 0; i < subpgsize; ) {
111bf60862aSArtem Bityutskiy 		for (j = 0; i < subpgsize && j < 32; ++i, ++j)
112bf60862aSArtem Bityutskiy 			printk("%02x", *p++);
113bf60862aSArtem Bityutskiy 		printk("\n");
114bf60862aSArtem Bityutskiy 	}
115bf60862aSArtem Bityutskiy }
116bf60862aSArtem Bityutskiy 
117bf60862aSArtem Bityutskiy static int verify_eraseblock(int ebnum)
118bf60862aSArtem Bityutskiy {
11930fa9848SArtem Bityutskiy 	size_t read;
120bf60862aSArtem Bityutskiy 	int err = 0;
1211001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
122bf60862aSArtem Bityutskiy 
123a312b78bSAkinobu Mita 	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
124bf60862aSArtem Bityutskiy 	clear_data(readbuf, subpgsize);
125329ad399SArtem Bityutskiy 	err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
126bf60862aSArtem Bityutskiy 	if (unlikely(err || read != subpgsize)) {
127d57f4054SBrian Norris 		if (mtd_is_bitflip(err) && read == subpgsize) {
128cd66a2dfSVikram Narayanan 			pr_info("ECC correction at %#llx\n",
129bf60862aSArtem Bityutskiy 			       (long long)addr);
130bf60862aSArtem Bityutskiy 			err = 0;
131bf60862aSArtem Bityutskiy 		} else {
132cd66a2dfSVikram Narayanan 			pr_err("error: read failed at %#llx\n",
133bf60862aSArtem Bityutskiy 			       (long long)addr);
134bf60862aSArtem Bityutskiy 			return err ? err : -1;
135bf60862aSArtem Bityutskiy 		}
136bf60862aSArtem Bityutskiy 	}
137bf60862aSArtem Bityutskiy 	if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
138cd66a2dfSVikram Narayanan 		pr_err("error: verify failed at %#llx\n",
139bf60862aSArtem Bityutskiy 		       (long long)addr);
140cd66a2dfSVikram Narayanan 		pr_info("------------- written----------------\n");
141bf60862aSArtem Bityutskiy 		print_subpage(writebuf);
142cd66a2dfSVikram Narayanan 		pr_info("------------- read ------------------\n");
143bf60862aSArtem Bityutskiy 		print_subpage(readbuf);
144cd66a2dfSVikram Narayanan 		pr_info("-------------------------------------\n");
145bf60862aSArtem Bityutskiy 		errcnt += 1;
146bf60862aSArtem Bityutskiy 	}
147bf60862aSArtem Bityutskiy 
148bf60862aSArtem Bityutskiy 	addr += subpgsize;
149bf60862aSArtem Bityutskiy 
150a312b78bSAkinobu Mita 	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
151bf60862aSArtem Bityutskiy 	clear_data(readbuf, subpgsize);
152329ad399SArtem Bityutskiy 	err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
153bf60862aSArtem Bityutskiy 	if (unlikely(err || read != subpgsize)) {
154d57f4054SBrian Norris 		if (mtd_is_bitflip(err) && read == subpgsize) {
155cd66a2dfSVikram Narayanan 			pr_info("ECC correction at %#llx\n",
156bf60862aSArtem Bityutskiy 			       (long long)addr);
157bf60862aSArtem Bityutskiy 			err = 0;
158bf60862aSArtem Bityutskiy 		} else {
159cd66a2dfSVikram Narayanan 			pr_err("error: read failed at %#llx\n",
160bf60862aSArtem Bityutskiy 			       (long long)addr);
161bf60862aSArtem Bityutskiy 			return err ? err : -1;
162bf60862aSArtem Bityutskiy 		}
163bf60862aSArtem Bityutskiy 	}
164bf60862aSArtem Bityutskiy 	if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
165cd66a2dfSVikram Narayanan 		pr_info("error: verify failed at %#llx\n",
166bf60862aSArtem Bityutskiy 		       (long long)addr);
167cd66a2dfSVikram Narayanan 		pr_info("------------- written----------------\n");
168bf60862aSArtem Bityutskiy 		print_subpage(writebuf);
169cd66a2dfSVikram Narayanan 		pr_info("------------- read ------------------\n");
170bf60862aSArtem Bityutskiy 		print_subpage(readbuf);
171cd66a2dfSVikram Narayanan 		pr_info("-------------------------------------\n");
172bf60862aSArtem Bityutskiy 		errcnt += 1;
173bf60862aSArtem Bityutskiy 	}
174bf60862aSArtem Bityutskiy 
175bf60862aSArtem Bityutskiy 	return err;
176bf60862aSArtem Bityutskiy }
177bf60862aSArtem Bityutskiy 
178bf60862aSArtem Bityutskiy static int verify_eraseblock2(int ebnum)
179bf60862aSArtem Bityutskiy {
18030fa9848SArtem Bityutskiy 	size_t read;
181bf60862aSArtem Bityutskiy 	int err = 0, k;
1821001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
183bf60862aSArtem Bityutskiy 
184bf60862aSArtem Bityutskiy 	for (k = 1; k < 33; ++k) {
185b9da8baeSBrian Norris 		if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
186bf60862aSArtem Bityutskiy 			break;
187a312b78bSAkinobu Mita 		prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
188bf60862aSArtem Bityutskiy 		clear_data(readbuf, subpgsize * k);
189329ad399SArtem Bityutskiy 		err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
190bf60862aSArtem Bityutskiy 		if (unlikely(err || read != subpgsize * k)) {
191d57f4054SBrian Norris 			if (mtd_is_bitflip(err) && read == subpgsize * k) {
192cd66a2dfSVikram Narayanan 				pr_info("ECC correction at %#llx\n",
193bf60862aSArtem Bityutskiy 				       (long long)addr);
194bf60862aSArtem Bityutskiy 				err = 0;
195bf60862aSArtem Bityutskiy 			} else {
196cd66a2dfSVikram Narayanan 				pr_err("error: read failed at "
197bf60862aSArtem Bityutskiy 				       "%#llx\n", (long long)addr);
198bf60862aSArtem Bityutskiy 				return err ? err : -1;
199bf60862aSArtem Bityutskiy 			}
200bf60862aSArtem Bityutskiy 		}
201bf60862aSArtem Bityutskiy 		if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
202cd66a2dfSVikram Narayanan 			pr_err("error: verify failed at %#llx\n",
203bf60862aSArtem Bityutskiy 			       (long long)addr);
204bf60862aSArtem Bityutskiy 			errcnt += 1;
205bf60862aSArtem Bityutskiy 		}
206bf60862aSArtem Bityutskiy 		addr += subpgsize * k;
207bf60862aSArtem Bityutskiy 	}
208bf60862aSArtem Bityutskiy 
209bf60862aSArtem Bityutskiy 	return err;
210bf60862aSArtem Bityutskiy }
211bf60862aSArtem Bityutskiy 
212bf60862aSArtem Bityutskiy static int verify_eraseblock_ff(int ebnum)
213bf60862aSArtem Bityutskiy {
214bf60862aSArtem Bityutskiy 	uint32_t j;
21530fa9848SArtem Bityutskiy 	size_t read;
216bf60862aSArtem Bityutskiy 	int err = 0;
2171001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
218bf60862aSArtem Bityutskiy 
219bf60862aSArtem Bityutskiy 	memset(writebuf, 0xff, subpgsize);
220bf60862aSArtem Bityutskiy 	for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
221bf60862aSArtem Bityutskiy 		clear_data(readbuf, subpgsize);
222329ad399SArtem Bityutskiy 		err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
223bf60862aSArtem Bityutskiy 		if (unlikely(err || read != subpgsize)) {
224d57f4054SBrian Norris 			if (mtd_is_bitflip(err) && read == subpgsize) {
225cd66a2dfSVikram Narayanan 				pr_info("ECC correction at %#llx\n",
226bf60862aSArtem Bityutskiy 				       (long long)addr);
227bf60862aSArtem Bityutskiy 				err = 0;
228bf60862aSArtem Bityutskiy 			} else {
229cd66a2dfSVikram Narayanan 				pr_err("error: read failed at "
230bf60862aSArtem Bityutskiy 				       "%#llx\n", (long long)addr);
231bf60862aSArtem Bityutskiy 				return err ? err : -1;
232bf60862aSArtem Bityutskiy 			}
233bf60862aSArtem Bityutskiy 		}
234bf60862aSArtem Bityutskiy 		if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
235cd66a2dfSVikram Narayanan 			pr_err("error: verify 0xff failed at "
236bf60862aSArtem Bityutskiy 			       "%#llx\n", (long long)addr);
237bf60862aSArtem Bityutskiy 			errcnt += 1;
238bf60862aSArtem Bityutskiy 		}
239bf60862aSArtem Bityutskiy 		addr += subpgsize;
240bf60862aSArtem Bityutskiy 	}
241bf60862aSArtem Bityutskiy 
242bf60862aSArtem Bityutskiy 	return err;
243bf60862aSArtem Bityutskiy }
244bf60862aSArtem Bityutskiy 
245bf60862aSArtem Bityutskiy static int verify_all_eraseblocks_ff(void)
246bf60862aSArtem Bityutskiy {
247bf60862aSArtem Bityutskiy 	int err;
248bf60862aSArtem Bityutskiy 	unsigned int i;
249bf60862aSArtem Bityutskiy 
250cd66a2dfSVikram Narayanan 	pr_info("verifying all eraseblocks for 0xff\n");
251bf60862aSArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
252bf60862aSArtem Bityutskiy 		if (bbt[i])
253bf60862aSArtem Bityutskiy 			continue;
254bf60862aSArtem Bityutskiy 		err = verify_eraseblock_ff(i);
255bf60862aSArtem Bityutskiy 		if (err)
256bf60862aSArtem Bityutskiy 			return err;
257bf60862aSArtem Bityutskiy 		if (i % 256 == 0)
258cd66a2dfSVikram Narayanan 			pr_info("verified up to eraseblock %u\n", i);
2592a6a28e7SRichard Weinberger 
2602a6a28e7SRichard Weinberger 		err = mtdtest_relax();
2612a6a28e7SRichard Weinberger 		if (err)
2622a6a28e7SRichard Weinberger 			return err;
263bf60862aSArtem Bityutskiy 	}
264cd66a2dfSVikram Narayanan 	pr_info("verified %u eraseblocks\n", i);
265bf60862aSArtem Bityutskiy 	return 0;
266bf60862aSArtem Bityutskiy }
267bf60862aSArtem Bityutskiy 
268bf60862aSArtem Bityutskiy static int __init mtd_subpagetest_init(void)
269bf60862aSArtem Bityutskiy {
270bf60862aSArtem Bityutskiy 	int err = 0;
271bf60862aSArtem Bityutskiy 	uint32_t i;
272bf60862aSArtem Bityutskiy 	uint64_t tmp;
273bf60862aSArtem Bityutskiy 
274bf60862aSArtem Bityutskiy 	printk(KERN_INFO "\n");
275bf60862aSArtem Bityutskiy 	printk(KERN_INFO "=================================================\n");
2767406060eSWolfram Sang 
2777406060eSWolfram Sang 	if (dev < 0) {
278064a7694SMasanari Iida 		pr_info("Please specify a valid mtd-device via module parameter\n");
279cd66a2dfSVikram Narayanan 		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
2807406060eSWolfram Sang 		return -EINVAL;
2817406060eSWolfram Sang 	}
2827406060eSWolfram Sang 
283cd66a2dfSVikram Narayanan 	pr_info("MTD device: %d\n", dev);
284bf60862aSArtem Bityutskiy 
285bf60862aSArtem Bityutskiy 	mtd = get_mtd_device(NULL, dev);
286bf60862aSArtem Bityutskiy 	if (IS_ERR(mtd)) {
287bf60862aSArtem Bityutskiy 		err = PTR_ERR(mtd);
288cd66a2dfSVikram Narayanan 		pr_err("error: cannot get MTD device\n");
289bf60862aSArtem Bityutskiy 		return err;
290bf60862aSArtem Bityutskiy 	}
291bf60862aSArtem Bityutskiy 
292818b9739SHuang Shijie 	if (!mtd_type_is_nand(mtd)) {
293cd66a2dfSVikram Narayanan 		pr_info("this test requires NAND flash\n");
294bf60862aSArtem Bityutskiy 		goto out;
295bf60862aSArtem Bityutskiy 	}
296bf60862aSArtem Bityutskiy 
297bf60862aSArtem Bityutskiy 	subpgsize = mtd->writesize >> mtd->subpage_sft;
2987b7e905eSRoman Tereshonkov 	tmp = mtd->size;
2997b7e905eSRoman Tereshonkov 	do_div(tmp, mtd->erasesize);
3007b7e905eSRoman Tereshonkov 	ebcnt = tmp;
3017b7e905eSRoman Tereshonkov 	pgcnt = mtd->erasesize / mtd->writesize;
3027b7e905eSRoman Tereshonkov 
303cd66a2dfSVikram Narayanan 	pr_info("MTD device size %llu, eraseblock size %u, "
304bf60862aSArtem Bityutskiy 	       "page size %u, subpage size %u, count of eraseblocks %u, "
305bf60862aSArtem Bityutskiy 	       "pages per eraseblock %u, OOB size %u\n",
306bf60862aSArtem Bityutskiy 	       (unsigned long long)mtd->size, mtd->erasesize,
307bf60862aSArtem Bityutskiy 	       mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
308bf60862aSArtem Bityutskiy 
309bf60862aSArtem Bityutskiy 	err = -ENOMEM;
310bf60862aSArtem Bityutskiy 	bufsize = subpgsize * 32;
311bf60862aSArtem Bityutskiy 	writebuf = kmalloc(bufsize, GFP_KERNEL);
31233777e66SBrian Norris 	if (!writebuf)
313bf60862aSArtem Bityutskiy 		goto out;
314bf60862aSArtem Bityutskiy 	readbuf = kmalloc(bufsize, GFP_KERNEL);
31533777e66SBrian Norris 	if (!readbuf)
316bf60862aSArtem Bityutskiy 		goto out;
317725cd71cSAkinobu Mita 	bbt = kzalloc(ebcnt, GFP_KERNEL);
318725cd71cSAkinobu Mita 	if (!bbt)
319725cd71cSAkinobu Mita 		goto out;
320bf60862aSArtem Bityutskiy 
321725cd71cSAkinobu Mita 	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
322bf60862aSArtem Bityutskiy 	if (err)
323bf60862aSArtem Bityutskiy 		goto out;
324bf60862aSArtem Bityutskiy 
325725cd71cSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
326bf60862aSArtem Bityutskiy 	if (err)
327bf60862aSArtem Bityutskiy 		goto out;
328bf60862aSArtem Bityutskiy 
329cd66a2dfSVikram Narayanan 	pr_info("writing whole device\n");
330a312b78bSAkinobu Mita 	prandom_seed_state(&rnd_state, 1);
331bf60862aSArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
332bf60862aSArtem Bityutskiy 		if (bbt[i])
333bf60862aSArtem Bityutskiy 			continue;
334bf60862aSArtem Bityutskiy 		err = write_eraseblock(i);
335bf60862aSArtem Bityutskiy 		if (unlikely(err))
336bf60862aSArtem Bityutskiy 			goto out;
337bf60862aSArtem Bityutskiy 		if (i % 256 == 0)
338cd66a2dfSVikram Narayanan 			pr_info("written up to eraseblock %u\n", i);
3392a6a28e7SRichard Weinberger 
3402a6a28e7SRichard Weinberger 		err = mtdtest_relax();
3412a6a28e7SRichard Weinberger 		if (err)
3422a6a28e7SRichard Weinberger 			goto out;
343bf60862aSArtem Bityutskiy 	}
344cd66a2dfSVikram Narayanan 	pr_info("written %u eraseblocks\n", i);
345bf60862aSArtem Bityutskiy 
346a312b78bSAkinobu Mita 	prandom_seed_state(&rnd_state, 1);
347cd66a2dfSVikram Narayanan 	pr_info("verifying all eraseblocks\n");
348bf60862aSArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
349bf60862aSArtem Bityutskiy 		if (bbt[i])
350bf60862aSArtem Bityutskiy 			continue;
351bf60862aSArtem Bityutskiy 		err = verify_eraseblock(i);
352bf60862aSArtem Bityutskiy 		if (unlikely(err))
353bf60862aSArtem Bityutskiy 			goto out;
354bf60862aSArtem Bityutskiy 		if (i % 256 == 0)
355cd66a2dfSVikram Narayanan 			pr_info("verified up to eraseblock %u\n", i);
3562a6a28e7SRichard Weinberger 
3572a6a28e7SRichard Weinberger 		err = mtdtest_relax();
3582a6a28e7SRichard Weinberger 		if (err)
3592a6a28e7SRichard Weinberger 			goto out;
360bf60862aSArtem Bityutskiy 	}
361cd66a2dfSVikram Narayanan 	pr_info("verified %u eraseblocks\n", i);
362bf60862aSArtem Bityutskiy 
363725cd71cSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
364bf60862aSArtem Bityutskiy 	if (err)
365bf60862aSArtem Bityutskiy 		goto out;
366bf60862aSArtem Bityutskiy 
367bf60862aSArtem Bityutskiy 	err = verify_all_eraseblocks_ff();
368bf60862aSArtem Bityutskiy 	if (err)
369bf60862aSArtem Bityutskiy 		goto out;
370bf60862aSArtem Bityutskiy 
371bf60862aSArtem Bityutskiy 	/* Write all eraseblocks */
372a312b78bSAkinobu Mita 	prandom_seed_state(&rnd_state, 3);
373cd66a2dfSVikram Narayanan 	pr_info("writing whole device\n");
374bf60862aSArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
375bf60862aSArtem Bityutskiy 		if (bbt[i])
376bf60862aSArtem Bityutskiy 			continue;
377bf60862aSArtem Bityutskiy 		err = write_eraseblock2(i);
378bf60862aSArtem Bityutskiy 		if (unlikely(err))
379bf60862aSArtem Bityutskiy 			goto out;
380bf60862aSArtem Bityutskiy 		if (i % 256 == 0)
381cd66a2dfSVikram Narayanan 			pr_info("written up to eraseblock %u\n", i);
3822a6a28e7SRichard Weinberger 
3832a6a28e7SRichard Weinberger 		err = mtdtest_relax();
3842a6a28e7SRichard Weinberger 		if (err)
3852a6a28e7SRichard Weinberger 			goto out;
386bf60862aSArtem Bityutskiy 	}
387cd66a2dfSVikram Narayanan 	pr_info("written %u eraseblocks\n", i);
388bf60862aSArtem Bityutskiy 
389bf60862aSArtem Bityutskiy 	/* Check all eraseblocks */
390a312b78bSAkinobu Mita 	prandom_seed_state(&rnd_state, 3);
391cd66a2dfSVikram Narayanan 	pr_info("verifying all eraseblocks\n");
392bf60862aSArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
393bf60862aSArtem Bityutskiy 		if (bbt[i])
394bf60862aSArtem Bityutskiy 			continue;
395bf60862aSArtem Bityutskiy 		err = verify_eraseblock2(i);
396bf60862aSArtem Bityutskiy 		if (unlikely(err))
397bf60862aSArtem Bityutskiy 			goto out;
398bf60862aSArtem Bityutskiy 		if (i % 256 == 0)
399cd66a2dfSVikram Narayanan 			pr_info("verified up to eraseblock %u\n", i);
4002a6a28e7SRichard Weinberger 
4012a6a28e7SRichard Weinberger 		err = mtdtest_relax();
4022a6a28e7SRichard Weinberger 		if (err)
4032a6a28e7SRichard Weinberger 			goto out;
404bf60862aSArtem Bityutskiy 	}
405cd66a2dfSVikram Narayanan 	pr_info("verified %u eraseblocks\n", i);
406bf60862aSArtem Bityutskiy 
407725cd71cSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
408bf60862aSArtem Bityutskiy 	if (err)
409bf60862aSArtem Bityutskiy 		goto out;
410bf60862aSArtem Bityutskiy 
411bf60862aSArtem Bityutskiy 	err = verify_all_eraseblocks_ff();
412bf60862aSArtem Bityutskiy 	if (err)
413bf60862aSArtem Bityutskiy 		goto out;
414bf60862aSArtem Bityutskiy 
415cd66a2dfSVikram Narayanan 	pr_info("finished with %d errors\n", errcnt);
416bf60862aSArtem Bityutskiy 
417bf60862aSArtem Bityutskiy out:
418bf60862aSArtem Bityutskiy 	kfree(bbt);
419bf60862aSArtem Bityutskiy 	kfree(readbuf);
420bf60862aSArtem Bityutskiy 	kfree(writebuf);
421bf60862aSArtem Bityutskiy 	put_mtd_device(mtd);
422bf60862aSArtem Bityutskiy 	if (err)
423cd66a2dfSVikram Narayanan 		pr_info("error %d occurred\n", err);
424bf60862aSArtem Bityutskiy 	printk(KERN_INFO "=================================================\n");
425bf60862aSArtem Bityutskiy 	return err;
426bf60862aSArtem Bityutskiy }
427bf60862aSArtem Bityutskiy module_init(mtd_subpagetest_init);
428bf60862aSArtem Bityutskiy 
429bf60862aSArtem Bityutskiy static void __exit mtd_subpagetest_exit(void)
430bf60862aSArtem Bityutskiy {
431bf60862aSArtem Bityutskiy 	return;
432bf60862aSArtem Bityutskiy }
433bf60862aSArtem Bityutskiy module_exit(mtd_subpagetest_exit);
434bf60862aSArtem Bityutskiy 
435bf60862aSArtem Bityutskiy MODULE_DESCRIPTION("Subpage test module");
436bf60862aSArtem Bityutskiy MODULE_AUTHOR("Adrian Hunter");
437bf60862aSArtem Bityutskiy MODULE_LICENSE("GPL");
438