xref: /openbmc/linux/drivers/mtd/tests/mtd_test.c (revision 8f347c42)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2084db4b0SAkinobu Mita #define pr_fmt(fmt) "mtd_test: " fmt
3084db4b0SAkinobu Mita 
4084db4b0SAkinobu Mita #include <linux/module.h>
5084db4b0SAkinobu Mita #include <linux/sched.h>
6084db4b0SAkinobu Mita #include <linux/printk.h>
7084db4b0SAkinobu Mita 
8084db4b0SAkinobu Mita #include "mtd_test.h"
9084db4b0SAkinobu Mita 
mtdtest_erase_eraseblock(struct mtd_info * mtd,unsigned int ebnum)10084db4b0SAkinobu Mita int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
11084db4b0SAkinobu Mita {
12084db4b0SAkinobu Mita 	int err;
13084db4b0SAkinobu Mita 	struct erase_info ei;
141001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
15084db4b0SAkinobu Mita 
16084db4b0SAkinobu Mita 	memset(&ei, 0, sizeof(struct erase_info));
17084db4b0SAkinobu Mita 	ei.addr = addr;
18084db4b0SAkinobu Mita 	ei.len  = mtd->erasesize;
19084db4b0SAkinobu Mita 
20084db4b0SAkinobu Mita 	err = mtd_erase(mtd, &ei);
21084db4b0SAkinobu Mita 	if (err) {
22084db4b0SAkinobu Mita 		pr_info("error %d while erasing EB %d\n", err, ebnum);
23084db4b0SAkinobu Mita 		return err;
24084db4b0SAkinobu Mita 	}
25084db4b0SAkinobu Mita 
26084db4b0SAkinobu Mita 	return 0;
27084db4b0SAkinobu Mita }
28084db4b0SAkinobu Mita 
is_block_bad(struct mtd_info * mtd,unsigned int ebnum)29084db4b0SAkinobu Mita static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum)
30084db4b0SAkinobu Mita {
31084db4b0SAkinobu Mita 	int ret;
321001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
33084db4b0SAkinobu Mita 
34084db4b0SAkinobu Mita 	ret = mtd_block_isbad(mtd, addr);
35084db4b0SAkinobu Mita 	if (ret)
36084db4b0SAkinobu Mita 		pr_info("block %d is bad\n", ebnum);
37084db4b0SAkinobu Mita 
38084db4b0SAkinobu Mita 	return ret;
39084db4b0SAkinobu Mita }
40084db4b0SAkinobu Mita 
mtdtest_scan_for_bad_eraseblocks(struct mtd_info * mtd,unsigned char * bbt,unsigned int eb,int ebcnt)41084db4b0SAkinobu Mita int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
42084db4b0SAkinobu Mita 					unsigned int eb, int ebcnt)
43084db4b0SAkinobu Mita {
44084db4b0SAkinobu Mita 	int i, bad = 0;
45084db4b0SAkinobu Mita 
46084db4b0SAkinobu Mita 	if (!mtd_can_have_bb(mtd))
47084db4b0SAkinobu Mita 		return 0;
48084db4b0SAkinobu Mita 
49084db4b0SAkinobu Mita 	pr_info("scanning for bad eraseblocks\n");
50084db4b0SAkinobu Mita 	for (i = 0; i < ebcnt; ++i) {
51084db4b0SAkinobu Mita 		bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0;
52084db4b0SAkinobu Mita 		if (bbt[i])
53084db4b0SAkinobu Mita 			bad += 1;
54084db4b0SAkinobu Mita 		cond_resched();
55084db4b0SAkinobu Mita 	}
56084db4b0SAkinobu Mita 	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
57084db4b0SAkinobu Mita 
58084db4b0SAkinobu Mita 	return 0;
59084db4b0SAkinobu Mita }
60084db4b0SAkinobu Mita 
mtdtest_erase_good_eraseblocks(struct mtd_info * mtd,unsigned char * bbt,unsigned int eb,int ebcnt)61084db4b0SAkinobu Mita int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
62084db4b0SAkinobu Mita 				unsigned int eb, int ebcnt)
63084db4b0SAkinobu Mita {
64084db4b0SAkinobu Mita 	int err;
65084db4b0SAkinobu Mita 	unsigned int i;
66084db4b0SAkinobu Mita 
67084db4b0SAkinobu Mita 	for (i = 0; i < ebcnt; ++i) {
68084db4b0SAkinobu Mita 		if (bbt[i])
69084db4b0SAkinobu Mita 			continue;
70084db4b0SAkinobu Mita 		err = mtdtest_erase_eraseblock(mtd, eb + i);
71084db4b0SAkinobu Mita 		if (err)
72084db4b0SAkinobu Mita 			return err;
73084db4b0SAkinobu Mita 		cond_resched();
74084db4b0SAkinobu Mita 	}
75084db4b0SAkinobu Mita 
76084db4b0SAkinobu Mita 	return 0;
77084db4b0SAkinobu Mita }
78084db4b0SAkinobu Mita 
mtdtest_read(struct mtd_info * mtd,loff_t addr,size_t size,void * buf)79084db4b0SAkinobu Mita int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf)
80084db4b0SAkinobu Mita {
81084db4b0SAkinobu Mita 	size_t read;
82084db4b0SAkinobu Mita 	int err;
83084db4b0SAkinobu Mita 
84084db4b0SAkinobu Mita 	err = mtd_read(mtd, addr, size, &read, buf);
85084db4b0SAkinobu Mita 	/* Ignore corrected ECC errors */
86084db4b0SAkinobu Mita 	if (mtd_is_bitflip(err))
87084db4b0SAkinobu Mita 		err = 0;
88084db4b0SAkinobu Mita 	if (!err && read != size)
89084db4b0SAkinobu Mita 		err = -EIO;
90abc173adSAkinobu Mita 	if (err)
91abc173adSAkinobu Mita 		pr_err("error: read failed at %#llx\n", addr);
92084db4b0SAkinobu Mita 
93084db4b0SAkinobu Mita 	return err;
94084db4b0SAkinobu Mita }
95084db4b0SAkinobu Mita 
mtdtest_write(struct mtd_info * mtd,loff_t addr,size_t size,const void * buf)96084db4b0SAkinobu Mita int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size,
97084db4b0SAkinobu Mita 		const void *buf)
98084db4b0SAkinobu Mita {
99084db4b0SAkinobu Mita 	size_t written;
100084db4b0SAkinobu Mita 	int err;
101084db4b0SAkinobu Mita 
102084db4b0SAkinobu Mita 	err = mtd_write(mtd, addr, size, &written, buf);
103084db4b0SAkinobu Mita 	if (!err && written != size)
104084db4b0SAkinobu Mita 		err = -EIO;
1058a9f4aa3SAkinobu Mita 	if (err)
1068a9f4aa3SAkinobu Mita 		pr_err("error: write failed at %#llx\n", addr);
107084db4b0SAkinobu Mita 
108084db4b0SAkinobu Mita 	return err;
109084db4b0SAkinobu Mita }
110