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.2-rc4 580 lines 13 kB view raw
1/* 2 * Copyright (C) 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 read and write speed of a MTD device. 18 * 19 * Author: Adrian Hunter <adrian.hunter@nokia.com> 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_speedtest: " 31 32static int dev = -EINVAL; 33module_param(dev, int, S_IRUGO); 34MODULE_PARM_DESC(dev, "MTD device number to use"); 35 36static int count; 37module_param(count, int, S_IRUGO); 38MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use " 39 "(0 means use all)"); 40 41static struct mtd_info *mtd; 42static unsigned char *iobuf; 43static unsigned char *bbt; 44 45static int pgsize; 46static int ebcnt; 47static int pgcnt; 48static int goodebcnt; 49static struct timeval start, finish; 50static unsigned long next = 1; 51 52static inline unsigned int simple_rand(void) 53{ 54 next = next * 1103515245 + 12345; 55 return (unsigned int)((next / 65536) % 32768); 56} 57 58static inline void simple_srand(unsigned long seed) 59{ 60 next = seed; 61} 62 63static void set_random_data(unsigned char *buf, size_t len) 64{ 65 size_t i; 66 67 for (i = 0; i < len; ++i) 68 buf[i] = simple_rand(); 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 multiblock_erase(int ebnum, int blocks) 98{ 99 int err; 100 struct erase_info ei; 101 loff_t addr = ebnum * mtd->erasesize; 102 103 memset(&ei, 0, sizeof(struct erase_info)); 104 ei.mtd = mtd; 105 ei.addr = addr; 106 ei.len = mtd->erasesize * blocks; 107 108 err = mtd->erase(mtd, &ei); 109 if (err) { 110 printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n", 111 err, ebnum, blocks); 112 return err; 113 } 114 115 if (ei.state == MTD_ERASE_FAILED) { 116 printk(PRINT_PREF "some erase error occurred at EB %d," 117 "blocks %d\n", ebnum, blocks); 118 return -EIO; 119 } 120 121 return 0; 122} 123 124static int erase_whole_device(void) 125{ 126 int err; 127 unsigned int i; 128 129 for (i = 0; i < ebcnt; ++i) { 130 if (bbt[i]) 131 continue; 132 err = erase_eraseblock(i); 133 if (err) 134 return err; 135 cond_resched(); 136 } 137 return 0; 138} 139 140static int write_eraseblock(int ebnum) 141{ 142 size_t written = 0; 143 int err = 0; 144 loff_t addr = ebnum * mtd->erasesize; 145 146 err = mtd->write(mtd, addr, mtd->erasesize, &written, iobuf); 147 if (err || written != mtd->erasesize) { 148 printk(PRINT_PREF "error: write failed at %#llx\n", addr); 149 if (!err) 150 err = -EINVAL; 151 } 152 153 return err; 154} 155 156static int write_eraseblock_by_page(int ebnum) 157{ 158 size_t written = 0; 159 int i, err = 0; 160 loff_t addr = ebnum * mtd->erasesize; 161 void *buf = iobuf; 162 163 for (i = 0; i < pgcnt; i++) { 164 err = mtd->write(mtd, addr, pgsize, &written, buf); 165 if (err || written != pgsize) { 166 printk(PRINT_PREF "error: write failed at %#llx\n", 167 addr); 168 if (!err) 169 err = -EINVAL; 170 break; 171 } 172 addr += pgsize; 173 buf += pgsize; 174 } 175 176 return err; 177} 178 179static int write_eraseblock_by_2pages(int ebnum) 180{ 181 size_t written = 0, sz = pgsize * 2; 182 int i, n = pgcnt / 2, err = 0; 183 loff_t addr = ebnum * mtd->erasesize; 184 void *buf = iobuf; 185 186 for (i = 0; i < n; i++) { 187 err = mtd->write(mtd, addr, sz, &written, buf); 188 if (err || written != sz) { 189 printk(PRINT_PREF "error: write failed at %#llx\n", 190 addr); 191 if (!err) 192 err = -EINVAL; 193 return err; 194 } 195 addr += sz; 196 buf += sz; 197 } 198 if (pgcnt % 2) { 199 err = mtd->write(mtd, addr, pgsize, &written, buf); 200 if (err || written != pgsize) { 201 printk(PRINT_PREF "error: write failed at %#llx\n", 202 addr); 203 if (!err) 204 err = -EINVAL; 205 } 206 } 207 208 return err; 209} 210 211static int read_eraseblock(int ebnum) 212{ 213 size_t read = 0; 214 int err = 0; 215 loff_t addr = ebnum * mtd->erasesize; 216 217 err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf); 218 /* Ignore corrected ECC errors */ 219 if (mtd_is_bitflip(err)) 220 err = 0; 221 if (err || read != mtd->erasesize) { 222 printk(PRINT_PREF "error: read failed at %#llx\n", addr); 223 if (!err) 224 err = -EINVAL; 225 } 226 227 return err; 228} 229 230static int read_eraseblock_by_page(int ebnum) 231{ 232 size_t read = 0; 233 int i, err = 0; 234 loff_t addr = ebnum * mtd->erasesize; 235 void *buf = iobuf; 236 237 for (i = 0; i < pgcnt; i++) { 238 err = mtd->read(mtd, addr, pgsize, &read, buf); 239 /* Ignore corrected ECC errors */ 240 if (mtd_is_bitflip(err)) 241 err = 0; 242 if (err || read != pgsize) { 243 printk(PRINT_PREF "error: read failed at %#llx\n", 244 addr); 245 if (!err) 246 err = -EINVAL; 247 break; 248 } 249 addr += pgsize; 250 buf += pgsize; 251 } 252 253 return err; 254} 255 256static int read_eraseblock_by_2pages(int ebnum) 257{ 258 size_t read = 0, sz = pgsize * 2; 259 int i, n = pgcnt / 2, err = 0; 260 loff_t addr = ebnum * mtd->erasesize; 261 void *buf = iobuf; 262 263 for (i = 0; i < n; i++) { 264 err = mtd->read(mtd, addr, sz, &read, buf); 265 /* Ignore corrected ECC errors */ 266 if (mtd_is_bitflip(err)) 267 err = 0; 268 if (err || read != sz) { 269 printk(PRINT_PREF "error: read failed at %#llx\n", 270 addr); 271 if (!err) 272 err = -EINVAL; 273 return err; 274 } 275 addr += sz; 276 buf += sz; 277 } 278 if (pgcnt % 2) { 279 err = mtd->read(mtd, addr, pgsize, &read, buf); 280 /* Ignore corrected ECC errors */ 281 if (mtd_is_bitflip(err)) 282 err = 0; 283 if (err || read != pgsize) { 284 printk(PRINT_PREF "error: read failed at %#llx\n", 285 addr); 286 if (!err) 287 err = -EINVAL; 288 } 289 } 290 291 return err; 292} 293 294static int is_block_bad(int ebnum) 295{ 296 loff_t addr = ebnum * mtd->erasesize; 297 int ret; 298 299 ret = mtd->block_isbad(mtd, addr); 300 if (ret) 301 printk(PRINT_PREF "block %d is bad\n", ebnum); 302 return ret; 303} 304 305static inline void start_timing(void) 306{ 307 do_gettimeofday(&start); 308} 309 310static inline void stop_timing(void) 311{ 312 do_gettimeofday(&finish); 313} 314 315static long calc_speed(void) 316{ 317 uint64_t k; 318 long ms; 319 320 ms = (finish.tv_sec - start.tv_sec) * 1000 + 321 (finish.tv_usec - start.tv_usec) / 1000; 322 if (ms == 0) 323 return 0; 324 k = goodebcnt * (mtd->erasesize / 1024) * 1000; 325 do_div(k, ms); 326 return k; 327} 328 329static int scan_for_bad_eraseblocks(void) 330{ 331 int i, bad = 0; 332 333 bbt = kzalloc(ebcnt, GFP_KERNEL); 334 if (!bbt) { 335 printk(PRINT_PREF "error: cannot allocate memory\n"); 336 return -ENOMEM; 337 } 338 339 /* NOR flash does not implement block_isbad */ 340 if (mtd->block_isbad == NULL) 341 goto out; 342 343 printk(PRINT_PREF "scanning for bad eraseblocks\n"); 344 for (i = 0; i < ebcnt; ++i) { 345 bbt[i] = is_block_bad(i) ? 1 : 0; 346 if (bbt[i]) 347 bad += 1; 348 cond_resched(); 349 } 350 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); 351out: 352 goodebcnt = ebcnt - bad; 353 return 0; 354} 355 356static int __init mtd_speedtest_init(void) 357{ 358 int err, i, blocks, j, k; 359 long speed; 360 uint64_t tmp; 361 362 printk(KERN_INFO "\n"); 363 printk(KERN_INFO "=================================================\n"); 364 365 if (dev < 0) { 366 printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); 367 printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); 368 return -EINVAL; 369 } 370 371 if (count) 372 printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); 373 else 374 printk(PRINT_PREF "MTD device: %d\n", dev); 375 376 mtd = get_mtd_device(NULL, dev); 377 if (IS_ERR(mtd)) { 378 err = PTR_ERR(mtd); 379 printk(PRINT_PREF "error: cannot get MTD device\n"); 380 return err; 381 } 382 383 if (mtd->writesize == 1) { 384 printk(PRINT_PREF "not NAND flash, assume page size is 512 " 385 "bytes.\n"); 386 pgsize = 512; 387 } else 388 pgsize = mtd->writesize; 389 390 tmp = mtd->size; 391 do_div(tmp, mtd->erasesize); 392 ebcnt = tmp; 393 pgcnt = mtd->erasesize / pgsize; 394 395 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " 396 "page size %u, count of eraseblocks %u, pages per " 397 "eraseblock %u, OOB size %u\n", 398 (unsigned long long)mtd->size, mtd->erasesize, 399 pgsize, ebcnt, pgcnt, mtd->oobsize); 400 401 if (count > 0 && count < ebcnt) 402 ebcnt = count; 403 404 err = -ENOMEM; 405 iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); 406 if (!iobuf) { 407 printk(PRINT_PREF "error: cannot allocate memory\n"); 408 goto out; 409 } 410 411 simple_srand(1); 412 set_random_data(iobuf, mtd->erasesize); 413 414 err = scan_for_bad_eraseblocks(); 415 if (err) 416 goto out; 417 418 err = erase_whole_device(); 419 if (err) 420 goto out; 421 422 /* Write all eraseblocks, 1 eraseblock at a time */ 423 printk(PRINT_PREF "testing eraseblock write speed\n"); 424 start_timing(); 425 for (i = 0; i < ebcnt; ++i) { 426 if (bbt[i]) 427 continue; 428 err = write_eraseblock(i); 429 if (err) 430 goto out; 431 cond_resched(); 432 } 433 stop_timing(); 434 speed = calc_speed(); 435 printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed); 436 437 /* Read all eraseblocks, 1 eraseblock at a time */ 438 printk(PRINT_PREF "testing eraseblock read speed\n"); 439 start_timing(); 440 for (i = 0; i < ebcnt; ++i) { 441 if (bbt[i]) 442 continue; 443 err = read_eraseblock(i); 444 if (err) 445 goto out; 446 cond_resched(); 447 } 448 stop_timing(); 449 speed = calc_speed(); 450 printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed); 451 452 err = erase_whole_device(); 453 if (err) 454 goto out; 455 456 /* Write all eraseblocks, 1 page at a time */ 457 printk(PRINT_PREF "testing page write speed\n"); 458 start_timing(); 459 for (i = 0; i < ebcnt; ++i) { 460 if (bbt[i]) 461 continue; 462 err = write_eraseblock_by_page(i); 463 if (err) 464 goto out; 465 cond_resched(); 466 } 467 stop_timing(); 468 speed = calc_speed(); 469 printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed); 470 471 /* Read all eraseblocks, 1 page at a time */ 472 printk(PRINT_PREF "testing page read speed\n"); 473 start_timing(); 474 for (i = 0; i < ebcnt; ++i) { 475 if (bbt[i]) 476 continue; 477 err = read_eraseblock_by_page(i); 478 if (err) 479 goto out; 480 cond_resched(); 481 } 482 stop_timing(); 483 speed = calc_speed(); 484 printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed); 485 486 err = erase_whole_device(); 487 if (err) 488 goto out; 489 490 /* Write all eraseblocks, 2 pages at a time */ 491 printk(PRINT_PREF "testing 2 page write speed\n"); 492 start_timing(); 493 for (i = 0; i < ebcnt; ++i) { 494 if (bbt[i]) 495 continue; 496 err = write_eraseblock_by_2pages(i); 497 if (err) 498 goto out; 499 cond_resched(); 500 } 501 stop_timing(); 502 speed = calc_speed(); 503 printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed); 504 505 /* Read all eraseblocks, 2 pages at a time */ 506 printk(PRINT_PREF "testing 2 page read speed\n"); 507 start_timing(); 508 for (i = 0; i < ebcnt; ++i) { 509 if (bbt[i]) 510 continue; 511 err = read_eraseblock_by_2pages(i); 512 if (err) 513 goto out; 514 cond_resched(); 515 } 516 stop_timing(); 517 speed = calc_speed(); 518 printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed); 519 520 /* Erase all eraseblocks */ 521 printk(PRINT_PREF "Testing erase speed\n"); 522 start_timing(); 523 for (i = 0; i < ebcnt; ++i) { 524 if (bbt[i]) 525 continue; 526 err = erase_eraseblock(i); 527 if (err) 528 goto out; 529 cond_resched(); 530 } 531 stop_timing(); 532 speed = calc_speed(); 533 printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); 534 535 /* Multi-block erase all eraseblocks */ 536 for (k = 1; k < 7; k++) { 537 blocks = 1 << k; 538 printk(PRINT_PREF "Testing %dx multi-block erase speed\n", 539 blocks); 540 start_timing(); 541 for (i = 0; i < ebcnt; ) { 542 for (j = 0; j < blocks && (i + j) < ebcnt; j++) 543 if (bbt[i + j]) 544 break; 545 if (j < 1) { 546 i++; 547 continue; 548 } 549 err = multiblock_erase(i, j); 550 if (err) 551 goto out; 552 cond_resched(); 553 i += j; 554 } 555 stop_timing(); 556 speed = calc_speed(); 557 printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n", 558 blocks, speed); 559 } 560 printk(PRINT_PREF "finished\n"); 561out: 562 kfree(iobuf); 563 kfree(bbt); 564 put_mtd_device(mtd); 565 if (err) 566 printk(PRINT_PREF "error %d occurred\n", err); 567 printk(KERN_INFO "=================================================\n"); 568 return err; 569} 570module_init(mtd_speedtest_init); 571 572static void __exit mtd_speedtest_exit(void) 573{ 574 return; 575} 576module_exit(mtd_speedtest_exit); 577 578MODULE_DESCRIPTION("Speed test module"); 579MODULE_AUTHOR("Adrian Hunter"); 580MODULE_LICENSE("GPL");