brintos

brintos / linux-shallow public Read only

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