mtd: tests: stresstest: bail out if device has not enough eraseblocks
[pandora-kernel.git] / drivers / mtd / tests / mtd_speedtest.c
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
32 static int dev = -EINVAL;
33 module_param(dev, int, S_IRUGO);
34 MODULE_PARM_DESC(dev, "MTD device number to use");
35
36 static int count;
37 module_param(count, int, S_IRUGO);
38 MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use "
39                         "(0 means use all)");
40
41 static struct mtd_info *mtd;
42 static unsigned char *iobuf;
43 static unsigned char *bbt;
44
45 static int pgsize;
46 static int ebcnt;
47 static int pgcnt;
48 static int goodebcnt;
49 static struct timeval start, finish;
50 static unsigned long next = 1;
51
52 static inline unsigned int simple_rand(void)
53 {
54         next = next * 1103515245 + 12345;
55         return (unsigned int)((next / 65536) % 32768);
56 }
57
58 static inline void simple_srand(unsigned long seed)
59 {
60         next = seed;
61 }
62
63 static 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
71 static 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
97 static 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
124 static 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
140 static 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
156 static 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
179 static 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
211 static 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
230 static 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
256 static 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
294 static 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
305 static inline void start_timing(void)
306 {
307         do_gettimeofday(&start);
308 }
309
310 static inline void stop_timing(void)
311 {
312         do_gettimeofday(&finish);
313 }
314
315 static 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
329 static 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);
351 out:
352         goodebcnt = ebcnt - bad;
353         return 0;
354 }
355
356 static 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");
561 out:
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 }
570 module_init(mtd_speedtest_init);
571
572 static void __exit mtd_speedtest_exit(void)
573 {
574         return;
575 }
576 module_exit(mtd_speedtest_exit);
577
578 MODULE_DESCRIPTION("Speed test module");
579 MODULE_AUTHOR("Adrian Hunter");
580 MODULE_LICENSE("GPL");