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