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

MTD: tests: add mtd_subpagetest

This tests makes sure sub-pages on NAND MTD device work fine.

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

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