static int __init mtd_stresstest_init(void)
{
	int err;
	int i, op;
	uint64_t tmp;

	printk(KERN_INFO "\n");
	printk(KERN_INFO "=================================================\n");
	printk(PRINT_PREF "MTD device: %d\n", dev);

	mtd = get_mtd_device(NULL, dev);
	if (IS_ERR(mtd)) {
		err = PTR_ERR(mtd);
		printk(PRINT_PREF "error: cannot get MTD device\n");
		return err;
	}

	if (mtd->writesize == 1) {
		printk(PRINT_PREF "not NAND flash, assume page size is 512 "
		       "bytes.\n");
		pgsize = 512;
	} else
		pgsize = mtd->writesize;

	tmp = mtd->size;
	do_div(tmp, mtd->erasesize);
	ebcnt = tmp;
	pgcnt = mtd->erasesize / mtd->writesize;

	printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
	       "page size %u, count of eraseblocks %u, pages per "
	       "eraseblock %u, OOB size %u\n",
	       (unsigned long long)mtd->size, mtd->erasesize,
	       pgsize, ebcnt, pgcnt, mtd->oobsize);

	/* Read or write up 2 eraseblocks at a time */
	bufsize = mtd->erasesize * 2;

	err = -ENOMEM;
	readbuf = vmalloc(bufsize);
	writebuf = vmalloc(bufsize);
	offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
	if (!readbuf || !writebuf || !offsets) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}
	for (i = 0; i < ebcnt; i++)
		offsets[i] = mtd->erasesize;
	simple_srand(current->pid);
	for (i = 0; i < bufsize; i++)
		writebuf[i] = simple_rand();

	err = scan_for_bad_eraseblocks();
	if (err)
		goto out;

	/* Do operations */
	printk(PRINT_PREF "doing operations\n");
	for (op = 0; op < count; op++) {
		if ((op & 1023) == 0)
			printk(PRINT_PREF "%d operations done\n", op);
		err = do_operation();
		if (err)
			goto out;
		cond_resched();
	}
	printk(PRINT_PREF "finished, %d operations done\n", op);

