Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mtd_speedtest.c
Go to the documentation of this file.
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 <[email protected]>
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 #include <linux/random.h>
30 
31 #define PRINT_PREF KERN_INFO "mtd_speedtest: "
32 
33 static int dev = -EINVAL;
34 module_param(dev, int, S_IRUGO);
35 MODULE_PARM_DESC(dev, "MTD device number to use");
36 
37 static int count;
39 MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use "
40  "(0 means use all)");
41 
42 static struct mtd_info *mtd;
43 static unsigned char *iobuf;
44 static unsigned char *bbt;
45 
46 static int pgsize;
47 static int ebcnt;
48 static int pgcnt;
49 static int goodebcnt;
50 static struct timeval start, finish;
51 
52 static void set_random_data(unsigned char *buf, size_t len)
53 {
54  size_t i;
55 
56  for (i = 0; i < len; ++i)
57  buf[i] = random32();
58 }
59 
60 static int erase_eraseblock(int ebnum)
61 {
62  int err;
63  struct erase_info ei;
64  loff_t addr = ebnum * mtd->erasesize;
65 
66  memset(&ei, 0, sizeof(struct erase_info));
67  ei.mtd = mtd;
68  ei.addr = addr;
69  ei.len = mtd->erasesize;
70 
71  err = mtd_erase(mtd, &ei);
72  if (err) {
73  printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
74  return err;
75  }
76 
77  if (ei.state == MTD_ERASE_FAILED) {
78  printk(PRINT_PREF "some erase error occurred at EB %d\n",
79  ebnum);
80  return -EIO;
81  }
82 
83  return 0;
84 }
85 
86 static int multiblock_erase(int ebnum, int blocks)
87 {
88  int err;
89  struct erase_info ei;
90  loff_t addr = ebnum * mtd->erasesize;
91 
92  memset(&ei, 0, sizeof(struct erase_info));
93  ei.mtd = mtd;
94  ei.addr = addr;
95  ei.len = mtd->erasesize * blocks;
96 
97  err = mtd_erase(mtd, &ei);
98  if (err) {
99  printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n",
100  err, ebnum, blocks);
101  return err;
102  }
103 
104  if (ei.state == MTD_ERASE_FAILED) {
105  printk(PRINT_PREF "some erase error occurred at EB %d,"
106  "blocks %d\n", ebnum, blocks);
107  return -EIO;
108  }
109 
110  return 0;
111 }
112 
113 static int erase_whole_device(void)
114 {
115  int err;
116  unsigned int i;
117 
118  for (i = 0; i < ebcnt; ++i) {
119  if (bbt[i])
120  continue;
121  err = erase_eraseblock(i);
122  if (err)
123  return err;
124  cond_resched();
125  }
126  return 0;
127 }
128 
129 static int write_eraseblock(int ebnum)
130 {
131  size_t written;
132  int err = 0;
133  loff_t addr = ebnum * mtd->erasesize;
134 
135  err = mtd_write(mtd, addr, mtd->erasesize, &written, iobuf);
136  if (err || written != mtd->erasesize) {
137  printk(PRINT_PREF "error: write failed at %#llx\n", addr);
138  if (!err)
139  err = -EINVAL;
140  }
141 
142  return err;
143 }
144 
145 static int write_eraseblock_by_page(int ebnum)
146 {
147  size_t written;
148  int i, err = 0;
149  loff_t addr = ebnum * mtd->erasesize;
150  void *buf = iobuf;
151 
152  for (i = 0; i < pgcnt; i++) {
153  err = mtd_write(mtd, addr, pgsize, &written, buf);
154  if (err || written != pgsize) {
155  printk(PRINT_PREF "error: write failed at %#llx\n",
156  addr);
157  if (!err)
158  err = -EINVAL;
159  break;
160  }
161  addr += pgsize;
162  buf += pgsize;
163  }
164 
165  return err;
166 }
167 
168 static int write_eraseblock_by_2pages(int ebnum)
169 {
170  size_t written, sz = pgsize * 2;
171  int i, n = pgcnt / 2, err = 0;
172  loff_t addr = ebnum * mtd->erasesize;
173  void *buf = iobuf;
174 
175  for (i = 0; i < n; i++) {
176  err = mtd_write(mtd, addr, sz, &written, buf);
177  if (err || written != sz) {
178  printk(PRINT_PREF "error: write failed at %#llx\n",
179  addr);
180  if (!err)
181  err = -EINVAL;
182  return err;
183  }
184  addr += sz;
185  buf += sz;
186  }
187  if (pgcnt % 2) {
188  err = mtd_write(mtd, addr, pgsize, &written, buf);
189  if (err || written != pgsize) {
190  printk(PRINT_PREF "error: write failed at %#llx\n",
191  addr);
192  if (!err)
193  err = -EINVAL;
194  }
195  }
196 
197  return err;
198 }
199 
200 static int read_eraseblock(int ebnum)
201 {
202  size_t read;
203  int err = 0;
204  loff_t addr = ebnum * mtd->erasesize;
205 
206  err = mtd_read(mtd, addr, mtd->erasesize, &read, iobuf);
207  /* Ignore corrected ECC errors */
208  if (mtd_is_bitflip(err))
209  err = 0;
210  if (err || read != mtd->erasesize) {
211  printk(PRINT_PREF "error: read failed at %#llx\n", addr);
212  if (!err)
213  err = -EINVAL;
214  }
215 
216  return err;
217 }
218 
219 static int read_eraseblock_by_page(int ebnum)
220 {
221  size_t read;
222  int i, err = 0;
223  loff_t addr = ebnum * mtd->erasesize;
224  void *buf = iobuf;
225 
226  for (i = 0; i < pgcnt; i++) {
227  err = mtd_read(mtd, addr, pgsize, &read, buf);
228  /* Ignore corrected ECC errors */
229  if (mtd_is_bitflip(err))
230  err = 0;
231  if (err || read != pgsize) {
232  printk(PRINT_PREF "error: read failed at %#llx\n",
233  addr);
234  if (!err)
235  err = -EINVAL;
236  break;
237  }
238  addr += pgsize;
239  buf += pgsize;
240  }
241 
242  return err;
243 }
244 
245 static int read_eraseblock_by_2pages(int ebnum)
246 {
247  size_t read, sz = pgsize * 2;
248  int i, n = pgcnt / 2, err = 0;
249  loff_t addr = ebnum * mtd->erasesize;
250  void *buf = iobuf;
251 
252  for (i = 0; i < n; i++) {
253  err = mtd_read(mtd, addr, sz, &read, buf);
254  /* Ignore corrected ECC errors */
255  if (mtd_is_bitflip(err))
256  err = 0;
257  if (err || read != sz) {
258  printk(PRINT_PREF "error: read failed at %#llx\n",
259  addr);
260  if (!err)
261  err = -EINVAL;
262  return err;
263  }
264  addr += sz;
265  buf += sz;
266  }
267  if (pgcnt % 2) {
268  err = mtd_read(mtd, addr, pgsize, &read, buf);
269  /* Ignore corrected ECC errors */
270  if (mtd_is_bitflip(err))
271  err = 0;
272  if (err || read != pgsize) {
273  printk(PRINT_PREF "error: read failed at %#llx\n",
274  addr);
275  if (!err)
276  err = -EINVAL;
277  }
278  }
279 
280  return err;
281 }
282 
283 static int is_block_bad(int ebnum)
284 {
285  loff_t addr = ebnum * mtd->erasesize;
286  int ret;
287 
288  ret = mtd_block_isbad(mtd, addr);
289  if (ret)
290  printk(PRINT_PREF "block %d is bad\n", ebnum);
291  return ret;
292 }
293 
294 static inline void start_timing(void)
295 {
297 }
298 
299 static inline void stop_timing(void)
300 {
301  do_gettimeofday(&finish);
302 }
303 
304 static long calc_speed(void)
305 {
306  uint64_t k;
307  long ms;
308 
309  ms = (finish.tv_sec - start.tv_sec) * 1000 +
310  (finish.tv_usec - start.tv_usec) / 1000;
311  if (ms == 0)
312  return 0;
313  k = goodebcnt * (mtd->erasesize / 1024) * 1000;
314  do_div(k, ms);
315  return k;
316 }
317 
318 static int scan_for_bad_eraseblocks(void)
319 {
320  int i, bad = 0;
321 
322  bbt = kzalloc(ebcnt, GFP_KERNEL);
323  if (!bbt) {
324  printk(PRINT_PREF "error: cannot allocate memory\n");
325  return -ENOMEM;
326  }
327 
328  if (!mtd_can_have_bb(mtd))
329  goto out;
330 
331  printk(PRINT_PREF "scanning for bad eraseblocks\n");
332  for (i = 0; i < ebcnt; ++i) {
333  bbt[i] = is_block_bad(i) ? 1 : 0;
334  if (bbt[i])
335  bad += 1;
336  cond_resched();
337  }
338  printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
339 out:
340  goodebcnt = ebcnt - bad;
341  return 0;
342 }
343 
344 static int __init mtd_speedtest_init(void)
345 {
346  int err, i, blocks, j, k;
347  long speed;
348  uint64_t tmp;
349 
350  printk(KERN_INFO "\n");
351  printk(KERN_INFO "=================================================\n");
352 
353  if (dev < 0) {
354  printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
355  printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
356  return -EINVAL;
357  }
358 
359  if (count)
360  printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count);
361  else
362  printk(PRINT_PREF "MTD device: %d\n", dev);
363 
364  mtd = get_mtd_device(NULL, dev);
365  if (IS_ERR(mtd)) {
366  err = PTR_ERR(mtd);
367  printk(PRINT_PREF "error: cannot get MTD device\n");
368  return err;
369  }
370 
371  if (mtd->writesize == 1) {
372  printk(PRINT_PREF "not NAND flash, assume page size is 512 "
373  "bytes.\n");
374  pgsize = 512;
375  } else
376  pgsize = mtd->writesize;
377 
378  tmp = mtd->size;
379  do_div(tmp, mtd->erasesize);
380  ebcnt = tmp;
381  pgcnt = mtd->erasesize / pgsize;
382 
383  printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
384  "page size %u, count of eraseblocks %u, pages per "
385  "eraseblock %u, OOB size %u\n",
386  (unsigned long long)mtd->size, mtd->erasesize,
387  pgsize, ebcnt, pgcnt, mtd->oobsize);
388 
389  if (count > 0 && count < ebcnt)
390  ebcnt = count;
391 
392  err = -ENOMEM;
393  iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
394  if (!iobuf) {
395  printk(PRINT_PREF "error: cannot allocate memory\n");
396  goto out;
397  }
398 
399  set_random_data(iobuf, mtd->erasesize);
400 
401  err = scan_for_bad_eraseblocks();
402  if (err)
403  goto out;
404 
405  err = erase_whole_device();
406  if (err)
407  goto out;
408 
409  /* Write all eraseblocks, 1 eraseblock at a time */
410  printk(PRINT_PREF "testing eraseblock write speed\n");
411  start_timing();
412  for (i = 0; i < ebcnt; ++i) {
413  if (bbt[i])
414  continue;
415  err = write_eraseblock(i);
416  if (err)
417  goto out;
418  cond_resched();
419  }
420  stop_timing();
421  speed = calc_speed();
422  printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed);
423 
424  /* Read all eraseblocks, 1 eraseblock at a time */
425  printk(PRINT_PREF "testing eraseblock read speed\n");
426  start_timing();
427  for (i = 0; i < ebcnt; ++i) {
428  if (bbt[i])
429  continue;
430  err = read_eraseblock(i);
431  if (err)
432  goto out;
433  cond_resched();
434  }
435  stop_timing();
436  speed = calc_speed();
437  printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed);
438 
439  err = erase_whole_device();
440  if (err)
441  goto out;
442 
443  /* Write all eraseblocks, 1 page at a time */
444  printk(PRINT_PREF "testing page write speed\n");
445  start_timing();
446  for (i = 0; i < ebcnt; ++i) {
447  if (bbt[i])
448  continue;
449  err = write_eraseblock_by_page(i);
450  if (err)
451  goto out;
452  cond_resched();
453  }
454  stop_timing();
455  speed = calc_speed();
456  printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed);
457 
458  /* Read all eraseblocks, 1 page at a time */
459  printk(PRINT_PREF "testing page read speed\n");
460  start_timing();
461  for (i = 0; i < ebcnt; ++i) {
462  if (bbt[i])
463  continue;
464  err = read_eraseblock_by_page(i);
465  if (err)
466  goto out;
467  cond_resched();
468  }
469  stop_timing();
470  speed = calc_speed();
471  printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed);
472 
473  err = erase_whole_device();
474  if (err)
475  goto out;
476 
477  /* Write all eraseblocks, 2 pages at a time */
478  printk(PRINT_PREF "testing 2 page write speed\n");
479  start_timing();
480  for (i = 0; i < ebcnt; ++i) {
481  if (bbt[i])
482  continue;
483  err = write_eraseblock_by_2pages(i);
484  if (err)
485  goto out;
486  cond_resched();
487  }
488  stop_timing();
489  speed = calc_speed();
490  printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed);
491 
492  /* Read all eraseblocks, 2 pages at a time */
493  printk(PRINT_PREF "testing 2 page read speed\n");
494  start_timing();
495  for (i = 0; i < ebcnt; ++i) {
496  if (bbt[i])
497  continue;
498  err = read_eraseblock_by_2pages(i);
499  if (err)
500  goto out;
501  cond_resched();
502  }
503  stop_timing();
504  speed = calc_speed();
505  printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed);
506 
507  /* Erase all eraseblocks */
508  printk(PRINT_PREF "Testing erase speed\n");
509  start_timing();
510  for (i = 0; i < ebcnt; ++i) {
511  if (bbt[i])
512  continue;
513  err = erase_eraseblock(i);
514  if (err)
515  goto out;
516  cond_resched();
517  }
518  stop_timing();
519  speed = calc_speed();
520  printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);
521 
522  /* Multi-block erase all eraseblocks */
523  for (k = 1; k < 7; k++) {
524  blocks = 1 << k;
525  printk(PRINT_PREF "Testing %dx multi-block erase speed\n",
526  blocks);
527  start_timing();
528  for (i = 0; i < ebcnt; ) {
529  for (j = 0; j < blocks && (i + j) < ebcnt; j++)
530  if (bbt[i + j])
531  break;
532  if (j < 1) {
533  i++;
534  continue;
535  }
536  err = multiblock_erase(i, j);
537  if (err)
538  goto out;
539  cond_resched();
540  i += j;
541  }
542  stop_timing();
543  speed = calc_speed();
544  printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n",
545  blocks, speed);
546  }
547  printk(PRINT_PREF "finished\n");
548 out:
549  kfree(iobuf);
550  kfree(bbt);
551  put_mtd_device(mtd);
552  if (err)
553  printk(PRINT_PREF "error %d occurred\n", err);
554  printk(KERN_INFO "=================================================\n");
555  return err;
556 }
557 module_init(mtd_speedtest_init);
558 
559 static void __exit mtd_speedtest_exit(void)
560 {
561  return;
562 }
563 module_exit(mtd_speedtest_exit);
564 
565 MODULE_DESCRIPTION("Speed test module");
566 MODULE_AUTHOR("Adrian Hunter");
567 MODULE_LICENSE("GPL");