diff options
author | Akinobu Mita <akinobu.mita@gmail.com> | 2013-08-03 05:52:08 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2013-08-30 16:34:06 -0400 |
commit | a995c792280db558f994c253c1c3c3a55977d529 (patch) | |
tree | 7555f07ffad35a5dbb216a4a03eb11efdc5e35a3 /drivers/mtd/tests/readtest.c | |
parent | 084db4b020c7bb7f4169ae74fb9a685c30a2939d (diff) |
mtd: tests: rename sources in order to link a helper object
Each mtd test module have a single source whose name is the same as
the module name. In order to link a single object including helper
functions to every test module, this rename these sources to the
different names.
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Brian Norris <computersforpeace@gmail.com>
Cc: Vikram Narayanan <vikram186@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/tests/readtest.c')
-rw-r--r-- | drivers/mtd/tests/readtest.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/drivers/mtd/tests/readtest.c b/drivers/mtd/tests/readtest.c new file mode 100644 index 000000000000..2cdd0c47cac1 --- /dev/null +++ b/drivers/mtd/tests/readtest.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2008 Nokia Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License version 2 as published by | ||
6 | * the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; see the file COPYING. If not, write to the Free Software | ||
15 | * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
16 | * | ||
17 | * Check MTD device read. | ||
18 | * | ||
19 | * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> | ||
20 | */ | ||
21 | |||
22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/mtd/mtd.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/sched.h> | ||
31 | |||
32 | static int dev = -EINVAL; | ||
33 | module_param(dev, int, S_IRUGO); | ||
34 | MODULE_PARM_DESC(dev, "MTD device number to use"); | ||
35 | |||
36 | static struct mtd_info *mtd; | ||
37 | static unsigned char *iobuf; | ||
38 | static unsigned char *iobuf1; | ||
39 | static unsigned char *bbt; | ||
40 | |||
41 | static int pgsize; | ||
42 | static int ebcnt; | ||
43 | static int pgcnt; | ||
44 | |||
45 | static int read_eraseblock_by_page(int ebnum) | ||
46 | { | ||
47 | size_t read; | ||
48 | int i, ret, err = 0; | ||
49 | loff_t addr = ebnum * mtd->erasesize; | ||
50 | void *buf = iobuf; | ||
51 | void *oobbuf = iobuf1; | ||
52 | |||
53 | for (i = 0; i < pgcnt; i++) { | ||
54 | memset(buf, 0 , pgsize); | ||
55 | ret = mtd_read(mtd, addr, pgsize, &read, buf); | ||
56 | if (ret == -EUCLEAN) | ||
57 | ret = 0; | ||
58 | if (ret || read != pgsize) { | ||
59 | pr_err("error: read failed at %#llx\n", | ||
60 | (long long)addr); | ||
61 | if (!err) | ||
62 | err = ret; | ||
63 | if (!err) | ||
64 | err = -EINVAL; | ||
65 | } | ||
66 | if (mtd->oobsize) { | ||
67 | struct mtd_oob_ops ops; | ||
68 | |||
69 | ops.mode = MTD_OPS_PLACE_OOB; | ||
70 | ops.len = 0; | ||
71 | ops.retlen = 0; | ||
72 | ops.ooblen = mtd->oobsize; | ||
73 | ops.oobretlen = 0; | ||
74 | ops.ooboffs = 0; | ||
75 | ops.datbuf = NULL; | ||
76 | ops.oobbuf = oobbuf; | ||
77 | ret = mtd_read_oob(mtd, addr, &ops); | ||
78 | if ((ret && !mtd_is_bitflip(ret)) || | ||
79 | ops.oobretlen != mtd->oobsize) { | ||
80 | pr_err("error: read oob failed at " | ||
81 | "%#llx\n", (long long)addr); | ||
82 | if (!err) | ||
83 | err = ret; | ||
84 | if (!err) | ||
85 | err = -EINVAL; | ||
86 | } | ||
87 | oobbuf += mtd->oobsize; | ||
88 | } | ||
89 | addr += pgsize; | ||
90 | buf += pgsize; | ||
91 | } | ||
92 | |||
93 | return err; | ||
94 | } | ||
95 | |||
96 | static void dump_eraseblock(int ebnum) | ||
97 | { | ||
98 | int i, j, n; | ||
99 | char line[128]; | ||
100 | int pg, oob; | ||
101 | |||
102 | pr_info("dumping eraseblock %d\n", ebnum); | ||
103 | n = mtd->erasesize; | ||
104 | for (i = 0; i < n;) { | ||
105 | char *p = line; | ||
106 | |||
107 | p += sprintf(p, "%05x: ", i); | ||
108 | for (j = 0; j < 32 && i < n; j++, i++) | ||
109 | p += sprintf(p, "%02x", (unsigned int)iobuf[i]); | ||
110 | printk(KERN_CRIT "%s\n", line); | ||
111 | cond_resched(); | ||
112 | } | ||
113 | if (!mtd->oobsize) | ||
114 | return; | ||
115 | pr_info("dumping oob from eraseblock %d\n", ebnum); | ||
116 | n = mtd->oobsize; | ||
117 | for (pg = 0, i = 0; pg < pgcnt; pg++) | ||
118 | for (oob = 0; oob < n;) { | ||
119 | char *p = line; | ||
120 | |||
121 | p += sprintf(p, "%05x: ", i); | ||
122 | for (j = 0; j < 32 && oob < n; j++, oob++, i++) | ||
123 | p += sprintf(p, "%02x", | ||
124 | (unsigned int)iobuf1[i]); | ||
125 | printk(KERN_CRIT "%s\n", line); | ||
126 | cond_resched(); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static int is_block_bad(int ebnum) | ||
131 | { | ||
132 | loff_t addr = ebnum * mtd->erasesize; | ||
133 | int ret; | ||
134 | |||
135 | ret = mtd_block_isbad(mtd, addr); | ||
136 | if (ret) | ||
137 | pr_info("block %d is bad\n", ebnum); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static int scan_for_bad_eraseblocks(void) | ||
142 | { | ||
143 | int i, bad = 0; | ||
144 | |||
145 | bbt = kzalloc(ebcnt, GFP_KERNEL); | ||
146 | if (!bbt) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | if (!mtd_can_have_bb(mtd)) | ||
150 | return 0; | ||
151 | |||
152 | pr_info("scanning for bad eraseblocks\n"); | ||
153 | for (i = 0; i < ebcnt; ++i) { | ||
154 | bbt[i] = is_block_bad(i) ? 1 : 0; | ||
155 | if (bbt[i]) | ||
156 | bad += 1; | ||
157 | cond_resched(); | ||
158 | } | ||
159 | pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int __init mtd_readtest_init(void) | ||
164 | { | ||
165 | uint64_t tmp; | ||
166 | int err, i; | ||
167 | |||
168 | printk(KERN_INFO "\n"); | ||
169 | printk(KERN_INFO "=================================================\n"); | ||
170 | |||
171 | if (dev < 0) { | ||
172 | pr_info("Please specify a valid mtd-device via module parameter\n"); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | pr_info("MTD device: %d\n", dev); | ||
177 | |||
178 | mtd = get_mtd_device(NULL, dev); | ||
179 | if (IS_ERR(mtd)) { | ||
180 | err = PTR_ERR(mtd); | ||
181 | pr_err("error: Cannot get MTD device\n"); | ||
182 | return err; | ||
183 | } | ||
184 | |||
185 | if (mtd->writesize == 1) { | ||
186 | pr_info("not NAND flash, assume page size is 512 " | ||
187 | "bytes.\n"); | ||
188 | pgsize = 512; | ||
189 | } else | ||
190 | pgsize = mtd->writesize; | ||
191 | |||
192 | tmp = mtd->size; | ||
193 | do_div(tmp, mtd->erasesize); | ||
194 | ebcnt = tmp; | ||
195 | pgcnt = mtd->erasesize / pgsize; | ||
196 | |||
197 | pr_info("MTD device size %llu, eraseblock size %u, " | ||
198 | "page size %u, count of eraseblocks %u, pages per " | ||
199 | "eraseblock %u, OOB size %u\n", | ||
200 | (unsigned long long)mtd->size, mtd->erasesize, | ||
201 | pgsize, ebcnt, pgcnt, mtd->oobsize); | ||
202 | |||
203 | err = -ENOMEM; | ||
204 | iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); | ||
205 | if (!iobuf) | ||
206 | goto out; | ||
207 | iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); | ||
208 | if (!iobuf1) | ||
209 | goto out; | ||
210 | |||
211 | err = scan_for_bad_eraseblocks(); | ||
212 | if (err) | ||
213 | goto out; | ||
214 | |||
215 | /* Read all eraseblocks 1 page at a time */ | ||
216 | pr_info("testing page read\n"); | ||
217 | for (i = 0; i < ebcnt; ++i) { | ||
218 | int ret; | ||
219 | |||
220 | if (bbt[i]) | ||
221 | continue; | ||
222 | ret = read_eraseblock_by_page(i); | ||
223 | if (ret) { | ||
224 | dump_eraseblock(i); | ||
225 | if (!err) | ||
226 | err = ret; | ||
227 | } | ||
228 | cond_resched(); | ||
229 | } | ||
230 | |||
231 | if (err) | ||
232 | pr_info("finished with errors\n"); | ||
233 | else | ||
234 | pr_info("finished\n"); | ||
235 | |||
236 | out: | ||
237 | |||
238 | kfree(iobuf); | ||
239 | kfree(iobuf1); | ||
240 | kfree(bbt); | ||
241 | put_mtd_device(mtd); | ||
242 | if (err) | ||
243 | pr_info("error %d occurred\n", err); | ||
244 | printk(KERN_INFO "=================================================\n"); | ||
245 | return err; | ||
246 | } | ||
247 | module_init(mtd_readtest_init); | ||
248 | |||
249 | static void __exit mtd_readtest_exit(void) | ||
250 | { | ||
251 | return; | ||
252 | } | ||
253 | module_exit(mtd_readtest_exit); | ||
254 | |||
255 | MODULE_DESCRIPTION("Read test module"); | ||
256 | MODULE_AUTHOR("Adrian Hunter"); | ||
257 | MODULE_LICENSE("GPL"); | ||