18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Nokia Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Test read and write speed of a MTD device. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Adrian Hunter <adrian.hunter@nokia.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/ktime.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci#include <linux/random.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "mtd_test.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int dev = -EINVAL; 258c2ecf20Sopenharmony_cimodule_param(dev, int, S_IRUGO); 268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dev, "MTD device number to use"); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int count; 298c2ecf20Sopenharmony_cimodule_param(count, int, S_IRUGO); 308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(count, "Maximum number of eraseblocks to use " 318c2ecf20Sopenharmony_ci "(0 means use all)"); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct mtd_info *mtd; 348c2ecf20Sopenharmony_cistatic unsigned char *iobuf; 358c2ecf20Sopenharmony_cistatic unsigned char *bbt; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int pgsize; 388c2ecf20Sopenharmony_cistatic int ebcnt; 398c2ecf20Sopenharmony_cistatic int pgcnt; 408c2ecf20Sopenharmony_cistatic int goodebcnt; 418c2ecf20Sopenharmony_cistatic ktime_t start, finish; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int multiblock_erase(int ebnum, int blocks) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci int err; 468c2ecf20Sopenharmony_ci struct erase_info ei; 478c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci memset(&ei, 0, sizeof(struct erase_info)); 508c2ecf20Sopenharmony_ci ei.addr = addr; 518c2ecf20Sopenharmony_ci ei.len = mtd->erasesize * blocks; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci err = mtd_erase(mtd, &ei); 548c2ecf20Sopenharmony_ci if (err) { 558c2ecf20Sopenharmony_ci pr_err("error %d while erasing EB %d, blocks %d\n", 568c2ecf20Sopenharmony_ci err, ebnum, blocks); 578c2ecf20Sopenharmony_ci return err; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int write_eraseblock(int ebnum) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return mtdtest_write(mtd, addr, mtd->erasesize, iobuf); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int write_eraseblock_by_page(int ebnum) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int i, err = 0; 738c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 748c2ecf20Sopenharmony_ci void *buf = iobuf; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci for (i = 0; i < pgcnt; i++) { 778c2ecf20Sopenharmony_ci err = mtdtest_write(mtd, addr, pgsize, buf); 788c2ecf20Sopenharmony_ci if (err) 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci addr += pgsize; 818c2ecf20Sopenharmony_ci buf += pgsize; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return err; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int write_eraseblock_by_2pages(int ebnum) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci size_t sz = pgsize * 2; 908c2ecf20Sopenharmony_ci int i, n = pgcnt / 2, err = 0; 918c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 928c2ecf20Sopenharmony_ci void *buf = iobuf; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 958c2ecf20Sopenharmony_ci err = mtdtest_write(mtd, addr, sz, buf); 968c2ecf20Sopenharmony_ci if (err) 978c2ecf20Sopenharmony_ci return err; 988c2ecf20Sopenharmony_ci addr += sz; 998c2ecf20Sopenharmony_ci buf += sz; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci if (pgcnt % 2) 1028c2ecf20Sopenharmony_ci err = mtdtest_write(mtd, addr, pgsize, buf); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return err; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int read_eraseblock(int ebnum) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return mtdtest_read(mtd, addr, mtd->erasesize, iobuf); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int read_eraseblock_by_page(int ebnum) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci int i, err = 0; 1178c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 1188c2ecf20Sopenharmony_ci void *buf = iobuf; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci for (i = 0; i < pgcnt; i++) { 1218c2ecf20Sopenharmony_ci err = mtdtest_read(mtd, addr, pgsize, buf); 1228c2ecf20Sopenharmony_ci if (err) 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci addr += pgsize; 1258c2ecf20Sopenharmony_ci buf += pgsize; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return err; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int read_eraseblock_by_2pages(int ebnum) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci size_t sz = pgsize * 2; 1348c2ecf20Sopenharmony_ci int i, n = pgcnt / 2, err = 0; 1358c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 1368c2ecf20Sopenharmony_ci void *buf = iobuf; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) { 1398c2ecf20Sopenharmony_ci err = mtdtest_read(mtd, addr, sz, buf); 1408c2ecf20Sopenharmony_ci if (err) 1418c2ecf20Sopenharmony_ci return err; 1428c2ecf20Sopenharmony_ci addr += sz; 1438c2ecf20Sopenharmony_ci buf += sz; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci if (pgcnt % 2) 1468c2ecf20Sopenharmony_ci err = mtdtest_read(mtd, addr, pgsize, buf); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return err; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline void start_timing(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci start = ktime_get(); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline void stop_timing(void) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci finish = ktime_get(); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic long calc_speed(void) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci uint64_t k; 1648c2ecf20Sopenharmony_ci long ms; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ms = ktime_ms_delta(finish, start); 1678c2ecf20Sopenharmony_ci if (ms == 0) 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci k = (uint64_t)goodebcnt * (mtd->erasesize / 1024) * 1000; 1708c2ecf20Sopenharmony_ci do_div(k, ms); 1718c2ecf20Sopenharmony_ci return k; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int __init mtd_speedtest_init(void) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci int err, i, blocks, j, k; 1778c2ecf20Sopenharmony_ci long speed; 1788c2ecf20Sopenharmony_ci uint64_t tmp; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci printk(KERN_INFO "\n"); 1818c2ecf20Sopenharmony_ci printk(KERN_INFO "=================================================\n"); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (dev < 0) { 1848c2ecf20Sopenharmony_ci pr_info("Please specify a valid mtd-device via module parameter\n"); 1858c2ecf20Sopenharmony_ci pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 1868c2ecf20Sopenharmony_ci return -EINVAL; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (count) 1908c2ecf20Sopenharmony_ci pr_info("MTD device: %d count: %d\n", dev, count); 1918c2ecf20Sopenharmony_ci else 1928c2ecf20Sopenharmony_ci pr_info("MTD device: %d\n", dev); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci mtd = get_mtd_device(NULL, dev); 1958c2ecf20Sopenharmony_ci if (IS_ERR(mtd)) { 1968c2ecf20Sopenharmony_ci err = PTR_ERR(mtd); 1978c2ecf20Sopenharmony_ci pr_err("error: cannot get MTD device\n"); 1988c2ecf20Sopenharmony_ci return err; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (mtd->writesize == 1) { 2028c2ecf20Sopenharmony_ci pr_info("not NAND flash, assume page size is 512 " 2038c2ecf20Sopenharmony_ci "bytes.\n"); 2048c2ecf20Sopenharmony_ci pgsize = 512; 2058c2ecf20Sopenharmony_ci } else 2068c2ecf20Sopenharmony_ci pgsize = mtd->writesize; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci tmp = mtd->size; 2098c2ecf20Sopenharmony_ci do_div(tmp, mtd->erasesize); 2108c2ecf20Sopenharmony_ci ebcnt = tmp; 2118c2ecf20Sopenharmony_ci pgcnt = mtd->erasesize / pgsize; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci pr_info("MTD device size %llu, eraseblock size %u, " 2148c2ecf20Sopenharmony_ci "page size %u, count of eraseblocks %u, pages per " 2158c2ecf20Sopenharmony_ci "eraseblock %u, OOB size %u\n", 2168c2ecf20Sopenharmony_ci (unsigned long long)mtd->size, mtd->erasesize, 2178c2ecf20Sopenharmony_ci pgsize, ebcnt, pgcnt, mtd->oobsize); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (count > 0 && count < ebcnt) 2208c2ecf20Sopenharmony_ci ebcnt = count; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci err = -ENOMEM; 2238c2ecf20Sopenharmony_ci iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); 2248c2ecf20Sopenharmony_ci if (!iobuf) 2258c2ecf20Sopenharmony_ci goto out; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci prandom_bytes(iobuf, mtd->erasesize); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci bbt = kzalloc(ebcnt, GFP_KERNEL); 2308c2ecf20Sopenharmony_ci if (!bbt) 2318c2ecf20Sopenharmony_ci goto out; 2328c2ecf20Sopenharmony_ci err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 2338c2ecf20Sopenharmony_ci if (err) 2348c2ecf20Sopenharmony_ci goto out; 2358c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; i++) { 2368c2ecf20Sopenharmony_ci if (!bbt[i]) 2378c2ecf20Sopenharmony_ci goodebcnt++; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 2418c2ecf20Sopenharmony_ci if (err) 2428c2ecf20Sopenharmony_ci goto out; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Write all eraseblocks, 1 eraseblock at a time */ 2458c2ecf20Sopenharmony_ci pr_info("testing eraseblock write speed\n"); 2468c2ecf20Sopenharmony_ci start_timing(); 2478c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 2488c2ecf20Sopenharmony_ci if (bbt[i]) 2498c2ecf20Sopenharmony_ci continue; 2508c2ecf20Sopenharmony_ci err = write_eraseblock(i); 2518c2ecf20Sopenharmony_ci if (err) 2528c2ecf20Sopenharmony_ci goto out; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci err = mtdtest_relax(); 2558c2ecf20Sopenharmony_ci if (err) 2568c2ecf20Sopenharmony_ci goto out; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci stop_timing(); 2598c2ecf20Sopenharmony_ci speed = calc_speed(); 2608c2ecf20Sopenharmony_ci pr_info("eraseblock write speed is %ld KiB/s\n", speed); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Read all eraseblocks, 1 eraseblock at a time */ 2638c2ecf20Sopenharmony_ci pr_info("testing eraseblock read speed\n"); 2648c2ecf20Sopenharmony_ci start_timing(); 2658c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 2668c2ecf20Sopenharmony_ci if (bbt[i]) 2678c2ecf20Sopenharmony_ci continue; 2688c2ecf20Sopenharmony_ci err = read_eraseblock(i); 2698c2ecf20Sopenharmony_ci if (err) 2708c2ecf20Sopenharmony_ci goto out; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci err = mtdtest_relax(); 2738c2ecf20Sopenharmony_ci if (err) 2748c2ecf20Sopenharmony_ci goto out; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci stop_timing(); 2778c2ecf20Sopenharmony_ci speed = calc_speed(); 2788c2ecf20Sopenharmony_ci pr_info("eraseblock read speed is %ld KiB/s\n", speed); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 2818c2ecf20Sopenharmony_ci if (err) 2828c2ecf20Sopenharmony_ci goto out; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Write all eraseblocks, 1 page at a time */ 2858c2ecf20Sopenharmony_ci pr_info("testing page write speed\n"); 2868c2ecf20Sopenharmony_ci start_timing(); 2878c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 2888c2ecf20Sopenharmony_ci if (bbt[i]) 2898c2ecf20Sopenharmony_ci continue; 2908c2ecf20Sopenharmony_ci err = write_eraseblock_by_page(i); 2918c2ecf20Sopenharmony_ci if (err) 2928c2ecf20Sopenharmony_ci goto out; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci err = mtdtest_relax(); 2958c2ecf20Sopenharmony_ci if (err) 2968c2ecf20Sopenharmony_ci goto out; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci stop_timing(); 2998c2ecf20Sopenharmony_ci speed = calc_speed(); 3008c2ecf20Sopenharmony_ci pr_info("page write speed is %ld KiB/s\n", speed); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* Read all eraseblocks, 1 page at a time */ 3038c2ecf20Sopenharmony_ci pr_info("testing page read speed\n"); 3048c2ecf20Sopenharmony_ci start_timing(); 3058c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 3068c2ecf20Sopenharmony_ci if (bbt[i]) 3078c2ecf20Sopenharmony_ci continue; 3088c2ecf20Sopenharmony_ci err = read_eraseblock_by_page(i); 3098c2ecf20Sopenharmony_ci if (err) 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci err = mtdtest_relax(); 3138c2ecf20Sopenharmony_ci if (err) 3148c2ecf20Sopenharmony_ci goto out; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci stop_timing(); 3178c2ecf20Sopenharmony_ci speed = calc_speed(); 3188c2ecf20Sopenharmony_ci pr_info("page read speed is %ld KiB/s\n", speed); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 3218c2ecf20Sopenharmony_ci if (err) 3228c2ecf20Sopenharmony_ci goto out; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Write all eraseblocks, 2 pages at a time */ 3258c2ecf20Sopenharmony_ci pr_info("testing 2 page write speed\n"); 3268c2ecf20Sopenharmony_ci start_timing(); 3278c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 3288c2ecf20Sopenharmony_ci if (bbt[i]) 3298c2ecf20Sopenharmony_ci continue; 3308c2ecf20Sopenharmony_ci err = write_eraseblock_by_2pages(i); 3318c2ecf20Sopenharmony_ci if (err) 3328c2ecf20Sopenharmony_ci goto out; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci err = mtdtest_relax(); 3358c2ecf20Sopenharmony_ci if (err) 3368c2ecf20Sopenharmony_ci goto out; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci stop_timing(); 3398c2ecf20Sopenharmony_ci speed = calc_speed(); 3408c2ecf20Sopenharmony_ci pr_info("2 page write speed is %ld KiB/s\n", speed); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Read all eraseblocks, 2 pages at a time */ 3438c2ecf20Sopenharmony_ci pr_info("testing 2 page read speed\n"); 3448c2ecf20Sopenharmony_ci start_timing(); 3458c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 3468c2ecf20Sopenharmony_ci if (bbt[i]) 3478c2ecf20Sopenharmony_ci continue; 3488c2ecf20Sopenharmony_ci err = read_eraseblock_by_2pages(i); 3498c2ecf20Sopenharmony_ci if (err) 3508c2ecf20Sopenharmony_ci goto out; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci err = mtdtest_relax(); 3538c2ecf20Sopenharmony_ci if (err) 3548c2ecf20Sopenharmony_ci goto out; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci stop_timing(); 3578c2ecf20Sopenharmony_ci speed = calc_speed(); 3588c2ecf20Sopenharmony_ci pr_info("2 page read speed is %ld KiB/s\n", speed); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Erase all eraseblocks */ 3618c2ecf20Sopenharmony_ci pr_info("Testing erase speed\n"); 3628c2ecf20Sopenharmony_ci start_timing(); 3638c2ecf20Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 3648c2ecf20Sopenharmony_ci if (err) 3658c2ecf20Sopenharmony_ci goto out; 3668c2ecf20Sopenharmony_ci stop_timing(); 3678c2ecf20Sopenharmony_ci speed = calc_speed(); 3688c2ecf20Sopenharmony_ci pr_info("erase speed is %ld KiB/s\n", speed); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Multi-block erase all eraseblocks */ 3718c2ecf20Sopenharmony_ci for (k = 1; k < 7; k++) { 3728c2ecf20Sopenharmony_ci blocks = 1 << k; 3738c2ecf20Sopenharmony_ci pr_info("Testing %dx multi-block erase speed\n", 3748c2ecf20Sopenharmony_ci blocks); 3758c2ecf20Sopenharmony_ci start_timing(); 3768c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ) { 3778c2ecf20Sopenharmony_ci for (j = 0; j < blocks && (i + j) < ebcnt; j++) 3788c2ecf20Sopenharmony_ci if (bbt[i + j]) 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci if (j < 1) { 3818c2ecf20Sopenharmony_ci i++; 3828c2ecf20Sopenharmony_ci continue; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci err = multiblock_erase(i, j); 3858c2ecf20Sopenharmony_ci if (err) 3868c2ecf20Sopenharmony_ci goto out; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci err = mtdtest_relax(); 3898c2ecf20Sopenharmony_ci if (err) 3908c2ecf20Sopenharmony_ci goto out; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci i += j; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci stop_timing(); 3958c2ecf20Sopenharmony_ci speed = calc_speed(); 3968c2ecf20Sopenharmony_ci pr_info("%dx multi-block erase speed is %ld KiB/s\n", 3978c2ecf20Sopenharmony_ci blocks, speed); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci pr_info("finished\n"); 4008c2ecf20Sopenharmony_ciout: 4018c2ecf20Sopenharmony_ci kfree(iobuf); 4028c2ecf20Sopenharmony_ci kfree(bbt); 4038c2ecf20Sopenharmony_ci put_mtd_device(mtd); 4048c2ecf20Sopenharmony_ci if (err) 4058c2ecf20Sopenharmony_ci pr_info("error %d occurred\n", err); 4068c2ecf20Sopenharmony_ci printk(KERN_INFO "=================================================\n"); 4078c2ecf20Sopenharmony_ci return err; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_cimodule_init(mtd_speedtest_init); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic void __exit mtd_speedtest_exit(void) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci return; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_cimodule_exit(mtd_speedtest_exit); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Speed test module"); 4188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Adrian Hunter"); 4198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 420