aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-12-08 06:34:16 -0500
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-12-08 06:56:14 -0500
commite73f217439c7f3e49f9c0048bd04cb77ba656e66 (patch)
tree367b1e7758c95f0d3655fd654f574c105fbad3e9 /drivers
parente3644da7563d844e94b186a468e480c5575a6572 (diff)
MTD: tests: add mtd_pagetest
This test checks that NAND pages read/write work fine. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/tests/mtd_pagetest.c632
1 files changed, 632 insertions, 0 deletions
diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c
new file mode 100644
index 000000000000..9648818b9e2c
--- /dev/null
+++ b/drivers/mtd/tests/mtd_pagetest.c
@@ -0,0 +1,632 @@
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 * Test page read and write on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#include <asm/div64.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/err.h>
27#include <linux/mtd/mtd.h>
28#include <linux/sched.h>
29
30#define PRINT_PREF KERN_INFO "mtd_pagetest: "
31
32static int dev;
33module_param(dev, int, S_IRUGO);
34MODULE_PARM_DESC(dev, "MTD device number to use");
35
36static struct mtd_info *mtd;
37static unsigned char *twopages;
38static unsigned char *writebuf;
39static unsigned char *boundary;
40static unsigned char *bbt;
41
42static int pgsize;
43static int bufsize;
44static int ebcnt;
45static int pgcnt;
46static int errcnt;
47static unsigned long next = 1;
48
49static inline unsigned int simple_rand(void)
50{
51 next = next * 1103515245 + 12345;
52 return (unsigned int)((next / 65536) % 32768);
53}
54
55static inline void simple_srand(unsigned long seed)
56{
57 next = seed;
58}
59
60static void set_random_data(unsigned char *buf, size_t len)
61{
62 size_t i;
63
64 for (i = 0; i < len; ++i)
65 buf[i] = simple_rand();
66}
67
68static int erase_eraseblock(int ebnum)
69{
70 int err;
71 struct erase_info ei;
72 loff_t addr = ebnum * mtd->erasesize;
73
74 memset(&ei, 0, sizeof(struct erase_info));
75 ei.mtd = mtd;
76 ei.addr = addr;
77 ei.len = mtd->erasesize;
78
79 err = mtd->erase(mtd, &ei);
80 if (err) {
81 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
82 return err;
83 }
84
85 if (ei.state == MTD_ERASE_FAILED) {
86 printk(PRINT_PREF "some erase error occurred at EB %d\n",
87 ebnum);
88 return -EIO;
89 }
90
91 return 0;
92}
93
94static int write_eraseblock(int ebnum)
95{
96 int err = 0;
97 size_t written = 0;
98 loff_t addr = ebnum * mtd->erasesize;
99
100 set_random_data(writebuf, mtd->erasesize);
101 cond_resched();
102 err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf);
103 if (err || written != mtd->erasesize)
104 printk(PRINT_PREF "error: write failed at %#llx\n",
105 (long long)addr);
106
107 return err;
108}
109
110static int verify_eraseblock(int ebnum)
111{
112 uint32_t j;
113 size_t read = 0;
114 int err = 0, i;
115 loff_t addr0, addrn;
116 loff_t addr = ebnum * mtd->erasesize;
117
118 addr0 = 0;
119 for (i = 0; bbt[i] && i < ebcnt; ++i)
120 addr0 += mtd->erasesize;
121
122 addrn = mtd->size;
123 for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i)
124 addrn -= mtd->erasesize;
125
126 set_random_data(writebuf, mtd->erasesize);
127 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
128 /* Do a read to set the internal dataRAMs to different data */
129 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
130 if (err == -EUCLEAN)
131 err = 0;
132 if (err || read != bufsize) {
133 printk(PRINT_PREF "error: read failed at %#llx\n",
134 (long long)addr0);
135 return err;
136 }
137 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
138 if (err == -EUCLEAN)
139 err = 0;
140 if (err || read != bufsize) {
141 printk(PRINT_PREF "error: read failed at %#llx\n",
142 (long long)(addrn - bufsize));
143 return err;
144 }
145 memset(twopages, 0, bufsize);
146 read = 0;
147 err = mtd->read(mtd, addr, bufsize, &read, twopages);
148 if (err == -EUCLEAN)
149 err = 0;
150 if (err || read != bufsize) {
151 printk(PRINT_PREF "error: read failed at %#llx\n",
152 (long long)addr);
153 break;
154 }
155 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
156 printk(PRINT_PREF "error: verify failed at %#llx\n",
157 (long long)addr);
158 errcnt += 1;
159 }
160 }
161 /* Check boundary between eraseblocks */
162 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
163 unsigned long oldnext = next;
164 /* Do a read to set the internal dataRAMs to different data */
165 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
166 if (err == -EUCLEAN)
167 err = 0;
168 if (err || read != bufsize) {
169 printk(PRINT_PREF "error: read failed at %#llx\n",
170 (long long)addr0);
171 return err;
172 }
173 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
174 if (err == -EUCLEAN)
175 err = 0;
176 if (err || read != bufsize) {
177 printk(PRINT_PREF "error: read failed at %#llx\n",
178 (long long)(addrn - bufsize));
179 return err;
180 }
181 memset(twopages, 0, bufsize);
182 read = 0;
183 err = mtd->read(mtd, addr, bufsize, &read, twopages);
184 if (err == -EUCLEAN)
185 err = 0;
186 if (err || read != bufsize) {
187 printk(PRINT_PREF "error: read failed at %#llx\n",
188 (long long)addr);
189 return err;
190 }
191 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
192 set_random_data(boundary + pgsize, pgsize);
193 if (memcmp(twopages, boundary, bufsize)) {
194 printk(PRINT_PREF "error: verify failed at %#llx\n",
195 (long long)addr);
196 errcnt += 1;
197 }
198 next = oldnext;
199 }
200 return err;
201}
202
203static int crosstest(void)
204{
205 size_t read = 0;
206 int err = 0, i;
207 loff_t addr, addr0, addrn;
208 unsigned char *pp1, *pp2, *pp3, *pp4;
209
210 printk(PRINT_PREF "crosstest\n");
211 pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
212 if (!pp1) {
213 printk(PRINT_PREF "error: cannot allocate memory\n");
214 return -ENOMEM;
215 }
216 pp2 = pp1 + pgsize;
217 pp3 = pp2 + pgsize;
218 pp4 = pp3 + pgsize;
219 memset(pp1, 0, pgsize * 4);
220
221 addr0 = 0;
222 for (i = 0; bbt[i] && i < ebcnt; ++i)
223 addr0 += mtd->erasesize;
224
225 addrn = mtd->size;
226 for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i)
227 addrn -= mtd->erasesize;
228
229 /* Read 2nd-to-last page to pp1 */
230 read = 0;
231 addr = addrn - pgsize - pgsize;
232 err = mtd->read(mtd, addr, pgsize, &read, pp1);
233 if (err == -EUCLEAN)
234 err = 0;
235 if (err || read != pgsize) {
236 printk(PRINT_PREF "error: read failed at %#llx\n",
237 (long long)addr);
238 kfree(pp1);
239 return err;
240 }
241
242 /* Read 3rd-to-last page to pp1 */
243 read = 0;
244 addr = addrn - pgsize - pgsize - pgsize;
245 err = mtd->read(mtd, addr, pgsize, &read, pp1);
246 if (err == -EUCLEAN)
247 err = 0;
248 if (err || read != pgsize) {
249 printk(PRINT_PREF "error: read failed at %#llx\n",
250 (long long)addr);
251 kfree(pp1);
252 return err;
253 }
254
255 /* Read first page to pp2 */
256 read = 0;
257 addr = addr0;
258 printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
259 err = mtd->read(mtd, addr, pgsize, &read, pp2);
260 if (err == -EUCLEAN)
261 err = 0;
262 if (err || read != pgsize) {
263 printk(PRINT_PREF "error: read failed at %#llx\n",
264 (long long)addr);
265 kfree(pp1);
266 return err;
267 }
268
269 /* Read last page to pp3 */
270 read = 0;
271 addr = addrn - pgsize;
272 printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
273 err = mtd->read(mtd, addr, pgsize, &read, pp3);
274 if (err == -EUCLEAN)
275 err = 0;
276 if (err || read != pgsize) {
277 printk(PRINT_PREF "error: read failed at %#llx\n",
278 (long long)addr);
279 kfree(pp1);
280 return err;
281 }
282
283 /* Read first page again to pp4 */
284 read = 0;
285 addr = addr0;
286 printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
287 err = mtd->read(mtd, addr, pgsize, &read, pp4);
288 if (err == -EUCLEAN)
289 err = 0;
290 if (err || read != pgsize) {
291 printk(PRINT_PREF "error: read failed at %#llx\n",
292 (long long)addr);
293 kfree(pp1);
294 return err;
295 }
296
297 /* pp2 and pp4 should be the same */
298 printk(PRINT_PREF "verifying pages read at %#llx match\n",
299 (long long)addr0);
300 if (memcmp(pp2, pp4, pgsize)) {
301 printk(PRINT_PREF "verify failed!\n");
302 errcnt += 1;
303 } else if (!err)
304 printk(PRINT_PREF "crosstest ok\n");
305 kfree(pp1);
306 return err;
307}
308
309static int erasecrosstest(void)
310{
311 size_t read = 0, written = 0;
312 int err = 0, i, ebnum, ok = 1, ebnum2;
313 loff_t addr0;
314 char *readbuf = twopages;
315
316 printk(PRINT_PREF "erasecrosstest\n");
317
318 ebnum = 0;
319 addr0 = 0;
320 for (i = 0; bbt[i] && i < ebcnt; ++i) {
321 addr0 += mtd->erasesize;
322 ebnum += 1;
323 }
324
325 ebnum2 = ebcnt - 1;
326 while (ebnum2 && bbt[ebnum2])
327 ebnum2 -= 1;
328
329 printk(PRINT_PREF "erasing block %d\n", ebnum);
330 err = erase_eraseblock(ebnum);
331 if (err)
332 return err;
333
334 printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
335 set_random_data(writebuf, pgsize);
336 strcpy(writebuf, "There is no data like this!");
337 err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
338 if (err || written != pgsize) {
339 printk(PRINT_PREF "error: write failed at %#llx\n",
340 (long long)addr0);
341 return err ? err : -1;
342 }
343
344 printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
345 memset(readbuf, 0, pgsize);
346 err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
347 if (err == -EUCLEAN)
348 err = 0;
349 if (err || read != pgsize) {
350 printk(PRINT_PREF "error: read failed at %#llx\n",
351 (long long)addr0);
352 return err ? err : -1;
353 }
354
355 printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
356 if (memcmp(writebuf, readbuf, pgsize)) {
357 printk(PRINT_PREF "verify failed!\n");
358 errcnt += 1;
359 ok = 0;
360 return err;
361 }
362
363 printk(PRINT_PREF "erasing block %d\n", ebnum);
364 err = erase_eraseblock(ebnum);
365 if (err)
366 return err;
367
368 printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
369 set_random_data(writebuf, pgsize);
370 strcpy(writebuf, "There is no data like this!");
371 err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
372 if (err || written != pgsize) {
373 printk(PRINT_PREF "error: write failed at %#llx\n",
374 (long long)addr0);
375 return err ? err : -1;
376 }
377
378 printk(PRINT_PREF "erasing block %d\n", ebnum2);
379 err = erase_eraseblock(ebnum2);
380 if (err)
381 return err;
382
383 printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
384 memset(readbuf, 0, pgsize);
385 err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
386 if (err == -EUCLEAN)
387 err = 0;
388 if (err || read != pgsize) {
389 printk(PRINT_PREF "error: read failed at %#llx\n",
390 (long long)addr0);
391 return err ? err : -1;
392 }
393
394 printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
395 if (memcmp(writebuf, readbuf, pgsize)) {
396 printk(PRINT_PREF "verify failed!\n");
397 errcnt += 1;
398 ok = 0;
399 }
400
401 if (ok && !err)
402 printk(PRINT_PREF "erasecrosstest ok\n");
403 return err;
404}
405
406static int erasetest(void)
407{
408 size_t read = 0, written = 0;
409 int err = 0, i, ebnum, ok = 1;
410 loff_t addr0;
411
412 printk(PRINT_PREF "erasetest\n");
413
414 ebnum = 0;
415 addr0 = 0;
416 for (i = 0; bbt[i] && i < ebcnt; ++i) {
417 addr0 += mtd->erasesize;
418 ebnum += 1;
419 }
420
421 printk(PRINT_PREF "erasing block %d\n", ebnum);
422 err = erase_eraseblock(ebnum);
423 if (err)
424 return err;
425
426 printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
427 set_random_data(writebuf, pgsize);
428 err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
429 if (err || written != pgsize) {
430 printk(PRINT_PREF "error: write failed at %#llx\n",
431 (long long)addr0);
432 return err ? err : -1;
433 }
434
435 printk(PRINT_PREF "erasing block %d\n", ebnum);
436 err = erase_eraseblock(ebnum);
437 if (err)
438 return err;
439
440 printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
441 err = mtd->read(mtd, addr0, pgsize, &read, twopages);
442 if (err == -EUCLEAN)
443 err = 0;
444 if (err || read != pgsize) {
445 printk(PRINT_PREF "error: read failed at %#llx\n",
446 (long long)addr0);
447 return err ? err : -1;
448 }
449
450 printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
451 ebnum);
452 for (i = 0; i < pgsize; ++i)
453 if (twopages[i] != 0xff) {
454 printk(PRINT_PREF "verifying all 0xff failed at %d\n",
455 i);
456 errcnt += 1;
457 ok = 0;
458 break;
459 }
460
461 if (ok && !err)
462 printk(PRINT_PREF "erasetest ok\n");
463
464 return err;
465}
466
467static int is_block_bad(int ebnum)
468{
469 loff_t addr = ebnum * mtd->erasesize;
470 int ret;
471
472 ret = mtd->block_isbad(mtd, addr);
473 if (ret)
474 printk(PRINT_PREF "block %d is bad\n", ebnum);
475 return ret;
476}
477
478static int scan_for_bad_eraseblocks(void)
479{
480 int i, bad = 0;
481
482 bbt = kmalloc(ebcnt, GFP_KERNEL);
483 if (!bbt) {
484 printk(PRINT_PREF "error: cannot allocate memory\n");
485 return -ENOMEM;
486 }
487 memset(bbt, 0 , ebcnt);
488
489 printk(PRINT_PREF "scanning for bad eraseblocks\n");
490 for (i = 0; i < ebcnt; ++i) {
491 bbt[i] = is_block_bad(i) ? 1 : 0;
492 if (bbt[i])
493 bad += 1;
494 cond_resched();
495 }
496 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
497 return 0;
498}
499
500static int __init mtd_pagetest_init(void)
501{
502 int err = 0;
503 uint64_t tmp;
504 uint32_t i;
505
506 printk(KERN_INFO "\n");
507 printk(KERN_INFO "=================================================\n");
508 printk(PRINT_PREF "MTD device: %d\n", dev);
509
510 mtd = get_mtd_device(NULL, dev);
511 if (IS_ERR(mtd)) {
512 err = PTR_ERR(mtd);
513 printk(PRINT_PREF "error: cannot get MTD device\n");
514 return err;
515 }
516
517 if (mtd->type != MTD_NANDFLASH) {
518 printk(PRINT_PREF "this test requires NAND flash\n");
519 goto out;
520 }
521
522 tmp = mtd->size;
523 do_div(tmp, mtd->erasesize);
524 ebcnt = tmp;
525 pgcnt = mtd->erasesize / mtd->writesize;
526
527 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
528 "page size %u, count of eraseblocks %u, pages per "
529 "eraseblock %u, OOB size %u\n",
530 (unsigned long long)mtd->size, mtd->erasesize,
531 pgsize, ebcnt, pgcnt, mtd->oobsize);
532
533 err = -ENOMEM;
534 bufsize = pgsize * 2;
535 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
536 if (!writebuf) {
537 printk(PRINT_PREF "error: cannot allocate memory\n");
538 goto out;
539 }
540 twopages = kmalloc(bufsize, GFP_KERNEL);
541 if (!twopages) {
542 printk(PRINT_PREF "error: cannot allocate memory\n");
543 goto out;
544 }
545 boundary = kmalloc(bufsize, GFP_KERNEL);
546 if (!boundary) {
547 printk(PRINT_PREF "error: cannot allocate memory\n");
548 goto out;
549 }
550
551 err = scan_for_bad_eraseblocks();
552 if (err)
553 goto out;
554
555 /* Erase all eraseblocks */
556 printk(PRINT_PREF "erasing whole device\n");
557 for (i = 0; i < ebcnt; ++i) {
558 if (bbt[i])
559 continue;
560 err = erase_eraseblock(i);
561 if (err)
562 goto out;
563 cond_resched();
564 }
565 printk(PRINT_PREF "erased %u eraseblocks\n", i);
566
567 /* Write all eraseblocks */
568 simple_srand(1);
569 printk(PRINT_PREF "writing whole device\n");
570 for (i = 0; i < ebcnt; ++i) {
571 if (bbt[i])
572 continue;
573 err = write_eraseblock(i);
574 if (err)
575 goto out;
576 if (i % 256 == 0)
577 printk(PRINT_PREF "written up to eraseblock %u\n", i);
578 cond_resched();
579 }
580 printk(PRINT_PREF "written %u eraseblocks\n", i);
581
582 /* Check all eraseblocks */
583 simple_srand(1);
584 printk(PRINT_PREF "verifying all eraseblocks\n");
585 for (i = 0; i < ebcnt; ++i) {
586 if (bbt[i])
587 continue;
588 err = verify_eraseblock(i);
589 if (err)
590 goto out;
591 if (i % 256 == 0)
592 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
593 cond_resched();
594 }
595 printk(PRINT_PREF "verified %u eraseblocks\n", i);
596
597 err = crosstest();
598 if (err)
599 goto out;
600
601 err = erasecrosstest();
602 if (err)
603 goto out;
604
605 err = erasetest();
606 if (err)
607 goto out;
608
609 printk(PRINT_PREF "finished with %d errors\n", errcnt);
610out:
611
612 kfree(bbt);
613 kfree(boundary);
614 kfree(twopages);
615 kfree(writebuf);
616 put_mtd_device(mtd);
617 if (err)
618 printk(PRINT_PREF "error %d occurred\n", err);
619 printk(KERN_INFO "=================================================\n");
620 return err;
621}
622module_init(mtd_pagetest_init);
623
624static void __exit mtd_pagetest_exit(void)
625{
626 return;
627}
628module_exit(mtd_pagetest_exit);
629
630MODULE_DESCRIPTION("NAND page test");
631MODULE_AUTHOR("Adrian Hunter");
632MODULE_LICENSE("GPL");