out:
	kfree(offsets);
	kfree(bbt);
	vfree(writebuf);
	vfree(readbuf);
	put_mtd_device(mtd);
	if (err)
		printk(PRINT_PREF "error %d occurred\n", err);
	printk(KERN_INFO "=================================================\n");
	return err;
}
static int __init mtd_speedtest_init(void)
{
	int err, i, blocks, j, k;
	long speed;
	uint64_t tmp;

	printk(KERN_INFO "\n");
	printk(KERN_INFO "=================================================\n");

	if (dev < 0) {
		printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
		printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
		return -EINVAL;
	}

	if (count)
		printk(PRINT_PREF "MTD device: %d    count: %d\n", dev, count);
	else
		printk(PRINT_PREF "MTD device: %d\n", dev);

	mtd = get_mtd_device(NULL, dev);
	if (IS_ERR(mtd)) {
		err = PTR_ERR(mtd);
		printk(PRINT_PREF "error: cannot get MTD device\n");
		return err;
	}

	if (mtd->writesize == 1) {
		printk(PRINT_PREF "not NAND flash, assume page size is 512 "
		       "bytes.\n");
		pgsize = 512;
	} else
		pgsize = mtd->writesize;

	tmp = mtd->size;
	do_div(tmp, mtd->erasesize);
	ebcnt = tmp;
	pgcnt = mtd->erasesize / pgsize;

	printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
	       "page size %u, count of eraseblocks %u, pages per "
	       "eraseblock %u, OOB size %u\n",
	       (unsigned long long)mtd->size, mtd->erasesize,
	       pgsize, ebcnt, pgcnt, mtd->oobsize);

	if (count > 0 && count < ebcnt)
		ebcnt = count;

	err = -ENOMEM;
	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
	if (!iobuf) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}

	simple_srand(1);
	set_random_data(iobuf, mtd->erasesize);

	err = scan_for_bad_eraseblocks();
	if (err)
		goto out;

	err = erase_whole_device();
	if (err)
		goto out;

	/* Write all eraseblocks, 1 eraseblock at a time */
	printk(PRINT_PREF "testing eraseblock write speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed);

	/* Read all eraseblocks, 1 eraseblock at a time */
	printk(PRINT_PREF "testing eraseblock read speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = read_eraseblock(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed);

	err = erase_whole_device();
	if (err)
		goto out;

	/* Write all eraseblocks, 1 page at a time */
	printk(PRINT_PREF "testing page write speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock_by_page(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed);

	/* Read all eraseblocks, 1 page at a time */
	printk(PRINT_PREF "testing page read speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = read_eraseblock_by_page(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed);

	err = erase_whole_device();
	if (err)
		goto out;

	/* Write all eraseblocks, 2 pages at a time */
	printk(PRINT_PREF "testing 2 page write speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock_by_2pages(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed);

	/* Read all eraseblocks, 2 pages at a time */
	printk(PRINT_PREF "testing 2 page read speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = read_eraseblock_by_2pages(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed);

	/* Erase all eraseblocks */
	printk(PRINT_PREF "Testing erase speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = erase_eraseblock(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);

	/* Multi-block erase all eraseblocks */
	for (k = 1; k < 7; k++) {
		blocks = 1 << k;
		printk(PRINT_PREF "Testing %dx multi-block erase speed\n",
		       blocks);
		start_timing();
		for (i = 0; i < ebcnt; ) {
			for (j = 0; j < blocks && (i + j) < ebcnt; j++)
				if (bbt[i + j])
					break;
			if (j < 1) {
				i++;
				continue;
			}
			err = multiblock_erase(i, j);
			if (err)
				goto out;
			cond_resched();
			i += j;
		}
		stop_timing();
		speed = calc_speed();
		printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n",
		       blocks, speed);
	}
	printk(PRINT_PREF "finished\n");
out:
	kfree(iobuf);
	kfree(bbt);
	put_mtd_device(mtd);
	if (err)
		printk(PRINT_PREF "error %d occurred\n", err);
	printk(KERN_INFO "=================================================\n");
	return err;
}
Exemple #3
0
static int __init mtd_oobtest_init(void)
{
	int err = 0;
	unsigned int i;
	uint64_t tmp;
	struct mtd_oob_ops ops;
	loff_t addr = 0, addr0;

	printk(KERN_INFO "\n");
	printk(KERN_INFO "=================================================\n");
	printk(PRINT_PREF "MTD device: %d\n", dev);

	mtd = get_mtd_device(NULL, dev);
	if (IS_ERR(mtd)) {
		err = PTR_ERR(mtd);
		printk(PRINT_PREF "error: cannot get MTD device\n");
		return err;
	}

	if (mtd->type != MTD_NANDFLASH) {
		printk(PRINT_PREF "this test requires NAND flash\n");
		goto out;
	}

	tmp = mtd->size;
	do_div(tmp, mtd->erasesize);
	ebcnt = tmp;
	pgcnt = mtd->erasesize / mtd->writesize;

	printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
	       "page size %u, count of eraseblocks %u, pages per "
	       "eraseblock %u, OOB size %u\n",
	       (unsigned long long)mtd->size, mtd->erasesize,
	       mtd->writesize, ebcnt, pgcnt, mtd->oobsize);

	err = -ENOMEM;
	mtd->erasesize = mtd->erasesize;
	readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
	if (!readbuf) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}
	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
	if (!writebuf) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}

	err = scan_for_bad_eraseblocks();
	if (err)
		goto out;

	use_offset = 0;
	use_len = mtd->ecclayout->oobavail;
	use_len_max = mtd->ecclayout->oobavail;
	vary_offset = 0;

	
	printk(PRINT_PREF "test 1 of 5\n");

	err = erase_whole_device();
	if (err)
		goto out;

	simple_srand(1);
	err = write_whole_device();
	if (err)
		goto out;

	simple_srand(1);
	err = verify_all_eraseblocks();
	if (err)
		goto out;

	
	printk(PRINT_PREF "test 2 of 5\n");

	err = erase_whole_device();
	if (err)
		goto out;

	simple_srand(3);
	err = write_whole_device();
	if (err)
		goto out;

	
	simple_srand(3);
	printk(PRINT_PREF "verifying all eraseblocks\n");
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = verify_eraseblock_in_one_go(i);
		if (err)
			goto out;
		if (i % 256 == 0)
			printk(PRINT_PREF "verified up to eraseblock %u\n", i);
		cond_resched();
	}
	printk(PRINT_PREF "verified %u eraseblocks\n", i);

	
	printk(PRINT_PREF "test 3 of 5\n");

	err = erase_whole_device();
	if (err)
		goto out;

	
	use_offset = 0;
	use_len = mtd->ecclayout->oobavail;
	use_len_max = mtd->ecclayout->oobavail;
	vary_offset = 1;
	simple_srand(5);
	printk(PRINT_PREF "writing OOBs of whole device\n");
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock(i);
		if (err)
			goto out;
		if (i % 256 == 0)
			printk(PRINT_PREF "written up to eraseblock %u\n", i);
		cond_resched();
	}
	printk(PRINT_PREF "written %u eraseblocks\n", i);

	
	use_offset = 0;
	use_len = mtd->ecclayout->oobavail;
	use_len_max = mtd->ecclayout->oobavail;
	vary_offset = 1;
	simple_srand(5);
	err = verify_all_eraseblocks();
	if (err)
		goto out;

	use_offset = 0;
	use_len = mtd->ecclayout->oobavail;
	use_len_max = mtd->ecclayout->oobavail;
	vary_offset = 0;

	
	printk(PRINT_PREF "test 4 of 5\n");

	err = erase_whole_device();
	if (err)
		goto out;

	addr0 = 0;
	for (i = 0; i < ebcnt && bbt[i]; ++i)
		addr0 += mtd->erasesize;

	
	ops.mode      = MTD_OOB_AUTO;
	ops.len       = 0;
	ops.retlen    = 0;
	ops.ooblen    = 1;
	ops.oobretlen = 0;
	ops.ooboffs   = mtd->ecclayout->oobavail;
	ops.datbuf    = NULL;
	ops.oobbuf    = writebuf;
	printk(PRINT_PREF "attempting to start write past end of OOB\n");
	printk(PRINT_PREF "an error is expected...\n");
	err = mtd->write_oob(mtd, addr0, &ops);
	if (err) {
		printk(PRINT_PREF "error occurred as expected\n");
		err = 0;
	} else {
		printk(PRINT_PREF "error: can write past end of OOB\n");
		errcnt += 1;
	}

	
	ops.mode      = MTD_OOB_AUTO;
	ops.len       = 0;
	ops.retlen    = 0;
	ops.ooblen    = 1;
	ops.oobretlen = 0;
	ops.ooboffs   = mtd->ecclayout->oobavail;
	ops.datbuf    = NULL;
	ops.oobbuf    = readbuf;
	printk(PRINT_PREF "attempting to start read past end of OOB\n");
	printk(PRINT_PREF "an error is expected...\n");
	err = mtd->read_oob(mtd, addr0, &ops);
	if (err) {
		printk(PRINT_PREF "error occurred as expected\n");
		err = 0;
	} else {
		printk(PRINT_PREF "error: can read past end of OOB\n");
		errcnt += 1;
	}

	if (bbt[ebcnt - 1])
		printk(PRINT_PREF "skipping end of device tests because last "
		       "block is bad\n");
	else {
		
		ops.mode      = MTD_OOB_AUTO;
		ops.len       = 0;
		ops.retlen    = 0;
		ops.ooblen    = mtd->ecclayout->oobavail + 1;
		ops.oobretlen = 0;
		ops.ooboffs   = 0;
		ops.datbuf    = NULL;
		ops.oobbuf    = writebuf;
		printk(PRINT_PREF "attempting to write past end of device\n");
		printk(PRINT_PREF "an error is expected...\n");
		err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
		if (err) {
			printk(PRINT_PREF "error occurred as expected\n");
			err = 0;
		} else {
			printk(PRINT_PREF "error: wrote past end of device\n");
			errcnt += 1;
		}

		
		ops.mode      = MTD_OOB_AUTO;
		ops.len       = 0;
		ops.retlen    = 0;
		ops.ooblen    = mtd->ecclayout->oobavail + 1;
		ops.oobretlen = 0;
		ops.ooboffs   = 0;
		ops.datbuf    = NULL;
		ops.oobbuf    = readbuf;
		printk(PRINT_PREF "attempting to read past end of device\n");
		printk(PRINT_PREF "an error is expected...\n");
		err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
		if (err) {
			printk(PRINT_PREF "error occurred as expected\n");
			err = 0;
		} else {
			printk(PRINT_PREF "error: read past end of device\n");
			errcnt += 1;
		}

		err = erase_eraseblock(ebcnt - 1);
		if (err)
			goto out;

		
		ops.mode      = MTD_OOB_AUTO;
		ops.len       = 0;
		ops.retlen    = 0;
		ops.ooblen    = mtd->ecclayout->oobavail;
		ops.oobretlen = 0;
		ops.ooboffs   = 1;
		ops.datbuf    = NULL;
		ops.oobbuf    = writebuf;
		printk(PRINT_PREF "attempting to write past end of device\n");
		printk(PRINT_PREF "an error is expected...\n");
		err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
		if (err) {
			printk(PRINT_PREF "error occurred as expected\n");
			err = 0;
		} else {
			printk(PRINT_PREF "error: wrote past end of device\n");
			errcnt += 1;
		}

		
		ops.mode      = MTD_OOB_AUTO;
		ops.len       = 0;
		ops.retlen    = 0;
		ops.ooblen    = mtd->ecclayout->oobavail;
		ops.oobretlen = 0;
		ops.ooboffs   = 1;
		ops.datbuf    = NULL;
		ops.oobbuf    = readbuf;
		printk(PRINT_PREF "attempting to read past end of device\n");
		printk(PRINT_PREF "an error is expected...\n");
		err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
		if (err) {
			printk(PRINT_PREF "error occurred as expected\n");
			err = 0;
		} else {
			printk(PRINT_PREF "error: read past end of device\n");
			errcnt += 1;
		}
	}

	
	printk(PRINT_PREF "test 5 of 5\n");

	
	err = erase_whole_device();
	if (err)
		goto out;

	
	simple_srand(11);
	printk(PRINT_PREF "writing OOBs of whole device\n");
	for (i = 0; i < ebcnt - 1; ++i) {
		int cnt = 2;
		int pg;
		size_t sz = mtd->ecclayout->oobavail;
		if (bbt[i] || bbt[i + 1])
			continue;
		addr = (i + 1) * mtd->erasesize - mtd->writesize;
		for (pg = 0; pg < cnt; ++pg) {
			set_random_data(writebuf, sz);
			ops.mode      = MTD_OOB_AUTO;
			ops.len       = 0;
			ops.retlen    = 0;
			ops.ooblen    = sz;
			ops.oobretlen = 0;
			ops.ooboffs   = 0;
			ops.datbuf    = NULL;
			ops.oobbuf    = writebuf;
			err = mtd->write_oob(mtd, addr, &ops);
			if (err)
				goto out;
			if (i % 256 == 0)
				printk(PRINT_PREF "written up to eraseblock "
				       "%u\n", i);
			cond_resched();
			addr += mtd->writesize;
		}
	}
	printk(PRINT_PREF "written %u eraseblocks\n", i);

	
	simple_srand(11);
	printk(PRINT_PREF "verifying all eraseblocks\n");
	for (i = 0; i < ebcnt - 1; ++i) {
		if (bbt[i] || bbt[i + 1])
			continue;
		set_random_data(writebuf, mtd->ecclayout->oobavail * 2);
		addr = (i + 1) * mtd->erasesize - mtd->writesize;
		ops.mode      = MTD_OOB_AUTO;
		ops.len       = 0;
		ops.retlen    = 0;
		ops.ooblen    = mtd->ecclayout->oobavail * 2;
		ops.oobretlen = 0;
		ops.ooboffs   = 0;
		ops.datbuf    = NULL;
		ops.oobbuf    = readbuf;
		err = mtd->read_oob(mtd, addr, &ops);
		if (err)
			goto out;
		if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
			printk(PRINT_PREF "error: verify failed at %#llx\n",
			       (long long)addr);
			errcnt += 1;
			if (errcnt > 1000) {
				printk(PRINT_PREF "error: too many errors\n");
				goto out;
			}
		}
		if (i % 256 == 0)
			printk(PRINT_PREF "verified up to eraseblock %u\n", i);
		cond_resched();
	}
	printk(PRINT_PREF "verified %u eraseblocks\n", i);

	printk(PRINT_PREF "finished with %d errors\n", errcnt);
