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 v2.6.30-rc7 525 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/sched.h> 28 29#define PRINT_PREF KERN_INFO "mtd_subpagetest: " 30 31static int dev; 32module_param(dev, int, S_IRUGO); 33MODULE_PARM_DESC(dev, "MTD device number to use"); 34 35static struct mtd_info *mtd; 36static unsigned char *writebuf; 37static unsigned char *readbuf; 38static unsigned char *bbt; 39 40static int subpgsize; 41static int bufsize; 42static int ebcnt; 43static int pgcnt; 44static int errcnt; 45static unsigned long next = 1; 46 47static inline unsigned int simple_rand(void) 48{ 49 next = next * 1103515245 + 12345; 50 return (unsigned int)((next / 65536) % 32768); 51} 52 53static inline void simple_srand(unsigned long seed) 54{ 55 next = seed; 56} 57 58static 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 66static inline void clear_data(unsigned char *buf, size_t len) 67{ 68 memset(buf, 0, len); 69} 70 71static 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 97static 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 115static 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: %#zx\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: %#zx\n", written); 143 } 144 return err ? err : -1; 145 } 146 147 return err; 148} 149 150static 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: %#08zx\n", 168 written); 169 } 170 return err ? err : -1; 171 } 172 addr += subpgsize * k; 173 } 174 175 return err; 176} 177 178static 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 189static 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 252static 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 287static 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 321static 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 341static 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 352static 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 374static 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 505out: 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} 515module_init(mtd_subpagetest_init); 516 517static void __exit mtd_subpagetest_exit(void) 518{ 519 return; 520} 521module_exit(mtd_subpagetest_exit); 522 523MODULE_DESCRIPTION("Subpage test module"); 524MODULE_AUTHOR("Adrian Hunter"); 525MODULE_LICENSE("GPL");