xref: /linux/drivers/mtd/tests/speedtest.c (revision 4cd10358d64a066ce31047e7704163c7c02d4bca)
1*4cd10358SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
272069be9SArtem Bityutskiy /*
372069be9SArtem Bityutskiy  * Copyright (C) 2007 Nokia Corporation
472069be9SArtem Bityutskiy  *
572069be9SArtem Bityutskiy  * Test read and write speed of a MTD device.
672069be9SArtem Bityutskiy  *
7fc7fe769SAdrian Hunter  * Author: Adrian Hunter <adrian.hunter@nokia.com>
872069be9SArtem Bityutskiy  */
972069be9SArtem Bityutskiy 
102c70d292SVikram Narayanan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
112c70d292SVikram Narayanan 
1272069be9SArtem Bityutskiy #include <linux/init.h>
13af30c0a0SShraddha Barke #include <linux/ktime.h>
1472069be9SArtem Bityutskiy #include <linux/module.h>
1572069be9SArtem Bityutskiy #include <linux/moduleparam.h>
1672069be9SArtem Bityutskiy #include <linux/err.h>
1772069be9SArtem Bityutskiy #include <linux/mtd/mtd.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
1972069be9SArtem Bityutskiy #include <linux/sched.h>
20bfea1d4eSArtem Bityutskiy #include <linux/random.h>
2172069be9SArtem Bityutskiy 
2259b0816dSAkinobu Mita #include "mtd_test.h"
2359b0816dSAkinobu Mita 
247406060eSWolfram Sang static int dev = -EINVAL;
2572069be9SArtem Bityutskiy module_param(dev, int, S_IRUGO);
2672069be9SArtem Bityutskiy MODULE_PARM_DESC(dev, "MTD device number to use");
2772069be9SArtem Bityutskiy 
28fc7fe769SAdrian Hunter static int count;
29fc7fe769SAdrian Hunter module_param(count, int, S_IRUGO);
30fc7fe769SAdrian Hunter MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use "
31fc7fe769SAdrian Hunter 			"(0 means use all)");
32fc7fe769SAdrian Hunter 
3372069be9SArtem Bityutskiy static struct mtd_info *mtd;
3472069be9SArtem Bityutskiy static unsigned char *iobuf;
3572069be9SArtem Bityutskiy static unsigned char *bbt;
3672069be9SArtem Bityutskiy 
3772069be9SArtem Bityutskiy static int pgsize;
3872069be9SArtem Bityutskiy static int ebcnt;
3972069be9SArtem Bityutskiy static int pgcnt;
4072069be9SArtem Bityutskiy static int goodebcnt;
41af30c0a0SShraddha Barke static ktime_t start, finish;
4272069be9SArtem Bityutskiy 
434085bcc6SRoman Tereshonkov static int multiblock_erase(int ebnum, int blocks)
444085bcc6SRoman Tereshonkov {
454085bcc6SRoman Tereshonkov 	int err;
464085bcc6SRoman Tereshonkov 	struct erase_info ei;
471001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
484085bcc6SRoman Tereshonkov 
494085bcc6SRoman Tereshonkov 	memset(&ei, 0, sizeof(struct erase_info));
504085bcc6SRoman Tereshonkov 	ei.addr = addr;
514085bcc6SRoman Tereshonkov 	ei.len  = mtd->erasesize * blocks;
524085bcc6SRoman Tereshonkov 
537e1f0dc0SArtem Bityutskiy 	err = mtd_erase(mtd, &ei);
544085bcc6SRoman Tereshonkov 	if (err) {
552c70d292SVikram Narayanan 		pr_err("error %d while erasing EB %d, blocks %d\n",
564085bcc6SRoman Tereshonkov 		       err, ebnum, blocks);
574085bcc6SRoman Tereshonkov 		return err;
584085bcc6SRoman Tereshonkov 	}
594085bcc6SRoman Tereshonkov 
604085bcc6SRoman Tereshonkov 	return 0;
614085bcc6SRoman Tereshonkov }
624085bcc6SRoman Tereshonkov 
6372069be9SArtem Bityutskiy static int write_eraseblock(int ebnum)
6472069be9SArtem Bityutskiy {
651001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
6672069be9SArtem Bityutskiy 
678a9f4aa3SAkinobu Mita 	return mtdtest_write(mtd, addr, mtd->erasesize, iobuf);
6872069be9SArtem Bityutskiy }
6972069be9SArtem Bityutskiy 
7072069be9SArtem Bityutskiy static int write_eraseblock_by_page(int ebnum)
7172069be9SArtem Bityutskiy {
7272069be9SArtem Bityutskiy 	int i, err = 0;
731001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
7472069be9SArtem Bityutskiy 	void *buf = iobuf;
7572069be9SArtem Bityutskiy 
7672069be9SArtem Bityutskiy 	for (i = 0; i < pgcnt; i++) {
7759b0816dSAkinobu Mita 		err = mtdtest_write(mtd, addr, pgsize, buf);
788a9f4aa3SAkinobu Mita 		if (err)
7972069be9SArtem Bityutskiy 			break;
8072069be9SArtem Bityutskiy 		addr += pgsize;
8172069be9SArtem Bityutskiy 		buf += pgsize;
8272069be9SArtem Bityutskiy 	}
8372069be9SArtem Bityutskiy 
8472069be9SArtem Bityutskiy 	return err;
8572069be9SArtem Bityutskiy }
8672069be9SArtem Bityutskiy 
8772069be9SArtem Bityutskiy static int write_eraseblock_by_2pages(int ebnum)
8872069be9SArtem Bityutskiy {
8959b0816dSAkinobu Mita 	size_t sz = pgsize * 2;
9072069be9SArtem Bityutskiy 	int i, n = pgcnt / 2, err = 0;
911001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
9272069be9SArtem Bityutskiy 	void *buf = iobuf;
9372069be9SArtem Bityutskiy 
9472069be9SArtem Bityutskiy 	for (i = 0; i < n; i++) {
9559b0816dSAkinobu Mita 		err = mtdtest_write(mtd, addr, sz, buf);
968a9f4aa3SAkinobu Mita 		if (err)
9772069be9SArtem Bityutskiy 			return err;
9872069be9SArtem Bityutskiy 		addr += sz;
9972069be9SArtem Bityutskiy 		buf += sz;
10072069be9SArtem Bityutskiy 	}
1018a9f4aa3SAkinobu Mita 	if (pgcnt % 2)
10259b0816dSAkinobu Mita 		err = mtdtest_write(mtd, addr, pgsize, buf);
10372069be9SArtem Bityutskiy 
10472069be9SArtem Bityutskiy 	return err;
10572069be9SArtem Bityutskiy }
10672069be9SArtem Bityutskiy 
10772069be9SArtem Bityutskiy static int read_eraseblock(int ebnum)
10872069be9SArtem Bityutskiy {
1091001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
11072069be9SArtem Bityutskiy 
111abc173adSAkinobu Mita 	return mtdtest_read(mtd, addr, mtd->erasesize, iobuf);
11272069be9SArtem Bityutskiy }
11372069be9SArtem Bityutskiy 
11472069be9SArtem Bityutskiy static int read_eraseblock_by_page(int ebnum)
11572069be9SArtem Bityutskiy {
11672069be9SArtem Bityutskiy 	int i, err = 0;
1171001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
11872069be9SArtem Bityutskiy 	void *buf = iobuf;
11972069be9SArtem Bityutskiy 
12072069be9SArtem Bityutskiy 	for (i = 0; i < pgcnt; i++) {
12159b0816dSAkinobu Mita 		err = mtdtest_read(mtd, addr, pgsize, buf);
122abc173adSAkinobu Mita 		if (err)
12372069be9SArtem Bityutskiy 			break;
12472069be9SArtem Bityutskiy 		addr += pgsize;
12572069be9SArtem Bityutskiy 		buf += pgsize;
12672069be9SArtem Bityutskiy 	}
12772069be9SArtem Bityutskiy 
12872069be9SArtem Bityutskiy 	return err;
12972069be9SArtem Bityutskiy }
13072069be9SArtem Bityutskiy 
13172069be9SArtem Bityutskiy static int read_eraseblock_by_2pages(int ebnum)
13272069be9SArtem Bityutskiy {
13359b0816dSAkinobu Mita 	size_t sz = pgsize * 2;
13472069be9SArtem Bityutskiy 	int i, n = pgcnt / 2, err = 0;
1351001ff7aSBrian Norris 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
13672069be9SArtem Bityutskiy 	void *buf = iobuf;
13772069be9SArtem Bityutskiy 
13872069be9SArtem Bityutskiy 	for (i = 0; i < n; i++) {
13959b0816dSAkinobu Mita 		err = mtdtest_read(mtd, addr, sz, buf);
140abc173adSAkinobu Mita 		if (err)
14172069be9SArtem Bityutskiy 			return err;
14272069be9SArtem Bityutskiy 		addr += sz;
14372069be9SArtem Bityutskiy 		buf += sz;
14472069be9SArtem Bityutskiy 	}
145abc173adSAkinobu Mita 	if (pgcnt % 2)
14659b0816dSAkinobu Mita 		err = mtdtest_read(mtd, addr, pgsize, buf);
14772069be9SArtem Bityutskiy 
14872069be9SArtem Bityutskiy 	return err;
14972069be9SArtem Bityutskiy }
15072069be9SArtem Bityutskiy 
15172069be9SArtem Bityutskiy static inline void start_timing(void)
15272069be9SArtem Bityutskiy {
153af30c0a0SShraddha Barke 	start = ktime_get();
15472069be9SArtem Bityutskiy }
15572069be9SArtem Bityutskiy 
15672069be9SArtem Bityutskiy static inline void stop_timing(void)
15772069be9SArtem Bityutskiy {
158af30c0a0SShraddha Barke 	finish = ktime_get();
15972069be9SArtem Bityutskiy }
16072069be9SArtem Bityutskiy 
16172069be9SArtem Bityutskiy static long calc_speed(void)
16272069be9SArtem Bityutskiy {
163e70727e4SDavid Lambert 	uint64_t k;
164e70727e4SDavid Lambert 	long ms;
16572069be9SArtem Bityutskiy 
166af30c0a0SShraddha Barke 	ms = ktime_ms_delta(finish, start);
167e70727e4SDavid Lambert 	if (ms == 0)
168e70727e4SDavid Lambert 		return 0;
169b9da8baeSBrian Norris 	k = (uint64_t)goodebcnt * (mtd->erasesize / 1024) * 1000;
170e70727e4SDavid Lambert 	do_div(k, ms);
171e70727e4SDavid Lambert 	return k;
17272069be9SArtem Bityutskiy }
17372069be9SArtem Bityutskiy 
17472069be9SArtem Bityutskiy static int __init mtd_speedtest_init(void)
17572069be9SArtem Bityutskiy {
1764085bcc6SRoman Tereshonkov 	int err, i, blocks, j, k;
17772069be9SArtem Bityutskiy 	long speed;
17872069be9SArtem Bityutskiy 	uint64_t tmp;
17972069be9SArtem Bityutskiy 
18072069be9SArtem Bityutskiy 	printk(KERN_INFO "\n");
18172069be9SArtem Bityutskiy 	printk(KERN_INFO "=================================================\n");
1827406060eSWolfram Sang 
1837406060eSWolfram Sang 	if (dev < 0) {
184064a7694SMasanari Iida 		pr_info("Please specify a valid mtd-device via module parameter\n");
1852c70d292SVikram Narayanan 		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
1867406060eSWolfram Sang 		return -EINVAL;
1877406060eSWolfram Sang 	}
1887406060eSWolfram Sang 
189fc7fe769SAdrian Hunter 	if (count)
1902c70d292SVikram Narayanan 		pr_info("MTD device: %d    count: %d\n", dev, count);
191fc7fe769SAdrian Hunter 	else
1922c70d292SVikram Narayanan 		pr_info("MTD device: %d\n", dev);
19372069be9SArtem Bityutskiy 
19472069be9SArtem Bityutskiy 	mtd = get_mtd_device(NULL, dev);
19572069be9SArtem Bityutskiy 	if (IS_ERR(mtd)) {
19672069be9SArtem Bityutskiy 		err = PTR_ERR(mtd);
1972c70d292SVikram Narayanan 		pr_err("error: cannot get MTD device\n");
19872069be9SArtem Bityutskiy 		return err;
19972069be9SArtem Bityutskiy 	}
20072069be9SArtem Bityutskiy 
20172069be9SArtem Bityutskiy 	if (mtd->writesize == 1) {
2022c70d292SVikram Narayanan 		pr_info("not NAND flash, assume page size is 512 "
20372069be9SArtem Bityutskiy 		       "bytes.\n");
20472069be9SArtem Bityutskiy 		pgsize = 512;
20572069be9SArtem Bityutskiy 	} else
20672069be9SArtem Bityutskiy 		pgsize = mtd->writesize;
20772069be9SArtem Bityutskiy 
20872069be9SArtem Bityutskiy 	tmp = mtd->size;
20972069be9SArtem Bityutskiy 	do_div(tmp, mtd->erasesize);
21072069be9SArtem Bityutskiy 	ebcnt = tmp;
211f5e2bae0SMorten Thunberg Svendsen 	pgcnt = mtd->erasesize / pgsize;
21272069be9SArtem Bityutskiy 
2132c70d292SVikram Narayanan 	pr_info("MTD device size %llu, eraseblock size %u, "
21472069be9SArtem Bityutskiy 	       "page size %u, count of eraseblocks %u, pages per "
21572069be9SArtem Bityutskiy 	       "eraseblock %u, OOB size %u\n",
21672069be9SArtem Bityutskiy 	       (unsigned long long)mtd->size, mtd->erasesize,
21772069be9SArtem Bityutskiy 	       pgsize, ebcnt, pgcnt, mtd->oobsize);
21872069be9SArtem Bityutskiy 
219fc7fe769SAdrian Hunter 	if (count > 0 && count < ebcnt)
220fc7fe769SAdrian Hunter 		ebcnt = count;
221fc7fe769SAdrian Hunter 
22272069be9SArtem Bityutskiy 	err = -ENOMEM;
22372069be9SArtem Bityutskiy 	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
22433777e66SBrian Norris 	if (!iobuf)
22572069be9SArtem Bityutskiy 		goto out;
22672069be9SArtem Bityutskiy 
22799672f32SAkinobu Mita 	prandom_bytes(iobuf, mtd->erasesize);
22872069be9SArtem Bityutskiy 
22959b0816dSAkinobu Mita 	bbt = kzalloc(ebcnt, GFP_KERNEL);
23059b0816dSAkinobu Mita 	if (!bbt)
23159b0816dSAkinobu Mita 		goto out;
23259b0816dSAkinobu Mita 	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
23372069be9SArtem Bityutskiy 	if (err)
23472069be9SArtem Bityutskiy 		goto out;
23559b0816dSAkinobu Mita 	for (i = 0; i < ebcnt; i++) {
23659b0816dSAkinobu Mita 		if (!bbt[i])
23759b0816dSAkinobu Mita 			goodebcnt++;
23859b0816dSAkinobu Mita 	}
23972069be9SArtem Bityutskiy 
24059b0816dSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
24172069be9SArtem Bityutskiy 	if (err)
24272069be9SArtem Bityutskiy 		goto out;
24372069be9SArtem Bityutskiy 
24472069be9SArtem Bityutskiy 	/* Write all eraseblocks, 1 eraseblock at a time */
2452c70d292SVikram Narayanan 	pr_info("testing eraseblock write speed\n");
24672069be9SArtem Bityutskiy 	start_timing();
24772069be9SArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
24872069be9SArtem Bityutskiy 		if (bbt[i])
24972069be9SArtem Bityutskiy 			continue;
25072069be9SArtem Bityutskiy 		err = write_eraseblock(i);
25172069be9SArtem Bityutskiy 		if (err)
25272069be9SArtem Bityutskiy 			goto out;
2532a6a28e7SRichard Weinberger 
2542a6a28e7SRichard Weinberger 		err = mtdtest_relax();
2552a6a28e7SRichard Weinberger 		if (err)
2562a6a28e7SRichard Weinberger 			goto out;
25772069be9SArtem Bityutskiy 	}
25872069be9SArtem Bityutskiy 	stop_timing();
25972069be9SArtem Bityutskiy 	speed = calc_speed();
2602c70d292SVikram Narayanan 	pr_info("eraseblock write speed is %ld KiB/s\n", speed);
26172069be9SArtem Bityutskiy 
26272069be9SArtem Bityutskiy 	/* Read all eraseblocks, 1 eraseblock at a time */
2632c70d292SVikram Narayanan 	pr_info("testing eraseblock read speed\n");
26472069be9SArtem Bityutskiy 	start_timing();
26572069be9SArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
26672069be9SArtem Bityutskiy 		if (bbt[i])
26772069be9SArtem Bityutskiy 			continue;
26872069be9SArtem Bityutskiy 		err = read_eraseblock(i);
26972069be9SArtem Bityutskiy 		if (err)
27072069be9SArtem Bityutskiy 			goto out;
2712a6a28e7SRichard Weinberger 
2722a6a28e7SRichard Weinberger 		err = mtdtest_relax();
2732a6a28e7SRichard Weinberger 		if (err)
2742a6a28e7SRichard Weinberger 			goto out;
27572069be9SArtem Bityutskiy 	}
27672069be9SArtem Bityutskiy 	stop_timing();
27772069be9SArtem Bityutskiy 	speed = calc_speed();
2782c70d292SVikram Narayanan 	pr_info("eraseblock read speed is %ld KiB/s\n", speed);
27972069be9SArtem Bityutskiy 
28059b0816dSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
28172069be9SArtem Bityutskiy 	if (err)
28272069be9SArtem Bityutskiy 		goto out;
28372069be9SArtem Bityutskiy 
28472069be9SArtem Bityutskiy 	/* Write all eraseblocks, 1 page at a time */
2852c70d292SVikram Narayanan 	pr_info("testing page write speed\n");
28672069be9SArtem Bityutskiy 	start_timing();
28772069be9SArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
28872069be9SArtem Bityutskiy 		if (bbt[i])
28972069be9SArtem Bityutskiy 			continue;
29072069be9SArtem Bityutskiy 		err = write_eraseblock_by_page(i);
29172069be9SArtem Bityutskiy 		if (err)
29272069be9SArtem Bityutskiy 			goto out;
2932a6a28e7SRichard Weinberger 
2942a6a28e7SRichard Weinberger 		err = mtdtest_relax();
2952a6a28e7SRichard Weinberger 		if (err)
2962a6a28e7SRichard Weinberger 			goto out;
29772069be9SArtem Bityutskiy 	}
29872069be9SArtem Bityutskiy 	stop_timing();
29972069be9SArtem Bityutskiy 	speed = calc_speed();
3002c70d292SVikram Narayanan 	pr_info("page write speed is %ld KiB/s\n", speed);
30172069be9SArtem Bityutskiy 
30272069be9SArtem Bityutskiy 	/* Read all eraseblocks, 1 page at a time */
3032c70d292SVikram Narayanan 	pr_info("testing page read speed\n");
30472069be9SArtem Bityutskiy 	start_timing();
30572069be9SArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
30672069be9SArtem Bityutskiy 		if (bbt[i])
30772069be9SArtem Bityutskiy 			continue;
30872069be9SArtem Bityutskiy 		err = read_eraseblock_by_page(i);
30972069be9SArtem Bityutskiy 		if (err)
31072069be9SArtem Bityutskiy 			goto out;
3112a6a28e7SRichard Weinberger 
3122a6a28e7SRichard Weinberger 		err = mtdtest_relax();
3132a6a28e7SRichard Weinberger 		if (err)
3142a6a28e7SRichard Weinberger 			goto out;
31572069be9SArtem Bityutskiy 	}
31672069be9SArtem Bityutskiy 	stop_timing();
31772069be9SArtem Bityutskiy 	speed = calc_speed();
3182c70d292SVikram Narayanan 	pr_info("page read speed is %ld KiB/s\n", speed);
31972069be9SArtem Bityutskiy 
32059b0816dSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
32172069be9SArtem Bityutskiy 	if (err)
32272069be9SArtem Bityutskiy 		goto out;
32372069be9SArtem Bityutskiy 
32472069be9SArtem Bityutskiy 	/* Write all eraseblocks, 2 pages at a time */
3252c70d292SVikram Narayanan 	pr_info("testing 2 page write speed\n");
32672069be9SArtem Bityutskiy 	start_timing();
32772069be9SArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
32872069be9SArtem Bityutskiy 		if (bbt[i])
32972069be9SArtem Bityutskiy 			continue;
33072069be9SArtem Bityutskiy 		err = write_eraseblock_by_2pages(i);
33172069be9SArtem Bityutskiy 		if (err)
33272069be9SArtem Bityutskiy 			goto out;
3332a6a28e7SRichard Weinberger 
3342a6a28e7SRichard Weinberger 		err = mtdtest_relax();
3352a6a28e7SRichard Weinberger 		if (err)
3362a6a28e7SRichard Weinberger 			goto out;
33772069be9SArtem Bityutskiy 	}
33872069be9SArtem Bityutskiy 	stop_timing();
33972069be9SArtem Bityutskiy 	speed = calc_speed();
3402c70d292SVikram Narayanan 	pr_info("2 page write speed is %ld KiB/s\n", speed);
34172069be9SArtem Bityutskiy 
34272069be9SArtem Bityutskiy 	/* Read all eraseblocks, 2 pages at a time */
3432c70d292SVikram Narayanan 	pr_info("testing 2 page read speed\n");
34472069be9SArtem Bityutskiy 	start_timing();
34572069be9SArtem Bityutskiy 	for (i = 0; i < ebcnt; ++i) {
34672069be9SArtem Bityutskiy 		if (bbt[i])
34772069be9SArtem Bityutskiy 			continue;
34872069be9SArtem Bityutskiy 		err = read_eraseblock_by_2pages(i);
34972069be9SArtem Bityutskiy 		if (err)
35072069be9SArtem Bityutskiy 			goto out;
3512a6a28e7SRichard Weinberger 
3522a6a28e7SRichard Weinberger 		err = mtdtest_relax();
3532a6a28e7SRichard Weinberger 		if (err)
3542a6a28e7SRichard Weinberger 			goto out;
35572069be9SArtem Bityutskiy 	}
35672069be9SArtem Bityutskiy 	stop_timing();
35772069be9SArtem Bityutskiy 	speed = calc_speed();
3582c70d292SVikram Narayanan 	pr_info("2 page read speed is %ld KiB/s\n", speed);
35972069be9SArtem Bityutskiy 
36072069be9SArtem Bityutskiy 	/* Erase all eraseblocks */
3612c70d292SVikram Narayanan 	pr_info("Testing erase speed\n");
36272069be9SArtem Bityutskiy 	start_timing();
36359b0816dSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
36472069be9SArtem Bityutskiy 	if (err)
36572069be9SArtem Bityutskiy 		goto out;
36672069be9SArtem Bityutskiy 	stop_timing();
36772069be9SArtem Bityutskiy 	speed = calc_speed();
3682c70d292SVikram Narayanan 	pr_info("erase speed is %ld KiB/s\n", speed);
36972069be9SArtem Bityutskiy 
3704085bcc6SRoman Tereshonkov 	/* Multi-block erase all eraseblocks */
3714085bcc6SRoman Tereshonkov 	for (k = 1; k < 7; k++) {
3724085bcc6SRoman Tereshonkov 		blocks = 1 << k;
3732c70d292SVikram Narayanan 		pr_info("Testing %dx multi-block erase speed\n",
3744085bcc6SRoman Tereshonkov 		       blocks);
3754085bcc6SRoman Tereshonkov 		start_timing();
3764085bcc6SRoman Tereshonkov 		for (i = 0; i < ebcnt; ) {
3774085bcc6SRoman Tereshonkov 			for (j = 0; j < blocks && (i + j) < ebcnt; j++)
3784085bcc6SRoman Tereshonkov 				if (bbt[i + j])
3794085bcc6SRoman Tereshonkov 					break;
3804085bcc6SRoman Tereshonkov 			if (j < 1) {
3814085bcc6SRoman Tereshonkov 				i++;
3824085bcc6SRoman Tereshonkov 				continue;
3834085bcc6SRoman Tereshonkov 			}
3844085bcc6SRoman Tereshonkov 			err = multiblock_erase(i, j);
3854085bcc6SRoman Tereshonkov 			if (err)
3864085bcc6SRoman Tereshonkov 				goto out;
3872a6a28e7SRichard Weinberger 
3882a6a28e7SRichard Weinberger 			err = mtdtest_relax();
3892a6a28e7SRichard Weinberger 			if (err)
3902a6a28e7SRichard Weinberger 				goto out;
3912a6a28e7SRichard Weinberger 
3924085bcc6SRoman Tereshonkov 			i += j;
3934085bcc6SRoman Tereshonkov 		}
3944085bcc6SRoman Tereshonkov 		stop_timing();
3954085bcc6SRoman Tereshonkov 		speed = calc_speed();
3962c70d292SVikram Narayanan 		pr_info("%dx multi-block erase speed is %ld KiB/s\n",
3974085bcc6SRoman Tereshonkov 		       blocks, speed);
3984085bcc6SRoman Tereshonkov 	}
3992c70d292SVikram Narayanan 	pr_info("finished\n");
40072069be9SArtem Bityutskiy out:
40172069be9SArtem Bityutskiy 	kfree(iobuf);
40272069be9SArtem Bityutskiy 	kfree(bbt);
40372069be9SArtem Bityutskiy 	put_mtd_device(mtd);
40472069be9SArtem Bityutskiy 	if (err)
4052c70d292SVikram Narayanan 		pr_info("error %d occurred\n", err);
40672069be9SArtem Bityutskiy 	printk(KERN_INFO "=================================================\n");
40772069be9SArtem Bityutskiy 	return err;
40872069be9SArtem Bityutskiy }
40972069be9SArtem Bityutskiy module_init(mtd_speedtest_init);
41072069be9SArtem Bityutskiy 
41172069be9SArtem Bityutskiy static void __exit mtd_speedtest_exit(void)
41272069be9SArtem Bityutskiy {
41372069be9SArtem Bityutskiy 	return;
41472069be9SArtem Bityutskiy }
41572069be9SArtem Bityutskiy module_exit(mtd_speedtest_exit);
41672069be9SArtem Bityutskiy 
41772069be9SArtem Bityutskiy MODULE_DESCRIPTION("Speed test module");
41872069be9SArtem Bityutskiy MODULE_AUTHOR("Adrian Hunter");
41972069be9SArtem Bityutskiy MODULE_LICENSE("GPL");
420