out:
	kfree(bbt);
	kfree(writebuf);
	kfree(readbuf);
	put_mtd_device(mtd);
	if (err)
		printk(PRINT_PREF "error %d occurred\n", err);
	printk(KERN_INFO "=================================================\n");
	return err;
}
Exemple #4
0
static int __init mtd_subpagetest_init(void)
{
	int err = 0;
	uint32_t i;
	uint64_t tmp;

	printk(KERN_INFO "\n");
	printk(KERN_INFO "=================================================\n");
	printk(PRINT_PREF "MTD device: %d\n", dev);

	mtd = get_mtd_device(NULL, dev);
	if (IS_ERR(mtd)) {
		err = PTR_ERR(mtd);
		printk(PRINT_PREF "error: cannot get MTD device\n");
		return err;
	}

	if (mtd->type != MTD_NANDFLASH) {
		printk(PRINT_PREF "this test requires NAND flash\n");
		goto out;
	}

	subpgsize = mtd->writesize >> mtd->subpage_sft;
	tmp = mtd->size;
	do_div(tmp, mtd->erasesize);
	ebcnt = tmp;
	pgcnt = mtd->erasesize / mtd->writesize;

	printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
	       "page size %u, subpage size %u, count of eraseblocks %u, "
	       "pages per eraseblock %u, OOB size %u\n",
	       (unsigned long long)mtd->size, mtd->erasesize,
	       mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);

	err = -ENOMEM;
	bufsize = subpgsize * 32;
	writebuf = kmalloc(bufsize, GFP_KERNEL);
	if (!writebuf) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}
	readbuf = kmalloc(bufsize, GFP_KERNEL);
	if (!readbuf) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}

	err = scan_for_bad_eraseblocks();
	if (err)
		goto out;

	err = erase_whole_device();
	if (err)
		goto out;

	printk(PRINT_PREF "writing whole device\n");
	simple_srand(1);
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock(i);
		if (unlikely(err))
			goto out;
		if (i % 256 == 0)
			printk(PRINT_PREF "written up to eraseblock %u\n", i);
		cond_resched();
	}
	printk(PRINT_PREF "written %u eraseblocks\n", i);

	simple_srand(1);
	printk(PRINT_PREF "verifying all eraseblocks\n");
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = verify_eraseblock(i);
		if (unlikely(err))
			goto out;
		if (i % 256 == 0)
			printk(PRINT_PREF "verified up to eraseblock %u\n", i);
		cond_resched();
	}
	printk(PRINT_PREF "verified %u eraseblocks\n", i);

	err = erase_whole_device();
	if (err)
		goto out;

	err = verify_all_eraseblocks_ff();
	if (err)
		goto out;

	/* Write all eraseblocks */
	simple_srand(3);
	printk(PRINT_PREF "writing whole device\n");
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock2(i);
		if (unlikely(err))
			goto out;
		if (i % 256 == 0)
			printk(PRINT_PREF "written up to eraseblock %u\n", i);
		cond_resched();
	}
	printk(PRINT_PREF "written %u eraseblocks\n", i);

	/* Check all eraseblocks */
	simple_srand(3);
	printk(PRINT_PREF "verifying all eraseblocks\n");
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = verify_eraseblock2(i);
		if (unlikely(err))
			goto out;
		if (i % 256 == 0)
			printk(PRINT_PREF "verified up to eraseblock %u\n", i);
		cond_resched();
	}
	printk(PRINT_PREF "verified %u eraseblocks\n", i);

	err = erase_whole_device();
	if (err)
		goto out;

	err = verify_all_eraseblocks_ff();
	if (err)
		goto out;

	printk(PRINT_PREF "finished with %d errors\n", errcnt);

