cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

speedtest.c (8570B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2007 Nokia Corporation
      4 *
      5 * Test read and write speed of a MTD device.
      6 *
      7 * Author: Adrian Hunter <adrian.hunter@nokia.com>
      8 */
      9
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12#include <linux/init.h>
     13#include <linux/ktime.h>
     14#include <linux/module.h>
     15#include <linux/moduleparam.h>
     16#include <linux/err.h>
     17#include <linux/mtd/mtd.h>
     18#include <linux/slab.h>
     19#include <linux/sched.h>
     20#include <linux/random.h>
     21
     22#include "mtd_test.h"
     23
     24static int dev = -EINVAL;
     25module_param(dev, int, S_IRUGO);
     26MODULE_PARM_DESC(dev, "MTD device number to use");
     27
     28static int count;
     29module_param(count, int, S_IRUGO);
     30MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use "
     31			"(0 means use all)");
     32
     33static struct mtd_info *mtd;
     34static unsigned char *iobuf;
     35static unsigned char *bbt;
     36
     37static int pgsize;
     38static int ebcnt;
     39static int pgcnt;
     40static int goodebcnt;
     41static ktime_t start, finish;
     42
     43static int multiblock_erase(int ebnum, int blocks)
     44{
     45	int err;
     46	struct erase_info ei;
     47	loff_t addr = (loff_t)ebnum * mtd->erasesize;
     48
     49	memset(&ei, 0, sizeof(struct erase_info));
     50	ei.addr = addr;
     51	ei.len  = mtd->erasesize * blocks;
     52
     53	err = mtd_erase(mtd, &ei);
     54	if (err) {
     55		pr_err("error %d while erasing EB %d, blocks %d\n",
     56		       err, ebnum, blocks);
     57		return err;
     58	}
     59
     60	return 0;
     61}
     62
     63static int write_eraseblock(int ebnum)
     64{
     65	loff_t addr = (loff_t)ebnum * mtd->erasesize;
     66
     67	return mtdtest_write(mtd, addr, mtd->erasesize, iobuf);
     68}
     69
     70static int write_eraseblock_by_page(int ebnum)
     71{
     72	int i, err = 0;
     73	loff_t addr = (loff_t)ebnum * mtd->erasesize;
     74	void *buf = iobuf;
     75
     76	for (i = 0; i < pgcnt; i++) {
     77		err = mtdtest_write(mtd, addr, pgsize, buf);
     78		if (err)
     79			break;
     80		addr += pgsize;
     81		buf += pgsize;
     82	}
     83
     84	return err;
     85}
     86
     87static int write_eraseblock_by_2pages(int ebnum)
     88{
     89	size_t sz = pgsize * 2;
     90	int i, n = pgcnt / 2, err = 0;
     91	loff_t addr = (loff_t)ebnum * mtd->erasesize;
     92	void *buf = iobuf;
     93
     94	for (i = 0; i < n; i++) {
     95		err = mtdtest_write(mtd, addr, sz, buf);
     96		if (err)
     97			return err;
     98		addr += sz;
     99		buf += sz;
    100	}
    101	if (pgcnt % 2)
    102		err = mtdtest_write(mtd, addr, pgsize, buf);
    103
    104	return err;
    105}
    106
    107static int read_eraseblock(int ebnum)
    108{
    109	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    110
    111	return mtdtest_read(mtd, addr, mtd->erasesize, iobuf);
    112}
    113
    114static int read_eraseblock_by_page(int ebnum)
    115{
    116	int i, err = 0;
    117	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    118	void *buf = iobuf;
    119
    120	for (i = 0; i < pgcnt; i++) {
    121		err = mtdtest_read(mtd, addr, pgsize, buf);
    122		if (err)
    123			break;
    124		addr += pgsize;
    125		buf += pgsize;
    126	}
    127
    128	return err;
    129}
    130
    131static int read_eraseblock_by_2pages(int ebnum)
    132{
    133	size_t sz = pgsize * 2;
    134	int i, n = pgcnt / 2, err = 0;
    135	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    136	void *buf = iobuf;
    137
    138	for (i = 0; i < n; i++) {
    139		err = mtdtest_read(mtd, addr, sz, buf);
    140		if (err)
    141			return err;
    142		addr += sz;
    143		buf += sz;
    144	}
    145	if (pgcnt % 2)
    146		err = mtdtest_read(mtd, addr, pgsize, buf);
    147
    148	return err;
    149}
    150
    151static inline void start_timing(void)
    152{
    153	start = ktime_get();
    154}
    155
    156static inline void stop_timing(void)
    157{
    158	finish = ktime_get();
    159}
    160
    161static long calc_speed(void)
    162{
    163	uint64_t k, us;
    164
    165	us = ktime_us_delta(finish, start);
    166	if (us == 0)
    167		return 0;
    168	k = (uint64_t)goodebcnt * (mtd->erasesize / 1024) * 1000000;
    169	do_div(k, us);
    170	return k;
    171}
    172
    173static int __init mtd_speedtest_init(void)
    174{
    175	int err, i, blocks, j, k;
    176	long speed;
    177	uint64_t tmp;
    178
    179	printk(KERN_INFO "\n");
    180	printk(KERN_INFO "=================================================\n");
    181
    182	if (dev < 0) {
    183		pr_info("Please specify a valid mtd-device via module parameter\n");
    184		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
    185		return -EINVAL;
    186	}
    187
    188	if (count)
    189		pr_info("MTD device: %d    count: %d\n", dev, count);
    190	else
    191		pr_info("MTD device: %d\n", dev);
    192
    193	mtd = get_mtd_device(NULL, dev);
    194	if (IS_ERR(mtd)) {
    195		err = PTR_ERR(mtd);
    196		pr_err("error: cannot get MTD device\n");
    197		return err;
    198	}
    199
    200	if (mtd->writesize == 1) {
    201		pr_info("not NAND flash, assume page size is 512 "
    202		       "bytes.\n");
    203		pgsize = 512;
    204	} else
    205		pgsize = mtd->writesize;
    206
    207	tmp = mtd->size;
    208	do_div(tmp, mtd->erasesize);
    209	ebcnt = tmp;
    210	pgcnt = mtd->erasesize / pgsize;
    211
    212	pr_info("MTD device size %llu, eraseblock size %u, "
    213	       "page size %u, count of eraseblocks %u, pages per "
    214	       "eraseblock %u, OOB size %u\n",
    215	       (unsigned long long)mtd->size, mtd->erasesize,
    216	       pgsize, ebcnt, pgcnt, mtd->oobsize);
    217
    218	if (count > 0 && count < ebcnt)
    219		ebcnt = count;
    220
    221	err = -ENOMEM;
    222	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
    223	if (!iobuf)
    224		goto out;
    225
    226	prandom_bytes(iobuf, mtd->erasesize);
    227
    228	bbt = kzalloc(ebcnt, GFP_KERNEL);
    229	if (!bbt)
    230		goto out;
    231	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
    232	if (err)
    233		goto out;
    234	for (i = 0; i < ebcnt; i++) {
    235		if (!bbt[i])
    236			goodebcnt++;
    237	}
    238
    239	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    240	if (err)
    241		goto out;
    242
    243	/* Write all eraseblocks, 1 eraseblock at a time */
    244	pr_info("testing eraseblock write speed\n");
    245	start_timing();
    246	for (i = 0; i < ebcnt; ++i) {
    247		if (bbt[i])
    248			continue;
    249		err = write_eraseblock(i);
    250		if (err)
    251			goto out;
    252
    253		err = mtdtest_relax();
    254		if (err)
    255			goto out;
    256	}
    257	stop_timing();
    258	speed = calc_speed();
    259	pr_info("eraseblock write speed is %ld KiB/s\n", speed);
    260
    261	/* Read all eraseblocks, 1 eraseblock at a time */
    262	pr_info("testing eraseblock read speed\n");
    263	start_timing();
    264	for (i = 0; i < ebcnt; ++i) {
    265		if (bbt[i])
    266			continue;
    267		err = read_eraseblock(i);
    268		if (err)
    269			goto out;
    270
    271		err = mtdtest_relax();
    272		if (err)
    273			goto out;
    274	}
    275	stop_timing();
    276	speed = calc_speed();
    277	pr_info("eraseblock read speed is %ld KiB/s\n", speed);
    278
    279	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    280	if (err)
    281		goto out;
    282
    283	/* Write all eraseblocks, 1 page at a time */
    284	pr_info("testing page write speed\n");
    285	start_timing();
    286	for (i = 0; i < ebcnt; ++i) {
    287		if (bbt[i])
    288			continue;
    289		err = write_eraseblock_by_page(i);
    290		if (err)
    291			goto out;
    292
    293		err = mtdtest_relax();
    294		if (err)
    295			goto out;
    296	}
    297	stop_timing();
    298	speed = calc_speed();
    299	pr_info("page write speed is %ld KiB/s\n", speed);
    300
    301	/* Read all eraseblocks, 1 page at a time */
    302	pr_info("testing page read speed\n");
    303	start_timing();
    304	for (i = 0; i < ebcnt; ++i) {
    305		if (bbt[i])
    306			continue;
    307		err = read_eraseblock_by_page(i);
    308		if (err)
    309			goto out;
    310
    311		err = mtdtest_relax();
    312		if (err)
    313			goto out;
    314	}
    315	stop_timing();
    316	speed = calc_speed();
    317	pr_info("page read speed is %ld KiB/s\n", speed);
    318
    319	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    320	if (err)
    321		goto out;
    322
    323	/* Write all eraseblocks, 2 pages at a time */
    324	pr_info("testing 2 page write speed\n");
    325	start_timing();
    326	for (i = 0; i < ebcnt; ++i) {
    327		if (bbt[i])
    328			continue;
    329		err = write_eraseblock_by_2pages(i);
    330		if (err)
    331			goto out;
    332
    333		err = mtdtest_relax();
    334		if (err)
    335			goto out;
    336	}
    337	stop_timing();
    338	speed = calc_speed();
    339	pr_info("2 page write speed is %ld KiB/s\n", speed);
    340
    341	/* Read all eraseblocks, 2 pages at a time */
    342	pr_info("testing 2 page read speed\n");
    343	start_timing();
    344	for (i = 0; i < ebcnt; ++i) {
    345		if (bbt[i])
    346			continue;
    347		err = read_eraseblock_by_2pages(i);
    348		if (err)
    349			goto out;
    350
    351		err = mtdtest_relax();
    352		if (err)
    353			goto out;
    354	}
    355	stop_timing();
    356	speed = calc_speed();
    357	pr_info("2 page read speed is %ld KiB/s\n", speed);
    358
    359	/* Erase all eraseblocks */
    360	pr_info("Testing erase speed\n");
    361	start_timing();
    362	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    363	if (err)
    364		goto out;
    365	stop_timing();
    366	speed = calc_speed();
    367	pr_info("erase speed is %ld KiB/s\n", speed);
    368
    369	/* Multi-block erase all eraseblocks */
    370	for (k = 1; k < 7; k++) {
    371		blocks = 1 << k;
    372		pr_info("Testing %dx multi-block erase speed\n",
    373		       blocks);
    374		start_timing();
    375		for (i = 0; i < ebcnt; ) {
    376			for (j = 0; j < blocks && (i + j) < ebcnt; j++)
    377				if (bbt[i + j])
    378					break;
    379			if (j < 1) {
    380				i++;
    381				continue;
    382			}
    383			err = multiblock_erase(i, j);
    384			if (err)
    385				goto out;
    386
    387			err = mtdtest_relax();
    388			if (err)
    389				goto out;
    390
    391			i += j;
    392		}
    393		stop_timing();
    394		speed = calc_speed();
    395		pr_info("%dx multi-block erase speed is %ld KiB/s\n",
    396		       blocks, speed);
    397	}
    398	pr_info("finished\n");
    399out:
    400	kfree(iobuf);
    401	kfree(bbt);
    402	put_mtd_device(mtd);
    403	if (err)
    404		pr_info("error %d occurred\n", err);
    405	printk(KERN_INFO "=================================================\n");
    406	return err;
    407}
    408module_init(mtd_speedtest_init);
    409
    410static void __exit mtd_speedtest_exit(void)
    411{
    412	return;
    413}
    414module_exit(mtd_speedtest_exit);
    415
    416MODULE_DESCRIPTION("Speed test module");
    417MODULE_AUTHOR("Adrian Hunter");
    418MODULE_LICENSE("GPL");