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