out:
	kfree(bbt);
	kfree(readbuf);
	kfree(writebuf);
	put_mtd_device(mtd);
	if (err)
		printk(PRINT_PREF "error %d occurred\n", err);
	printk(KERN_INFO "=================================================\n");
	return err;
}
static int __init mtd_pagetest_init(void)
{
	int err = 0;
	uint64_t tmp;
	uint32_t i;

#ifdef CONFIG_DEBUG_PRINTK
	printk(KERN_INFO "\n");
#else
	;
#endif
#ifdef CONFIG_DEBUG_PRINTK
	printk(KERN_INFO "=================================================\n");
#else
	;
#endif
#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "MTD device: %d\n", dev);
#else
	;
#endif

	mtd = get_mtd_device(NULL, dev);
	if (IS_ERR(mtd)) {
		err = PTR_ERR(mtd);
#ifdef CONFIG_DEBUG_PRINTK
		printk(PRINT_PREF "error: cannot get MTD device\n");
#else
		;
#endif
		return err;
	}

	if (mtd->type != MTD_NANDFLASH) {
#ifdef CONFIG_DEBUG_PRINTK
		printk(PRINT_PREF "this test requires NAND flash\n");
#else
		;
#endif
		goto out;
	}

	tmp = mtd->size;
	do_div(tmp, mtd->erasesize);
	ebcnt = tmp;
	pgcnt = mtd->erasesize / mtd->writesize;
	pgsize = mtd->writesize;

#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
	       "page size %u, count of eraseblocks %u, pages per "
	       "eraseblock %u, OOB size %u\n",
	       (unsigned long long)mtd->size, mtd->erasesize,
	       pgsize, ebcnt, pgcnt, mtd->oobsize);
