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.6-rc3 579 lines 12 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; 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; 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, 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; 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; 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, 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 if (!mtd_can_have_bb(mtd)) 340 goto out; 341 342 printk(PRINT_PREF "scanning for bad eraseblocks\n"); 343 for (i = 0; i < ebcnt; ++i) { 344 bbt[i] = is_block_bad(i) ? 1 : 0; 345 if (bbt[i]) 346 bad += 1; 347 cond_resched(); 348 } 349 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); 350out: 351 goodebcnt = ebcnt - bad; 352 return 0; 353} 354 355static int __init mtd_speedtest_init(void) 356{ 357 int err, i, blocks, j, k; 358 long speed; 359 uint64_t tmp; 360 361 printk(KERN_INFO "\n"); 362 printk(KERN_INFO "=================================================\n"); 363 364 if (dev < 0) { 365 printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); 366 printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); 367 return -EINVAL; 368 } 369 370 if (count) 371 printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); 372 else 373 printk(PRINT_PREF "MTD device: %d\n", dev); 374 375 mtd = get_mtd_device(NULL, dev); 376 if (IS_ERR(mtd)) { 377 err = PTR_ERR(mtd); 378 printk(PRINT_PREF "error: cannot get MTD device\n"); 379 return err; 380 } 381 382 if (mtd->writesize == 1) { 383 printk(PRINT_PREF "not NAND flash, assume page size is 512 " 384 "bytes.\n"); 385 pgsize = 512; 386 } else 387 pgsize = mtd->writesize; 388 389 tmp = mtd->size; 390 do_div(tmp, mtd->erasesize); 391 ebcnt = tmp; 392 pgcnt = mtd->erasesize / pgsize; 393 394 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " 395 "page size %u, count of eraseblocks %u, pages per " 396 "eraseblock %u, OOB size %u\n", 397 (unsigned long long)mtd->size, mtd->erasesize, 398 pgsize, ebcnt, pgcnt, mtd->oobsize); 399 400 if (count > 0 && count < ebcnt) 401 ebcnt = count; 402 403 err = -ENOMEM; 404 iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); 405 if (!iobuf) { 406 printk(PRINT_PREF "error: cannot allocate memory\n"); 407 goto out; 408 } 409 410 simple_srand(1); 411 set_random_data(iobuf, mtd->erasesize); 412 413 err = scan_for_bad_eraseblocks(); 414 if (err) 415 goto out; 416 417 err = erase_whole_device(); 418 if (err) 419 goto out; 420 421 /* Write all eraseblocks, 1 eraseblock at a time */ 422 printk(PRINT_PREF "testing eraseblock write speed\n"); 423 start_timing(); 424 for (i = 0; i < ebcnt; ++i) { 425 if (bbt[i]) 426 continue; 427 err = write_eraseblock(i); 428 if (err) 429 goto out; 430 cond_resched(); 431 } 432 stop_timing(); 433 speed = calc_speed(); 434 printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed); 435 436 /* Read all eraseblocks, 1 eraseblock at a time */ 437 printk(PRINT_PREF "testing eraseblock read speed\n"); 438 start_timing(); 439 for (i = 0; i < ebcnt; ++i) { 440 if (bbt[i]) 441 continue; 442 err = read_eraseblock(i); 443 if (err) 444 goto out; 445 cond_resched(); 446 } 447 stop_timing(); 448 speed = calc_speed(); 449 printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed); 450 451 err = erase_whole_device(); 452 if (err) 453 goto out; 454 455 /* Write all eraseblocks, 1 page at a time */ 456 printk(PRINT_PREF "testing page write speed\n"); 457 start_timing(); 458 for (i = 0; i < ebcnt; ++i) { 459 if (bbt[i]) 460 continue; 461 err = write_eraseblock_by_page(i); 462 if (err) 463 goto out; 464 cond_resched(); 465 } 466 stop_timing(); 467 speed = calc_speed(); 468 printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed); 469 470 /* Read all eraseblocks, 1 page at a time */ 471 printk(PRINT_PREF "testing page read speed\n"); 472 start_timing(); 473 for (i = 0; i < ebcnt; ++i) { 474 if (bbt[i]) 475 continue; 476 err = read_eraseblock_by_page(i); 477 if (err) 478 goto out; 479 cond_resched(); 480 } 481 stop_timing(); 482 speed = calc_speed(); 483 printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed); 484 485 err = erase_whole_device(); 486 if (err) 487 goto out; 488 489 /* Write all eraseblocks, 2 pages at a time */ 490 printk(PRINT_PREF "testing 2 page write speed\n"); 491 start_timing(); 492 for (i = 0; i < ebcnt; ++i) { 493 if (bbt[i]) 494 continue; 495 err = write_eraseblock_by_2pages(i); 496 if (err) 497 goto out; 498 cond_resched(); 499 } 500 stop_timing(); 501 speed = calc_speed(); 502 printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed); 503 504 /* Read all eraseblocks, 2 pages at a time */ 505 printk(PRINT_PREF "testing 2 page read speed\n"); 506 start_timing(); 507 for (i = 0; i < ebcnt; ++i) { 508 if (bbt[i]) 509 continue; 510 err = read_eraseblock_by_2pages(i); 511 if (err) 512 goto out; 513 cond_resched(); 514 } 515 stop_timing(); 516 speed = calc_speed(); 517 printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed); 518 519 /* Erase all eraseblocks */ 520 printk(PRINT_PREF "Testing erase speed\n"); 521 start_timing(); 522 for (i = 0; i < ebcnt; ++i) { 523 if (bbt[i]) 524 continue; 525 err = erase_eraseblock(i); 526 if (err) 527 goto out; 528 cond_resched(); 529 } 530 stop_timing(); 531 speed = calc_speed(); 532 printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); 533 534 /* Multi-block erase all eraseblocks */ 535 for (k = 1; k < 7; k++) { 536 blocks = 1 << k; 537 printk(PRINT_PREF "Testing %dx multi-block erase speed\n", 538 blocks); 539 start_timing(); 540 for (i = 0; i < ebcnt; ) { 541 for (j = 0; j < blocks && (i + j) < ebcnt; j++) 542 if (bbt[i + j]) 543 break; 544 if (j < 1) { 545 i++; 546 continue; 547 } 548 err = multiblock_erase(i, j); 549 if (err) 550 goto out; 551 cond_resched(); 552 i += j; 553 } 554 stop_timing(); 555 speed = calc_speed(); 556 printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n", 557 blocks, speed); 558 } 559 printk(PRINT_PREF "finished\n"); 560out: 561 kfree(iobuf); 562 kfree(bbt); 563 put_mtd_device(mtd); 564 if (err) 565 printk(PRINT_PREF "error %d occurred\n", err); 566 printk(KERN_INFO "=================================================\n"); 567 return err; 568} 569module_init(mtd_speedtest_init); 570 571static void __exit mtd_speedtest_exit(void) 572{ 573 return; 574} 575module_exit(mtd_speedtest_exit); 576 577MODULE_DESCRIPTION("Speed test module"); 578MODULE_AUTHOR("Adrian Hunter"); 579MODULE_LICENSE("GPL");