2 * Copyright (C) 2007 Nokia Corporation
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.
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
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.
17 * Test read and write speed of a MTD device.
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
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>
29 #define PRINT_PREF KERN_INFO "mtd_speedtest: "
32 module_param(dev
, int, S_IRUGO
);
33 MODULE_PARM_DESC(dev
, "MTD device number to use");
35 static struct mtd_info
*mtd
;
36 static unsigned char *iobuf
;
37 static unsigned char *bbt
;
43 static struct timeval start
, finish
;
44 static unsigned long next
= 1;
46 static inline unsigned int simple_rand(void)
48 next
= next
* 1103515245 + 12345;
49 return (unsigned int)((next
/ 65536) % 32768);
52 static inline void simple_srand(unsigned long seed
)
57 static void set_random_data(unsigned char *buf
, size_t len
)
61 for (i
= 0; i
< len
; ++i
)
62 buf
[i
] = simple_rand();
65 static int erase_eraseblock(int ebnum
)
69 loff_t addr
= ebnum
* mtd
->erasesize
;
71 memset(&ei
, 0, sizeof(struct erase_info
));
74 ei
.len
= mtd
->erasesize
;
76 err
= mtd
->erase(mtd
, &ei
);
78 printk(PRINT_PREF
"error %d while erasing EB %d\n", err
, ebnum
);
82 if (ei
.state
== MTD_ERASE_FAILED
) {
83 printk(PRINT_PREF
"some erase error occurred at EB %d\n",
91 static int erase_whole_device(void)
96 for (i
= 0; i
< ebcnt
; ++i
) {
99 err
= erase_eraseblock(i
);
107 static int write_eraseblock(int ebnum
)
111 loff_t addr
= ebnum
* mtd
->erasesize
;
113 err
= mtd
->write(mtd
, addr
, mtd
->erasesize
, &written
, iobuf
);
114 if (err
|| written
!= mtd
->erasesize
) {
115 printk(PRINT_PREF
"error: write failed at %#llx\n", addr
);
123 static int write_eraseblock_by_page(int ebnum
)
127 loff_t addr
= ebnum
* mtd
->erasesize
;
130 for (i
= 0; i
< pgcnt
; i
++) {
131 err
= mtd
->write(mtd
, addr
, pgsize
, &written
, buf
);
132 if (err
|| written
!= pgsize
) {
133 printk(PRINT_PREF
"error: write failed at %#llx\n",
146 static int write_eraseblock_by_2pages(int ebnum
)
148 size_t written
= 0, sz
= pgsize
* 2;
149 int i
, n
= pgcnt
/ 2, err
= 0;
150 loff_t addr
= ebnum
* mtd
->erasesize
;
153 for (i
= 0; i
< n
; i
++) {
154 err
= mtd
->write(mtd
, addr
, sz
, &written
, buf
);
155 if (err
|| written
!= sz
) {
156 printk(PRINT_PREF
"error: write failed at %#llx\n",
166 err
= mtd
->write(mtd
, addr
, pgsize
, &written
, buf
);
167 if (err
|| written
!= pgsize
) {
168 printk(PRINT_PREF
"error: write failed at %#llx\n",
178 static int read_eraseblock(int ebnum
)
182 loff_t addr
= ebnum
* mtd
->erasesize
;
184 err
= mtd
->read(mtd
, addr
, mtd
->erasesize
, &read
, iobuf
);
185 /* Ignore corrected ECC errors */
188 if (err
|| read
!= mtd
->erasesize
) {
189 printk(PRINT_PREF
"error: read failed at %#llx\n", addr
);
197 static int read_eraseblock_by_page(int ebnum
)
201 loff_t addr
= ebnum
* mtd
->erasesize
;
204 for (i
= 0; i
< pgcnt
; i
++) {
205 err
= mtd
->read(mtd
, addr
, pgsize
, &read
, buf
);
206 /* Ignore corrected ECC errors */
209 if (err
|| read
!= pgsize
) {
210 printk(PRINT_PREF
"error: read failed at %#llx\n",
223 static int read_eraseblock_by_2pages(int ebnum
)
225 size_t read
= 0, sz
= pgsize
* 2;
226 int i
, n
= pgcnt
/ 2, err
= 0;
227 loff_t addr
= ebnum
* mtd
->erasesize
;
230 for (i
= 0; i
< n
; i
++) {
231 err
= mtd
->read(mtd
, addr
, sz
, &read
, buf
);
232 /* Ignore corrected ECC errors */
235 if (err
|| read
!= sz
) {
236 printk(PRINT_PREF
"error: read failed at %#llx\n",
246 err
= mtd
->read(mtd
, addr
, pgsize
, &read
, buf
);
247 /* Ignore corrected ECC errors */
250 if (err
|| read
!= pgsize
) {
251 printk(PRINT_PREF
"error: read failed at %#llx\n",
261 static int is_block_bad(int ebnum
)
263 loff_t addr
= ebnum
* mtd
->erasesize
;
266 ret
= mtd
->block_isbad(mtd
, addr
);
268 printk(PRINT_PREF
"block %d is bad\n", ebnum
);
272 static inline void start_timing(void)
274 do_gettimeofday(&start
);
277 static inline void stop_timing(void)
279 do_gettimeofday(&finish
);
282 static long calc_speed(void)
286 ms
= (finish
.tv_sec
- start
.tv_sec
) * 1000 +
287 (finish
.tv_usec
- start
.tv_usec
) / 1000;
288 k
= goodebcnt
* mtd
->erasesize
/ 1024;
289 speed
= (k
* 1000) / ms
;
293 static int scan_for_bad_eraseblocks(void)
297 bbt
= kmalloc(ebcnt
, GFP_KERNEL
);
299 printk(PRINT_PREF
"error: cannot allocate memory\n");
302 memset(bbt
, 0 , ebcnt
);
304 printk(PRINT_PREF
"scanning for bad eraseblocks\n");
305 for (i
= 0; i
< ebcnt
; ++i
) {
306 bbt
[i
] = is_block_bad(i
) ? 1 : 0;
311 printk(PRINT_PREF
"scanned %d eraseblocks, %d are bad\n", i
, bad
);
312 goodebcnt
= ebcnt
- bad
;
316 static int __init
mtd_speedtest_init(void)
322 printk(KERN_INFO
"\n");
323 printk(KERN_INFO
"=================================================\n");
324 printk(PRINT_PREF
"MTD device: %d\n", dev
);
326 mtd
= get_mtd_device(NULL
, dev
);
329 printk(PRINT_PREF
"error: cannot get MTD device\n");
333 if (mtd
->writesize
== 1) {
334 printk(PRINT_PREF
"not NAND flash, assume page size is 512 "
338 pgsize
= mtd
->writesize
;
341 do_div(tmp
, mtd
->erasesize
);
343 pgcnt
= mtd
->erasesize
/ mtd
->writesize
;
345 printk(PRINT_PREF
"MTD device size %llu, eraseblock size %u, "
346 "page size %u, count of eraseblocks %u, pages per "
347 "eraseblock %u, OOB size %u\n",
348 (unsigned long long)mtd
->size
, mtd
->erasesize
,
349 pgsize
, ebcnt
, pgcnt
, mtd
->oobsize
);
352 iobuf
= kmalloc(mtd
->erasesize
, GFP_KERNEL
);
354 printk(PRINT_PREF
"error: cannot allocate memory\n");
359 set_random_data(iobuf
, mtd
->erasesize
);
361 err
= scan_for_bad_eraseblocks();
365 err
= erase_whole_device();
369 /* Write all eraseblocks, 1 eraseblock at a time */
370 printk(PRINT_PREF
"testing eraseblock write speed\n");
372 for (i
= 0; i
< ebcnt
; ++i
) {
375 err
= write_eraseblock(i
);
381 speed
= calc_speed();
382 printk(PRINT_PREF
"eraseblock write speed is %ld KiB/s\n", speed
);
384 /* Read all eraseblocks, 1 eraseblock at a time */
385 printk(PRINT_PREF
"testing eraseblock read speed\n");
387 for (i
= 0; i
< ebcnt
; ++i
) {
390 err
= read_eraseblock(i
);
396 speed
= calc_speed();
397 printk(PRINT_PREF
"eraseblock read speed is %ld KiB/s\n", speed
);
399 err
= erase_whole_device();
403 /* Write all eraseblocks, 1 page at a time */
404 printk(PRINT_PREF
"testing page write speed\n");
406 for (i
= 0; i
< ebcnt
; ++i
) {
409 err
= write_eraseblock_by_page(i
);
415 speed
= calc_speed();
416 printk(PRINT_PREF
"page write speed is %ld KiB/s\n", speed
);
418 /* Read all eraseblocks, 1 page at a time */
419 printk(PRINT_PREF
"testing page read speed\n");
421 for (i
= 0; i
< ebcnt
; ++i
) {
424 err
= read_eraseblock_by_page(i
);
430 speed
= calc_speed();
431 printk(PRINT_PREF
"page read speed is %ld KiB/s\n", speed
);
433 err
= erase_whole_device();
437 /* Write all eraseblocks, 2 pages at a time */
438 printk(PRINT_PREF
"testing 2 page write speed\n");
440 for (i
= 0; i
< ebcnt
; ++i
) {
443 err
= write_eraseblock_by_2pages(i
);
449 speed
= calc_speed();
450 printk(PRINT_PREF
"2 page write speed is %ld KiB/s\n", speed
);
452 /* Read all eraseblocks, 2 pages at a time */
453 printk(PRINT_PREF
"testing 2 page read speed\n");
455 for (i
= 0; i
< ebcnt
; ++i
) {
458 err
= read_eraseblock_by_2pages(i
);
464 speed
= calc_speed();
465 printk(PRINT_PREF
"2 page read speed is %ld KiB/s\n", speed
);
467 /* Erase all eraseblocks */
468 printk(PRINT_PREF
"Testing erase speed\n");
470 for (i
= 0; i
< ebcnt
; ++i
) {
473 err
= erase_eraseblock(i
);
479 speed
= calc_speed();
480 printk(PRINT_PREF
"erase speed is %ld KiB/s\n", speed
);
482 printk(PRINT_PREF
"finished\n");
488 printk(PRINT_PREF
"error %d occurred\n", err
);
489 printk(KERN_INFO
"=================================================\n");
492 module_init(mtd_speedtest_init
);
494 static void __exit
mtd_speedtest_exit(void)
498 module_exit(mtd_speedtest_exit
);
500 MODULE_DESCRIPTION("Speed test module");
501 MODULE_AUTHOR("Adrian Hunter");
502 MODULE_LICENSE("GPL");