1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2006-2008 Nokia Corporation
5 * Test page read and write on MTD device.
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12 #include <asm/div64.h>
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/moduleparam.h>
16 #include <linux/err.h>
17 #include <linux/mtd/mtd.h>
18 #include <linux/slab.h>
19 #include <linux/sched.h>
20 #include <linux/random.h>
24 static int dev = -EINVAL;
25 module_param(dev, int, S_IRUGO);
26 MODULE_PARM_DESC(dev, "MTD device number to use");
28 static struct mtd_info *mtd;
29 static unsigned char *twopages;
30 static unsigned char *writebuf;
31 static unsigned char *boundary;
32 static unsigned char *bbt;
39 static struct rnd_state rnd_state;
41 static int write_eraseblock(int ebnum)
43 loff_t addr = (loff_t)ebnum * mtd->erasesize;
45 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
47 return mtdtest_write(mtd, addr, mtd->erasesize, writebuf);
50 static int verify_eraseblock(int ebnum)
55 loff_t addr = (loff_t)ebnum * mtd->erasesize;
58 for (i = 0; i < ebcnt && bbt[i]; ++i)
59 addr0 += mtd->erasesize;
62 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
63 addrn -= mtd->erasesize;
65 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
66 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
67 /* Do a read to set the internal dataRAMs to different data */
68 err = mtdtest_read(mtd, addr0, bufsize, twopages);
71 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
74 memset(twopages, 0, bufsize);
75 err = mtdtest_read(mtd, addr, bufsize, twopages);
78 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
79 pr_err("error: verify failed at %#llx\n",
84 /* Check boundary between eraseblocks */
85 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
86 struct rnd_state old_state = rnd_state;
88 /* Do a read to set the internal dataRAMs to different data */
89 err = mtdtest_read(mtd, addr0, bufsize, twopages);
92 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
95 memset(twopages, 0, bufsize);
96 err = mtdtest_read(mtd, addr, bufsize, twopages);
99 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
100 prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
101 if (memcmp(twopages, boundary, bufsize)) {
102 pr_err("error: verify failed at %#llx\n",
106 rnd_state = old_state;
111 static int crosstest(void)
114 loff_t addr, addr0, addrn;
115 unsigned char *pp1, *pp2, *pp3, *pp4;
117 pr_info("crosstest\n");
118 pp1 = kcalloc(pgsize, 4, GFP_KERNEL);
126 for (i = 0; i < ebcnt && bbt[i]; ++i)
127 addr0 += mtd->erasesize;
130 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
131 addrn -= mtd->erasesize;
133 /* Read 2nd-to-last page to pp1 */
134 addr = addrn - pgsize - pgsize;
135 err = mtdtest_read(mtd, addr, pgsize, pp1);
141 /* Read 3rd-to-last page to pp1 */
142 addr = addrn - pgsize - pgsize - pgsize;
143 err = mtdtest_read(mtd, addr, pgsize, pp1);
149 /* Read first page to pp2 */
151 pr_info("reading page at %#llx\n", (long long)addr);
152 err = mtdtest_read(mtd, addr, pgsize, pp2);
158 /* Read last page to pp3 */
159 addr = addrn - pgsize;
160 pr_info("reading page at %#llx\n", (long long)addr);
161 err = mtdtest_read(mtd, addr, pgsize, pp3);
167 /* Read first page again to pp4 */
169 pr_info("reading page at %#llx\n", (long long)addr);
170 err = mtdtest_read(mtd, addr, pgsize, pp4);
176 /* pp2 and pp4 should be the same */
177 pr_info("verifying pages read at %#llx match\n",
179 if (memcmp(pp2, pp4, pgsize)) {
180 pr_err("verify failed!\n");
183 pr_info("crosstest ok\n");
188 static int erasecrosstest(void)
190 int err = 0, i, ebnum, ebnum2;
192 char *readbuf = twopages;
194 pr_info("erasecrosstest\n");
198 for (i = 0; i < ebcnt && bbt[i]; ++i) {
199 addr0 += mtd->erasesize;
204 while (ebnum2 && bbt[ebnum2])
207 pr_info("erasing block %d\n", ebnum);
208 err = mtdtest_erase_eraseblock(mtd, ebnum);
212 pr_info("writing 1st page of block %d\n", ebnum);
213 prandom_bytes_state(&rnd_state, writebuf, pgsize);
214 strcpy(writebuf, "There is no data like this!");
215 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
219 pr_info("reading 1st page of block %d\n", ebnum);
220 memset(readbuf, 0, pgsize);
221 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
225 pr_info("verifying 1st page of block %d\n", ebnum);
226 if (memcmp(writebuf, readbuf, pgsize)) {
227 pr_err("verify failed!\n");
232 pr_info("erasing block %d\n", ebnum);
233 err = mtdtest_erase_eraseblock(mtd, ebnum);
237 pr_info("writing 1st page of block %d\n", ebnum);
238 prandom_bytes_state(&rnd_state, writebuf, pgsize);
239 strcpy(writebuf, "There is no data like this!");
240 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
244 pr_info("erasing block %d\n", ebnum2);
245 err = mtdtest_erase_eraseblock(mtd, ebnum2);
249 pr_info("reading 1st page of block %d\n", ebnum);
250 memset(readbuf, 0, pgsize);
251 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
255 pr_info("verifying 1st page of block %d\n", ebnum);
256 if (memcmp(writebuf, readbuf, pgsize)) {
257 pr_err("verify failed!\n");
263 pr_info("erasecrosstest ok\n");
267 static int erasetest(void)
269 int err = 0, i, ebnum, ok = 1;
272 pr_info("erasetest\n");
276 for (i = 0; i < ebcnt && bbt[i]; ++i) {
277 addr0 += mtd->erasesize;
281 pr_info("erasing block %d\n", ebnum);
282 err = mtdtest_erase_eraseblock(mtd, ebnum);
286 pr_info("writing 1st page of block %d\n", ebnum);
287 prandom_bytes_state(&rnd_state, writebuf, pgsize);
288 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
292 pr_info("erasing block %d\n", ebnum);
293 err = mtdtest_erase_eraseblock(mtd, ebnum);
297 pr_info("reading 1st page of block %d\n", ebnum);
298 err = mtdtest_read(mtd, addr0, pgsize, twopages);
302 pr_info("verifying 1st page of block %d is all 0xff\n",
304 for (i = 0; i < pgsize; ++i)
305 if (twopages[i] != 0xff) {
306 pr_err("verifying all 0xff failed at %d\n",
314 pr_info("erasetest ok\n");
319 static int __init mtd_pagetest_init(void)
325 printk(KERN_INFO "\n");
326 printk(KERN_INFO "=================================================\n");
329 pr_info("Please specify a valid mtd-device via module parameter\n");
330 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
334 pr_info("MTD device: %d\n", dev);
336 mtd = get_mtd_device(NULL, dev);
339 pr_err("error: cannot get MTD device\n");
343 if (!mtd_type_is_nand(mtd)) {
344 pr_info("this test requires NAND flash\n");
349 do_div(tmp, mtd->erasesize);
351 pgcnt = mtd->erasesize / mtd->writesize;
352 pgsize = mtd->writesize;
354 pr_info("MTD device size %llu, eraseblock size %u, "
355 "page size %u, count of eraseblocks %u, pages per "
356 "eraseblock %u, OOB size %u\n",
357 (unsigned long long)mtd->size, mtd->erasesize,
358 pgsize, ebcnt, pgcnt, mtd->oobsize);
361 bufsize = pgsize * 2;
362 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
365 twopages = kmalloc(bufsize, GFP_KERNEL);
368 boundary = kmalloc(bufsize, GFP_KERNEL);
372 bbt = kzalloc(ebcnt, GFP_KERNEL);
375 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
379 /* Erase all eraseblocks */
380 pr_info("erasing whole device\n");
381 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
384 pr_info("erased %u eraseblocks\n", ebcnt);
386 /* Write all eraseblocks */
387 prandom_seed_state(&rnd_state, 1);
388 pr_info("writing whole device\n");
389 for (i = 0; i < ebcnt; ++i) {
392 err = write_eraseblock(i);
396 pr_info("written up to eraseblock %u\n", i);
398 err = mtdtest_relax();
402 pr_info("written %u eraseblocks\n", i);
404 /* Check all eraseblocks */
405 prandom_seed_state(&rnd_state, 1);
406 pr_info("verifying all eraseblocks\n");
407 for (i = 0; i < ebcnt; ++i) {
410 err = verify_eraseblock(i);
414 pr_info("verified up to eraseblock %u\n", i);
416 err = mtdtest_relax();
420 pr_info("verified %u eraseblocks\n", i);
427 err = erasecrosstest();
431 pr_info("skipping erasecrosstest, 2 erase blocks needed\n");
438 pr_info("finished with %d errors\n", errcnt);
447 pr_info("error %d occurred\n", err);
448 printk(KERN_INFO "=================================================\n");
451 module_init(mtd_pagetest_init);
453 static void __exit mtd_pagetest_exit(void)
457 module_exit(mtd_pagetest_exit);
459 MODULE_DESCRIPTION("NAND page test");
460 MODULE_AUTHOR("Adrian Hunter");
461 MODULE_LICENSE("GPL");