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 /* NOR flash does not implement block_isbad */
305 if (mtd
->block_isbad
== NULL
)
308 printk(PRINT_PREF
"scanning for bad eraseblocks\n");
309 for (i
= 0; i
< ebcnt
; ++i
) {
310 bbt
[i
] = is_block_bad(i
) ? 1 : 0;
315 printk(PRINT_PREF
"scanned %d eraseblocks, %d are bad\n", i
, bad
);
317 goodebcnt
= ebcnt
- bad
;
321 static int __init
mtd_speedtest_init(void)
327 printk(KERN_INFO
"\n");
328 printk(KERN_INFO
"=================================================\n");
329 printk(PRINT_PREF
"MTD device: %d\n", dev
);
331 mtd
= get_mtd_device(NULL
, dev
);
334 printk(PRINT_PREF
"error: cannot get MTD device\n");
338 if (mtd
->writesize
== 1) {
339 printk(PRINT_PREF
"not NAND flash, assume page size is 512 "
343 pgsize
= mtd
->writesize
;
346 do_div(tmp
, mtd
->erasesize
);
348 pgcnt
= mtd
->erasesize
/ pgsize
;
350 printk(PRINT_PREF
"MTD device size %llu, eraseblock size %u, "
351 "page size %u, count of eraseblocks %u, pages per "
352 "eraseblock %u, OOB size %u\n",
353 (unsigned long long)mtd
->size
, mtd
->erasesize
,
354 pgsize
, ebcnt
, pgcnt
, mtd
->oobsize
);
357 iobuf
= kmalloc(mtd
->erasesize
, GFP_KERNEL
);
359 printk(PRINT_PREF
"error: cannot allocate memory\n");
364 set_random_data(iobuf
, mtd
->erasesize
);
366 err
= scan_for_bad_eraseblocks();
370 err
= erase_whole_device();
374 /* Write all eraseblocks, 1 eraseblock at a time */
375 printk(PRINT_PREF
"testing eraseblock write speed\n");
377 for (i
= 0; i
< ebcnt
; ++i
) {
380 err
= write_eraseblock(i
);
386 speed
= calc_speed();
387 printk(PRINT_PREF
"eraseblock write speed is %ld KiB/s\n", speed
);
389 /* Read all eraseblocks, 1 eraseblock at a time */
390 printk(PRINT_PREF
"testing eraseblock read speed\n");
392 for (i
= 0; i
< ebcnt
; ++i
) {
395 err
= read_eraseblock(i
);
401 speed
= calc_speed();
402 printk(PRINT_PREF
"eraseblock read speed is %ld KiB/s\n", speed
);
404 err
= erase_whole_device();
408 /* Write all eraseblocks, 1 page at a time */
409 printk(PRINT_PREF
"testing page write speed\n");
411 for (i
= 0; i
< ebcnt
; ++i
) {
414 err
= write_eraseblock_by_page(i
);
420 speed
= calc_speed();
421 printk(PRINT_PREF
"page write speed is %ld KiB/s\n", speed
);
423 /* Read all eraseblocks, 1 page at a time */
424 printk(PRINT_PREF
"testing page read speed\n");
426 for (i
= 0; i
< ebcnt
; ++i
) {
429 err
= read_eraseblock_by_page(i
);
435 speed
= calc_speed();
436 printk(PRINT_PREF
"page read speed is %ld KiB/s\n", speed
);
438 err
= erase_whole_device();
442 /* Write all eraseblocks, 2 pages at a time */
443 printk(PRINT_PREF
"testing 2 page write speed\n");
445 for (i
= 0; i
< ebcnt
; ++i
) {
448 err
= write_eraseblock_by_2pages(i
);
454 speed
= calc_speed();
455 printk(PRINT_PREF
"2 page write speed is %ld KiB/s\n", speed
);
457 /* Read all eraseblocks, 2 pages at a time */
458 printk(PRINT_PREF
"testing 2 page read speed\n");
460 for (i
= 0; i
< ebcnt
; ++i
) {
463 err
= read_eraseblock_by_2pages(i
);
469 speed
= calc_speed();
470 printk(PRINT_PREF
"2 page read speed is %ld KiB/s\n", speed
);
472 /* Erase all eraseblocks */
473 printk(PRINT_PREF
"Testing erase speed\n");
475 for (i
= 0; i
< ebcnt
; ++i
) {
478 err
= erase_eraseblock(i
);
484 speed
= calc_speed();
485 printk(PRINT_PREF
"erase speed is %ld KiB/s\n", speed
);
487 printk(PRINT_PREF
"finished\n");
493 printk(PRINT_PREF
"error %d occurred\n", err
);
494 printk(KERN_INFO
"=================================================\n");
497 module_init(mtd_speedtest_init
);
499 static void __exit
mtd_speedtest_exit(void)
503 module_exit(mtd_speedtest_exit
);
505 MODULE_DESCRIPTION("Speed test module");
506 MODULE_AUTHOR("Adrian Hunter");
507 MODULE_LICENSE("GPL");