2 * Copyright (C) 2006-2008 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 random reads, writes and erases on 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>
28 #include <linux/vmalloc.h>
30 #define PRINT_PREF KERN_INFO "mtd_stresstest: "
33 module_param(dev
, int, S_IRUGO
);
34 MODULE_PARM_DESC(dev
, "MTD device number to use");
36 static int count
= 10000;
37 module_param(count
, int, S_IRUGO
);
38 MODULE_PARM_DESC(count
, "Number of operations to do (default is 10000)");
40 static struct mtd_info
*mtd
;
41 static unsigned char *writebuf
;
42 static unsigned char *readbuf
;
43 static unsigned char *bbt
;
50 static unsigned long next
= 1;
52 static inline unsigned int simple_rand(void)
54 next
= next
* 1103515245 + 12345;
55 return (unsigned int)((next
/ 65536) % 32768);
58 static inline void simple_srand(unsigned long seed
)
63 static int rand_eb(void)
71 eb
= (simple_rand() << 15) | simple_rand();
72 /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
79 static int rand_offs(void)
86 offs
= (simple_rand() << 15) | simple_rand();
91 static int rand_len(int offs
)
98 len
= (simple_rand() << 15) | simple_rand();
99 len
%= (bufsize
- offs
);
103 static int erase_eraseblock(int ebnum
)
106 struct erase_info ei
;
107 loff_t addr
= ebnum
* mtd
->erasesize
;
109 memset(&ei
, 0, sizeof(struct erase_info
));
112 ei
.len
= mtd
->erasesize
;
114 err
= mtd
->erase(mtd
, &ei
);
116 printk(PRINT_PREF
"error %d while erasing EB %d\n", err
, ebnum
);
120 if (unlikely(ei
.state
== MTD_ERASE_FAILED
)) {
121 printk(PRINT_PREF
"some erase error occurred at EB %d\n",
129 static int is_block_bad(int ebnum
)
131 loff_t addr
= ebnum
* mtd
->erasesize
;
134 ret
= mtd
->block_isbad(mtd
, addr
);
136 printk(PRINT_PREF
"block %d is bad\n", ebnum
);
140 static int do_read(void)
144 int offs
= rand_offs();
145 int len
= rand_len(offs
), err
;
149 if (offs
>= mtd
->erasesize
)
150 offs
-= mtd
->erasesize
;
151 if (offs
+ len
> mtd
->erasesize
)
152 len
= mtd
->erasesize
- offs
;
154 addr
= eb
* mtd
->erasesize
+ offs
;
155 err
= mtd
->read(mtd
, addr
, len
, &read
, readbuf
);
158 if (unlikely(err
|| read
!= len
)) {
159 printk(PRINT_PREF
"error: read failed at 0x%llx\n",
168 static int do_write(void)
170 int eb
= rand_eb(), offs
, err
, len
;
175 if (offs
>= mtd
->erasesize
) {
176 err
= erase_eraseblock(eb
);
179 offs
= offsets
[eb
] = 0;
181 len
= rand_len(offs
);
182 len
= ((len
+ pgsize
- 1) / pgsize
) * pgsize
;
183 if (offs
+ len
> mtd
->erasesize
) {
185 len
= mtd
->erasesize
- offs
;
187 err
= erase_eraseblock(eb
+ 1);
193 addr
= eb
* mtd
->erasesize
+ offs
;
194 err
= mtd
->write(mtd
, addr
, len
, &written
, writebuf
);
195 if (unlikely(err
|| written
!= len
)) {
196 printk(PRINT_PREF
"error: write failed at 0x%llx\n",
203 while (offs
> mtd
->erasesize
) {
204 offsets
[eb
++] = mtd
->erasesize
;
205 offs
-= mtd
->erasesize
;
211 static int do_operation(void)
213 if (simple_rand() & 1)
219 static int scan_for_bad_eraseblocks(void)
223 bbt
= kmalloc(ebcnt
, GFP_KERNEL
);
225 printk(PRINT_PREF
"error: cannot allocate memory\n");
228 memset(bbt
, 0 , ebcnt
);
230 /* NOR flash does not implement block_isbad */
231 if (mtd
->block_isbad
== NULL
)
234 printk(PRINT_PREF
"scanning for bad eraseblocks\n");
235 for (i
= 0; i
< ebcnt
; ++i
) {
236 bbt
[i
] = is_block_bad(i
) ? 1 : 0;
241 printk(PRINT_PREF
"scanned %d eraseblocks, %d are bad\n", i
, bad
);
245 static int __init
mtd_stresstest_init(void)
251 printk(KERN_INFO
"\n");
252 printk(KERN_INFO
"=================================================\n");
253 printk(PRINT_PREF
"MTD device: %d\n", dev
);
255 mtd
= get_mtd_device(NULL
, dev
);
258 printk(PRINT_PREF
"error: cannot get MTD device\n");
262 if (mtd
->writesize
== 1) {
263 printk(PRINT_PREF
"not NAND flash, assume page size is 512 "
267 pgsize
= mtd
->writesize
;
270 do_div(tmp
, mtd
->erasesize
);
272 pgcnt
= mtd
->erasesize
/ pgsize
;
274 printk(PRINT_PREF
"MTD device size %llu, eraseblock size %u, "
275 "page size %u, count of eraseblocks %u, pages per "
276 "eraseblock %u, OOB size %u\n",
277 (unsigned long long)mtd
->size
, mtd
->erasesize
,
278 pgsize
, ebcnt
, pgcnt
, mtd
->oobsize
);
280 /* Read or write up 2 eraseblocks at a time */
281 bufsize
= mtd
->erasesize
* 2;
284 readbuf
= vmalloc(bufsize
);
285 writebuf
= vmalloc(bufsize
);
286 offsets
= kmalloc(ebcnt
* sizeof(int), GFP_KERNEL
);
287 if (!readbuf
|| !writebuf
|| !offsets
) {
288 printk(PRINT_PREF
"error: cannot allocate memory\n");
291 for (i
= 0; i
< ebcnt
; i
++)
292 offsets
[i
] = mtd
->erasesize
;
293 simple_srand(current
->pid
);
294 for (i
= 0; i
< bufsize
; i
++)
295 writebuf
[i
] = simple_rand();
297 err
= scan_for_bad_eraseblocks();
302 printk(PRINT_PREF
"doing operations\n");
303 for (op
= 0; op
< count
; op
++) {
304 if ((op
& 1023) == 0)
305 printk(PRINT_PREF
"%d operations done\n", op
);
306 err
= do_operation();
311 printk(PRINT_PREF
"finished, %d operations done\n", op
);
320 printk(PRINT_PREF
"error %d occurred\n", err
);
321 printk(KERN_INFO
"=================================================\n");
324 module_init(mtd_stresstest_init
);
326 static void __exit
mtd_stresstest_exit(void)
330 module_exit(mtd_stresstest_exit
);
332 MODULE_DESCRIPTION("Stress test module");
333 MODULE_AUTHOR("Adrian Hunter");
334 MODULE_LICENSE("GPL");