#else
	;
#endif

	err = -ENOMEM;
	bufsize = pgsize * 2;
	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
	if (!writebuf) {
#ifdef CONFIG_DEBUG_PRINTK
		printk(PRINT_PREF "error: cannot allocate memory\n");
#else
		;
#endif
		goto out;
	}
	twopages = kmalloc(bufsize, GFP_KERNEL);
	if (!twopages) {
#ifdef CONFIG_DEBUG_PRINTK
		printk(PRINT_PREF "error: cannot allocate memory\n");
#else
		;
#endif
		goto out;
	}
	boundary = kmalloc(bufsize, GFP_KERNEL);
	if (!boundary) {
#ifdef CONFIG_DEBUG_PRINTK
		printk(PRINT_PREF "error: cannot allocate memory\n");
#else
		;
#endif
		goto out;
	}

	err = scan_for_bad_eraseblocks();
	if (err)
		goto out;

	/* Erase all eraseblocks */
#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "erasing whole device\n");
#else
	;
#endif
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = erase_eraseblock(i);
		if (err)
			goto out;
		cond_resched();
	}
#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "erased %u eraseblocks\n", i);
#else
	;
#endif

	/* Write all eraseblocks */
	simple_srand(1);
#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "writing whole device\n");
#else
	;
#endif
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock(i);
		if (err)
			goto out;
		if (i % 256 == 0)
