Merge branch 'gma500-next' of git://github.com/patjak/drm-gma500 into drm-next
[deliverable/linux.git] / drivers / mtd / tests / mtd_subpagetest.c
1 /*
2 * Copyright (C) 2006-2007 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 * Test sub-page read and write on MTD device.
18 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
19 *
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 #include <linux/random.h>
32
33 static int dev = -EINVAL;
34 module_param(dev, int, S_IRUGO);
35 MODULE_PARM_DESC(dev, "MTD device number to use");
36
37 static struct mtd_info *mtd;
38 static unsigned char *writebuf;
39 static unsigned char *readbuf;
40 static unsigned char *bbt;
41
42 static int subpgsize;
43 static int bufsize;
44 static int ebcnt;
45 static int pgcnt;
46 static int errcnt;
47 static struct rnd_state rnd_state;
48
49 static inline void clear_data(unsigned char *buf, size_t len)
50 {
51 memset(buf, 0, len);
52 }
53
54 static int erase_eraseblock(int ebnum)
55 {
56 int err;
57 struct erase_info ei;
58 loff_t addr = ebnum * mtd->erasesize;
59
60 memset(&ei, 0, sizeof(struct erase_info));
61 ei.mtd = mtd;
62 ei.addr = addr;
63 ei.len = mtd->erasesize;
64
65 err = mtd_erase(mtd, &ei);
66 if (err) {
67 pr_err("error %d while erasing EB %d\n", err, ebnum);
68 return err;
69 }
70
71 if (ei.state == MTD_ERASE_FAILED) {
72 pr_err("some erase error occurred at EB %d\n",
73 ebnum);
74 return -EIO;
75 }
76
77 return 0;
78 }
79
80 static int erase_whole_device(void)
81 {
82 int err;
83 unsigned int i;
84
85 pr_info("erasing whole device\n");
86 for (i = 0; i < ebcnt; ++i) {
87 if (bbt[i])
88 continue;
89 err = erase_eraseblock(i);
90 if (err)
91 return err;
92 cond_resched();
93 }
94 pr_info("erased %u eraseblocks\n", i);
95 return 0;
96 }
97
98 static int write_eraseblock(int ebnum)
99 {
100 size_t written;
101 int err = 0;
102 loff_t addr = ebnum * mtd->erasesize;
103
104 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
105 err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
106 if (unlikely(err || written != subpgsize)) {
107 pr_err("error: write failed at %#llx\n",
108 (long long)addr);
109 if (written != subpgsize) {
110 pr_err(" write size: %#x\n", subpgsize);
111 pr_err(" written: %#zx\n", written);
112 }
113 return err ? err : -1;
114 }
115
116 addr += subpgsize;
117
118 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
119 err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
120 if (unlikely(err || written != subpgsize)) {
121 pr_err("error: write failed at %#llx\n",
122 (long long)addr);
123 if (written != subpgsize) {
124 pr_err(" write size: %#x\n", subpgsize);
125 pr_err(" written: %#zx\n", written);
126 }
127 return err ? err : -1;
128 }
129
130 return err;
131 }
132
133 static int write_eraseblock2(int ebnum)
134 {
135 size_t written;
136 int err = 0, k;
137 loff_t addr = ebnum * mtd->erasesize;
138
139 for (k = 1; k < 33; ++k) {
140 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
141 break;
142 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
143 err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
144 if (unlikely(err || written != subpgsize * k)) {
145 pr_err("error: write failed at %#llx\n",
146 (long long)addr);
147 if (written != subpgsize) {
148 pr_err(" write size: %#x\n",
149 subpgsize * k);
150 pr_err(" written: %#08zx\n",
151 written);
152 }
153 return err ? err : -1;
154 }
155 addr += subpgsize * k;
156 }
157
158 return err;
159 }
160
161 static void print_subpage(unsigned char *p)
162 {
163 int i, j;
164
165 for (i = 0; i < subpgsize; ) {
166 for (j = 0; i < subpgsize && j < 32; ++i, ++j)
167 printk("%02x", *p++);
168 printk("\n");
169 }
170 }
171
172 static int verify_eraseblock(int ebnum)
173 {
174 size_t read;
175 int err = 0;
176 loff_t addr = ebnum * mtd->erasesize;
177
178 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
179 clear_data(readbuf, subpgsize);
180 err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
181 if (unlikely(err || read != subpgsize)) {
182 if (mtd_is_bitflip(err) && read == subpgsize) {
183 pr_info("ECC correction at %#llx\n",
184 (long long)addr);
185 err = 0;
186 } else {
187 pr_err("error: read failed at %#llx\n",
188 (long long)addr);
189 return err ? err : -1;
190 }
191 }
192 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
193 pr_err("error: verify failed at %#llx\n",
194 (long long)addr);
195 pr_info("------------- written----------------\n");
196 print_subpage(writebuf);
197 pr_info("------------- read ------------------\n");
198 print_subpage(readbuf);
199 pr_info("-------------------------------------\n");
200 errcnt += 1;
201 }
202
203 addr += subpgsize;
204
205 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
206 clear_data(readbuf, subpgsize);
207 err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
208 if (unlikely(err || read != subpgsize)) {
209 if (mtd_is_bitflip(err) && read == subpgsize) {
210 pr_info("ECC correction at %#llx\n",
211 (long long)addr);
212 err = 0;
213 } else {
214 pr_err("error: read failed at %#llx\n",
215 (long long)addr);
216 return err ? err : -1;
217 }
218 }
219 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
220 pr_info("error: verify failed at %#llx\n",
221 (long long)addr);
222 pr_info("------------- written----------------\n");
223 print_subpage(writebuf);
224 pr_info("------------- read ------------------\n");
225 print_subpage(readbuf);
226 pr_info("-------------------------------------\n");
227 errcnt += 1;
228 }
229
230 return err;
231 }
232
233 static int verify_eraseblock2(int ebnum)
234 {
235 size_t read;
236 int err = 0, k;
237 loff_t addr = ebnum * mtd->erasesize;
238
239 for (k = 1; k < 33; ++k) {
240 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
241 break;
242 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
243 clear_data(readbuf, subpgsize * k);
244 err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
245 if (unlikely(err || read != subpgsize * k)) {
246 if (mtd_is_bitflip(err) && read == subpgsize * k) {
247 pr_info("ECC correction at %#llx\n",
248 (long long)addr);
249 err = 0;
250 } else {
251 pr_err("error: read failed at "
252 "%#llx\n", (long long)addr);
253 return err ? err : -1;
254 }
255 }
256 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
257 pr_err("error: verify failed at %#llx\n",
258 (long long)addr);
259 errcnt += 1;
260 }
261 addr += subpgsize * k;
262 }
263
264 return err;
265 }
266
267 static int verify_eraseblock_ff(int ebnum)
268 {
269 uint32_t j;
270 size_t read;
271 int err = 0;
272 loff_t addr = ebnum * mtd->erasesize;
273
274 memset(writebuf, 0xff, subpgsize);
275 for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
276 clear_data(readbuf, subpgsize);
277 err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
278 if (unlikely(err || read != subpgsize)) {
279 if (mtd_is_bitflip(err) && read == subpgsize) {
280 pr_info("ECC correction at %#llx\n",
281 (long long)addr);
282 err = 0;
283 } else {
284 pr_err("error: read failed at "
285 "%#llx\n", (long long)addr);
286 return err ? err : -1;
287 }
288 }
289 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
290 pr_err("error: verify 0xff failed at "
291 "%#llx\n", (long long)addr);
292 errcnt += 1;
293 }
294 addr += subpgsize;
295 }
296
297 return err;
298 }
299
300 static int verify_all_eraseblocks_ff(void)
301 {
302 int err;
303 unsigned int i;
304
305 pr_info("verifying all eraseblocks for 0xff\n");
306 for (i = 0; i < ebcnt; ++i) {
307 if (bbt[i])
308 continue;
309 err = verify_eraseblock_ff(i);
310 if (err)
311 return err;
312 if (i % 256 == 0)
313 pr_info("verified up to eraseblock %u\n", i);
314 cond_resched();
315 }
316 pr_info("verified %u eraseblocks\n", i);
317 return 0;
318 }
319
320 static int is_block_bad(int ebnum)
321 {
322 loff_t addr = ebnum * mtd->erasesize;
323 int ret;
324
325 ret = mtd_block_isbad(mtd, addr);
326 if (ret)
327 pr_info("block %d is bad\n", ebnum);
328 return ret;
329 }
330
331 static int scan_for_bad_eraseblocks(void)
332 {
333 int i, bad = 0;
334
335 bbt = kzalloc(ebcnt, GFP_KERNEL);
336 if (!bbt) {
337 pr_err("error: cannot allocate memory\n");
338 return -ENOMEM;
339 }
340
341 pr_info("scanning for bad eraseblocks\n");
342 for (i = 0; i < ebcnt; ++i) {
343 bbt[i] = is_block_bad(i) ? 1 : 0;
344 if (bbt[i])
345 bad += 1;
346 cond_resched();
347 }
348 pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
349 return 0;
350 }
351
352 static int __init mtd_subpagetest_init(void)
353 {
354 int err = 0;
355 uint32_t i;
356 uint64_t tmp;
357
358 printk(KERN_INFO "\n");
359 printk(KERN_INFO "=================================================\n");
360
361 if (dev < 0) {
362 pr_info("Please specify a valid mtd-device via module parameter\n");
363 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
364 return -EINVAL;
365 }
366
367 pr_info("MTD device: %d\n", dev);
368
369 mtd = get_mtd_device(NULL, dev);
370 if (IS_ERR(mtd)) {
371 err = PTR_ERR(mtd);
372 pr_err("error: cannot get MTD device\n");
373 return err;
374 }
375
376 if (mtd->type != MTD_NANDFLASH) {
377 pr_info("this test requires NAND flash\n");
378 goto out;
379 }
380
381 subpgsize = mtd->writesize >> mtd->subpage_sft;
382 tmp = mtd->size;
383 do_div(tmp, mtd->erasesize);
384 ebcnt = tmp;
385 pgcnt = mtd->erasesize / mtd->writesize;
386
387 pr_info("MTD device size %llu, eraseblock size %u, "
388 "page size %u, subpage size %u, count of eraseblocks %u, "
389 "pages per eraseblock %u, OOB size %u\n",
390 (unsigned long long)mtd->size, mtd->erasesize,
391 mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
392
393 err = -ENOMEM;
394 bufsize = subpgsize * 32;
395 writebuf = kmalloc(bufsize, GFP_KERNEL);
396 if (!writebuf) {
397 pr_info("error: cannot allocate memory\n");
398 goto out;
399 }
400 readbuf = kmalloc(bufsize, GFP_KERNEL);
401 if (!readbuf) {
402 pr_info("error: cannot allocate memory\n");
403 goto out;
404 }
405
406 err = scan_for_bad_eraseblocks();
407 if (err)
408 goto out;
409
410 err = erase_whole_device();
411 if (err)
412 goto out;
413
414 pr_info("writing whole device\n");
415 prandom_seed_state(&rnd_state, 1);
416 for (i = 0; i < ebcnt; ++i) {
417 if (bbt[i])
418 continue;
419 err = write_eraseblock(i);
420 if (unlikely(err))
421 goto out;
422 if (i % 256 == 0)
423 pr_info("written up to eraseblock %u\n", i);
424 cond_resched();
425 }
426 pr_info("written %u eraseblocks\n", i);
427
428 prandom_seed_state(&rnd_state, 1);
429 pr_info("verifying all eraseblocks\n");
430 for (i = 0; i < ebcnt; ++i) {
431 if (bbt[i])
432 continue;
433 err = verify_eraseblock(i);
434 if (unlikely(err))
435 goto out;
436 if (i % 256 == 0)
437 pr_info("verified up to eraseblock %u\n", i);
438 cond_resched();
439 }
440 pr_info("verified %u eraseblocks\n", i);
441
442 err = erase_whole_device();
443 if (err)
444 goto out;
445
446 err = verify_all_eraseblocks_ff();
447 if (err)
448 goto out;
449
450 /* Write all eraseblocks */
451 prandom_seed_state(&rnd_state, 3);
452 pr_info("writing whole device\n");
453 for (i = 0; i < ebcnt; ++i) {
454 if (bbt[i])
455 continue;
456 err = write_eraseblock2(i);
457 if (unlikely(err))
458 goto out;
459 if (i % 256 == 0)
460 pr_info("written up to eraseblock %u\n", i);
461 cond_resched();
462 }
463 pr_info("written %u eraseblocks\n", i);
464
465 /* Check all eraseblocks */
466 prandom_seed_state(&rnd_state, 3);
467 pr_info("verifying all eraseblocks\n");
468 for (i = 0; i < ebcnt; ++i) {
469 if (bbt[i])
470 continue;
471 err = verify_eraseblock2(i);
472 if (unlikely(err))
473 goto out;
474 if (i % 256 == 0)
475 pr_info("verified up to eraseblock %u\n", i);
476 cond_resched();
477 }
478 pr_info("verified %u eraseblocks\n", i);
479
480 err = erase_whole_device();
481 if (err)
482 goto out;
483
484 err = verify_all_eraseblocks_ff();
485 if (err)
486 goto out;
487
488 pr_info("finished with %d errors\n", errcnt);
489
490 out:
491 kfree(bbt);
492 kfree(readbuf);
493 kfree(writebuf);
494 put_mtd_device(mtd);
495 if (err)
496 pr_info("error %d occurred\n", err);
497 printk(KERN_INFO "=================================================\n");
498 return err;
499 }
500 module_init(mtd_subpagetest_init);
501
502 static void __exit mtd_subpagetest_exit(void)
503 {
504 return;
505 }
506 module_exit(mtd_subpagetest_exit);
507
508 MODULE_DESCRIPTION("Subpage test module");
509 MODULE_AUTHOR("Adrian Hunter");
510 MODULE_LICENSE("GPL");
This page took 0.056124 seconds and 6 git commands to generate.