Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MTD: tests: add mtd_pagetest

This test checks that NAND pages read/write work fine.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

+632
+632
drivers/mtd/tests/mtd_pagetest.c
··· 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 + 32 + static int dev; 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 *twopages; 38 + static unsigned char *writebuf; 39 + static unsigned char *boundary; 40 + static unsigned char *bbt; 41 + 42 + static int pgsize; 43 + static int bufsize; 44 + static int ebcnt; 45 + static int pgcnt; 46 + static int errcnt; 47 + static unsigned long next = 1; 48 + 49 + static inline unsigned int simple_rand(void) 50 + { 51 + next = next * 1103515245 + 12345; 52 + return (unsigned int)((next / 65536) % 32768); 53 + } 54 + 55 + static inline void simple_srand(unsigned long seed) 56 + { 57 + next = seed; 58 + } 59 + 60 + static 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 + 68 + static 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 + 94 + static 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 + 110 + static 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 + 203 + static 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 + 309 + static 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 + 406 + static 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 + 467 + static 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 + 478 + static 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 + 500 + static 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); 610 + out: 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 + } 622 + module_init(mtd_pagetest_init); 623 + 624 + static void __exit mtd_pagetest_exit(void) 625 + { 626 + return; 627 + } 628 + module_exit(mtd_pagetest_exit); 629 + 630 + MODULE_DESCRIPTION("NAND page test"); 631 + MODULE_AUTHOR("Adrian Hunter"); 632 + MODULE_LICENSE("GPL");