brintos

brintos / linux-shallow public Read only

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