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

Configure Feed

Select the types of activity you want to include in your feed.

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