#ifdef CONFIG_DEBUG_PRINTK
			printk(PRINT_PREF "written up to eraseblock %u\n", i);
#else
			;
#endif
		cond_resched();
	}
#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "written %u eraseblocks\n", i);
#else
	;
#endif

	/* Check all eraseblocks */
	simple_srand(1);
#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "verifying all eraseblocks\n");
#else
	;
#endif
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = verify_eraseblock(i);
		if (err)
			goto out;
		if (i % 256 == 0)
#ifdef CONFIG_DEBUG_PRINTK
			printk(PRINT_PREF "verified up to eraseblock %u\n", i);
#else
			;
#endif
		cond_resched();
	}
#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "verified %u eraseblocks\n", i);
#else
	;
#endif

	err = crosstest();
	if (err)
		goto out;

	err = erasecrosstest();
	if (err)
		goto out;

	err = erasetest();
	if (err)
		goto out;

#ifdef CONFIG_DEBUG_PRINTK
	printk(PRINT_PREF "finished with %d errors\n", errcnt);
#else
	;
#endif
out:

	kfree(bbt);
	kfree(boundary);
	kfree(twopages);
	kfree(writebuf);
	put_mtd_device(mtd);
	if (err)
#ifdef CONFIG_DEBUG_PRINTK
		printk(PRINT_PREF "error %d occurred\n", err);
#else
		;
#endif
#ifdef CONFIG_DEBUG_PRINTK
	printk(KERN_INFO "=================================================\n");
#else
	;
