1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #define pr_fmt(fmt) "mtd_test: " fmt
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/module.h>
5*4882a593Smuzhiyun #include <linux/sched.h>
6*4882a593Smuzhiyun #include <linux/printk.h>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "mtd_test.h"
9*4882a593Smuzhiyun
mtdtest_erase_eraseblock(struct mtd_info * mtd,unsigned int ebnum)10*4882a593Smuzhiyun int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
11*4882a593Smuzhiyun {
12*4882a593Smuzhiyun int err;
13*4882a593Smuzhiyun struct erase_info ei;
14*4882a593Smuzhiyun loff_t addr = (loff_t)ebnum * mtd->erasesize;
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun memset(&ei, 0, sizeof(struct erase_info));
17*4882a593Smuzhiyun ei.addr = addr;
18*4882a593Smuzhiyun ei.len = mtd->erasesize;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun err = mtd_erase(mtd, &ei);
21*4882a593Smuzhiyun if (err) {
22*4882a593Smuzhiyun pr_info("error %d while erasing EB %d\n", err, ebnum);
23*4882a593Smuzhiyun return err;
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun return 0;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
is_block_bad(struct mtd_info * mtd,unsigned int ebnum)29*4882a593Smuzhiyun static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun int ret;
32*4882a593Smuzhiyun loff_t addr = (loff_t)ebnum * mtd->erasesize;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun ret = mtd_block_isbad(mtd, addr);
35*4882a593Smuzhiyun if (ret)
36*4882a593Smuzhiyun pr_info("block %d is bad\n", ebnum);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun return ret;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
mtdtest_scan_for_bad_eraseblocks(struct mtd_info * mtd,unsigned char * bbt,unsigned int eb,int ebcnt)41*4882a593Smuzhiyun int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
42*4882a593Smuzhiyun unsigned int eb, int ebcnt)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun int i, bad = 0;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun if (!mtd_can_have_bb(mtd))
47*4882a593Smuzhiyun return 0;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun pr_info("scanning for bad eraseblocks\n");
50*4882a593Smuzhiyun for (i = 0; i < ebcnt; ++i) {
51*4882a593Smuzhiyun bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0;
52*4882a593Smuzhiyun if (bbt[i])
53*4882a593Smuzhiyun bad += 1;
54*4882a593Smuzhiyun cond_resched();
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun return 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
mtdtest_erase_good_eraseblocks(struct mtd_info * mtd,unsigned char * bbt,unsigned int eb,int ebcnt)61*4882a593Smuzhiyun int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
62*4882a593Smuzhiyun unsigned int eb, int ebcnt)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun int err;
65*4882a593Smuzhiyun unsigned int i;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun for (i = 0; i < ebcnt; ++i) {
68*4882a593Smuzhiyun if (bbt[i])
69*4882a593Smuzhiyun continue;
70*4882a593Smuzhiyun err = mtdtest_erase_eraseblock(mtd, eb + i);
71*4882a593Smuzhiyun if (err)
72*4882a593Smuzhiyun return err;
73*4882a593Smuzhiyun cond_resched();
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
mtdtest_read(struct mtd_info * mtd,loff_t addr,size_t size,void * buf)79*4882a593Smuzhiyun int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun size_t read;
82*4882a593Smuzhiyun int err;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun err = mtd_read(mtd, addr, size, &read, buf);
85*4882a593Smuzhiyun /* Ignore corrected ECC errors */
86*4882a593Smuzhiyun if (mtd_is_bitflip(err))
87*4882a593Smuzhiyun err = 0;
88*4882a593Smuzhiyun if (!err && read != size)
89*4882a593Smuzhiyun err = -EIO;
90*4882a593Smuzhiyun if (err)
91*4882a593Smuzhiyun pr_err("error: read failed at %#llx\n", addr);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun return err;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
mtdtest_write(struct mtd_info * mtd,loff_t addr,size_t size,const void * buf)96*4882a593Smuzhiyun int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size,
97*4882a593Smuzhiyun const void *buf)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun size_t written;
100*4882a593Smuzhiyun int err;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun err = mtd_write(mtd, addr, size, &written, buf);
103*4882a593Smuzhiyun if (!err && written != size)
104*4882a593Smuzhiyun err = -EIO;
105*4882a593Smuzhiyun if (err)
106*4882a593Smuzhiyun pr_err("error: write failed at %#llx\n", addr);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return err;
109*4882a593Smuzhiyun }
110