#endif
	return err;
}
static int __init fsspeed_init(void)
{
	int err, i;
	long speed;
	struct file *fp;
	mm_segment_t fs;

	printk(KERN_INFO "\n");
	printk(KERN_INFO "=================================================\n");
	printk(PRINT_PREF "rw %d PAGES using file: %s\n", count, fname);

	err = -ENOMEM;
	iobuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
	if (!iobuf) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}

	simple_srand(1);
	set_random_data(iobuf, PAGE_SIZE);

	fp = filp_open(fname, O_RDWR|O_CREAT, 0600);
	if (IS_ERR(fp)) {
		printk("open file %s failed.\n", fname);
		err = PTR_ERR(fp);
		goto out;
	}

	/* Write all eraseblocks, 1 eraseblock at a time */
	printk(PRINT_PREF "testing file system write speed\n");
	fs = get_fs();
	set_fs(KERNEL_DS);
	start_timing();
	for (i = 0; i < count; ++i) {
		err = vfs_write(fp, iobuf, PAGE_SIZE, &fp->f_pos);
		if (err < 0)
			goto out2;
//		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "write speed is %ld KiB/s\n", speed);
	
	vfs_fsync(fp, fp->f_path.dentry, 0);
	invalidate_mapping_pages(fp->f_dentry->d_inode->i_mapping, 0, -1);
	vfs_llseek(fp, 0, SEEK_SET);
	
	/* Read all eraseblocks, 1 eraseblock at a time */
	printk(PRINT_PREF "testing file system read speed\n");
	start_timing();
	for (i = 0; i < count; ++i) {
		err = vfs_read(fp, iobuf, PAGE_SIZE, &fp->f_pos);
		if (err < 0)
			goto out2;
//		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "read speed is %ld KiB/s\n", speed);

	printk(PRINT_PREF "finished\n");
	err = 0;
out2:
	filp_close(fp, NULL);
	set_fs(fs);
out:
	kfree(iobuf);
	if (err)
		printk(PRINT_PREF "error %d occurred\n", err);
	printk(KERN_INFO "=================================================\n");
	return err;
}
static int __init mtd_speedtest_init(void)
{
	int err, i;
	long speed;
	uint64_t tmp;

	printk(KERN_INFO "\n");
	printk(KERN_INFO "=================================================\n");
	printk(PRINT_PREF "MTD device: %d\n", dev);

	mtd = get_mtd_device(NULL, dev);
	if (IS_ERR(mtd)) {
		err = PTR_ERR(mtd);
		printk(PRINT_PREF "error: cannot get MTD device\n");
		return err;
	}

	if (mtd->writesize == 1) {
		printk(PRINT_PREF "not NAND flash, assume page size is 512 "
		       "bytes.\n");
		pgsize = 512;
	} else
		pgsize = mtd->writesize;

	tmp = mtd->size;
	do_div(tmp, mtd->erasesize);
	ebcnt = tmp;
	pgcnt = mtd->erasesize / pgsize;

	printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
	       "page size %u, count of eraseblocks %u, pages per "
	       "eraseblock %u, OOB size %u\n",
	       (unsigned long long)mtd->size, mtd->erasesize,
	       pgsize, ebcnt, pgcnt, mtd->oobsize);

	err = -ENOMEM;
	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
	if (!iobuf) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		goto out;
	}

	simple_srand(1);
	set_random_data(iobuf, mtd->erasesize);

	err = scan_for_bad_eraseblocks();
	if (err)
		goto out;

	err = erase_whole_device();
	if (err)
		goto out;

	/* Write all eraseblocks, 1 eraseblock at a time */
	printk(PRINT_PREF "testing eraseblock write speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed);

	/* Read all eraseblocks, 1 eraseblock at a time */
	printk(PRINT_PREF "testing eraseblock read speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = read_eraseblock(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed);

	err = erase_whole_device();
	if (err)
		goto out;

	/* Write all eraseblocks, 1 page at a time */
	printk(PRINT_PREF "testing page write speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock_by_page(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed);

	/* Read all eraseblocks, 1 page at a time */
	printk(PRINT_PREF "testing page read speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = read_eraseblock_by_page(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed);

	err = erase_whole_device();
	if (err)
		goto out;

	/* Write all eraseblocks, 2 pages at a time */
	printk(PRINT_PREF "testing 2 page write speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = write_eraseblock_by_2pages(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed);

	/* Read all eraseblocks, 2 pages at a time */
	printk(PRINT_PREF "testing 2 page read speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = read_eraseblock_by_2pages(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed);

	/* Erase all eraseblocks */
	printk(PRINT_PREF "Testing erase speed\n");
	start_timing();
	for (i = 0; i < ebcnt; ++i) {
		if (bbt[i])
			continue;
		err = erase_eraseblock(i);
		if (err)
			goto out;
		cond_resched();
	}
	stop_timing();
	speed = calc_speed();
	printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);

	printk(PRINT_PREF "finished\n");
out:
	kfree(iobuf);
	kfree(bbt);
	put_mtd_device(mtd);
	if (err)
		printk(PRINT_PREF "error %d occurred\n", err);
	printk(KERN_INFO "=================================================\n");
	return err;
}