162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Test page read and write on MTD device. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/div64.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/moduleparam.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/sched.h> 2062306a36Sopenharmony_ci#include <linux/random.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "mtd_test.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic int dev = -EINVAL; 2562306a36Sopenharmony_cimodule_param(dev, int, S_IRUGO); 2662306a36Sopenharmony_ciMODULE_PARM_DESC(dev, "MTD device number to use"); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic struct mtd_info *mtd; 2962306a36Sopenharmony_cistatic unsigned char *twopages; 3062306a36Sopenharmony_cistatic unsigned char *writebuf; 3162306a36Sopenharmony_cistatic unsigned char *boundary; 3262306a36Sopenharmony_cistatic unsigned char *bbt; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int pgsize; 3562306a36Sopenharmony_cistatic int bufsize; 3662306a36Sopenharmony_cistatic int ebcnt; 3762306a36Sopenharmony_cistatic int pgcnt; 3862306a36Sopenharmony_cistatic int errcnt; 3962306a36Sopenharmony_cistatic struct rnd_state rnd_state; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int write_eraseblock(int ebnum) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); 4662306a36Sopenharmony_ci cond_resched(); 4762306a36Sopenharmony_ci return mtdtest_write(mtd, addr, mtd->erasesize, writebuf); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int verify_eraseblock(int ebnum) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci uint32_t j; 5362306a36Sopenharmony_ci int err = 0, i; 5462306a36Sopenharmony_ci loff_t addr0, addrn; 5562306a36Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci addr0 = 0; 5862306a36Sopenharmony_ci for (i = 0; i < ebcnt && bbt[i]; ++i) 5962306a36Sopenharmony_ci addr0 += mtd->erasesize; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci addrn = mtd->size; 6262306a36Sopenharmony_ci for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i) 6362306a36Sopenharmony_ci addrn -= mtd->erasesize; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); 6662306a36Sopenharmony_ci for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { 6762306a36Sopenharmony_ci /* Do a read to set the internal dataRAMs to different data */ 6862306a36Sopenharmony_ci err = mtdtest_read(mtd, addr0, bufsize, twopages); 6962306a36Sopenharmony_ci if (err) 7062306a36Sopenharmony_ci return err; 7162306a36Sopenharmony_ci err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages); 7262306a36Sopenharmony_ci if (err) 7362306a36Sopenharmony_ci return err; 7462306a36Sopenharmony_ci memset(twopages, 0, bufsize); 7562306a36Sopenharmony_ci err = mtdtest_read(mtd, addr, bufsize, twopages); 7662306a36Sopenharmony_ci if (err) 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { 7962306a36Sopenharmony_ci pr_err("error: verify failed at %#llx\n", 8062306a36Sopenharmony_ci (long long)addr); 8162306a36Sopenharmony_ci errcnt += 1; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci /* Check boundary between eraseblocks */ 8562306a36Sopenharmony_ci if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) { 8662306a36Sopenharmony_ci struct rnd_state old_state = rnd_state; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Do a read to set the internal dataRAMs to different data */ 8962306a36Sopenharmony_ci err = mtdtest_read(mtd, addr0, bufsize, twopages); 9062306a36Sopenharmony_ci if (err) 9162306a36Sopenharmony_ci return err; 9262306a36Sopenharmony_ci err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages); 9362306a36Sopenharmony_ci if (err) 9462306a36Sopenharmony_ci return err; 9562306a36Sopenharmony_ci memset(twopages, 0, bufsize); 9662306a36Sopenharmony_ci err = mtdtest_read(mtd, addr, bufsize, twopages); 9762306a36Sopenharmony_ci if (err) 9862306a36Sopenharmony_ci return err; 9962306a36Sopenharmony_ci memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); 10062306a36Sopenharmony_ci prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize); 10162306a36Sopenharmony_ci if (memcmp(twopages, boundary, bufsize)) { 10262306a36Sopenharmony_ci pr_err("error: verify failed at %#llx\n", 10362306a36Sopenharmony_ci (long long)addr); 10462306a36Sopenharmony_ci errcnt += 1; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci rnd_state = old_state; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci return err; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int crosstest(void) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int err = 0, i; 11462306a36Sopenharmony_ci loff_t addr, addr0, addrn; 11562306a36Sopenharmony_ci unsigned char *pp1, *pp2, *pp3, *pp4; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci pr_info("crosstest\n"); 11862306a36Sopenharmony_ci pp1 = kcalloc(pgsize, 4, GFP_KERNEL); 11962306a36Sopenharmony_ci if (!pp1) 12062306a36Sopenharmony_ci return -ENOMEM; 12162306a36Sopenharmony_ci pp2 = pp1 + pgsize; 12262306a36Sopenharmony_ci pp3 = pp2 + pgsize; 12362306a36Sopenharmony_ci pp4 = pp3 + pgsize; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci addr0 = 0; 12662306a36Sopenharmony_ci for (i = 0; i < ebcnt && bbt[i]; ++i) 12762306a36Sopenharmony_ci addr0 += mtd->erasesize; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci addrn = mtd->size; 13062306a36Sopenharmony_ci for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i) 13162306a36Sopenharmony_ci addrn -= mtd->erasesize; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Read 2nd-to-last page to pp1 */ 13462306a36Sopenharmony_ci addr = addrn - pgsize - pgsize; 13562306a36Sopenharmony_ci err = mtdtest_read(mtd, addr, pgsize, pp1); 13662306a36Sopenharmony_ci if (err) { 13762306a36Sopenharmony_ci kfree(pp1); 13862306a36Sopenharmony_ci return err; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Read 3rd-to-last page to pp1 */ 14262306a36Sopenharmony_ci addr = addrn - pgsize - pgsize - pgsize; 14362306a36Sopenharmony_ci err = mtdtest_read(mtd, addr, pgsize, pp1); 14462306a36Sopenharmony_ci if (err) { 14562306a36Sopenharmony_ci kfree(pp1); 14662306a36Sopenharmony_ci return err; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Read first page to pp2 */ 15062306a36Sopenharmony_ci addr = addr0; 15162306a36Sopenharmony_ci pr_info("reading page at %#llx\n", (long long)addr); 15262306a36Sopenharmony_ci err = mtdtest_read(mtd, addr, pgsize, pp2); 15362306a36Sopenharmony_ci if (err) { 15462306a36Sopenharmony_ci kfree(pp1); 15562306a36Sopenharmony_ci return err; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Read last page to pp3 */ 15962306a36Sopenharmony_ci addr = addrn - pgsize; 16062306a36Sopenharmony_ci pr_info("reading page at %#llx\n", (long long)addr); 16162306a36Sopenharmony_ci err = mtdtest_read(mtd, addr, pgsize, pp3); 16262306a36Sopenharmony_ci if (err) { 16362306a36Sopenharmony_ci kfree(pp1); 16462306a36Sopenharmony_ci return err; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Read first page again to pp4 */ 16862306a36Sopenharmony_ci addr = addr0; 16962306a36Sopenharmony_ci pr_info("reading page at %#llx\n", (long long)addr); 17062306a36Sopenharmony_ci err = mtdtest_read(mtd, addr, pgsize, pp4); 17162306a36Sopenharmony_ci if (err) { 17262306a36Sopenharmony_ci kfree(pp1); 17362306a36Sopenharmony_ci return err; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* pp2 and pp4 should be the same */ 17762306a36Sopenharmony_ci pr_info("verifying pages read at %#llx match\n", 17862306a36Sopenharmony_ci (long long)addr0); 17962306a36Sopenharmony_ci if (memcmp(pp2, pp4, pgsize)) { 18062306a36Sopenharmony_ci pr_err("verify failed!\n"); 18162306a36Sopenharmony_ci errcnt += 1; 18262306a36Sopenharmony_ci } else if (!err) 18362306a36Sopenharmony_ci pr_info("crosstest ok\n"); 18462306a36Sopenharmony_ci kfree(pp1); 18562306a36Sopenharmony_ci return err; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int erasecrosstest(void) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci int err = 0, i, ebnum, ebnum2; 19162306a36Sopenharmony_ci loff_t addr0; 19262306a36Sopenharmony_ci char *readbuf = twopages; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci pr_info("erasecrosstest\n"); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci ebnum = 0; 19762306a36Sopenharmony_ci addr0 = 0; 19862306a36Sopenharmony_ci for (i = 0; i < ebcnt && bbt[i]; ++i) { 19962306a36Sopenharmony_ci addr0 += mtd->erasesize; 20062306a36Sopenharmony_ci ebnum += 1; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci ebnum2 = ebcnt - 1; 20462306a36Sopenharmony_ci while (ebnum2 && bbt[ebnum2]) 20562306a36Sopenharmony_ci ebnum2 -= 1; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci pr_info("erasing block %d\n", ebnum); 20862306a36Sopenharmony_ci err = mtdtest_erase_eraseblock(mtd, ebnum); 20962306a36Sopenharmony_ci if (err) 21062306a36Sopenharmony_ci return err; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci pr_info("writing 1st page of block %d\n", ebnum); 21362306a36Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, pgsize); 21462306a36Sopenharmony_ci strcpy(writebuf, "There is no data like this!"); 21562306a36Sopenharmony_ci err = mtdtest_write(mtd, addr0, pgsize, writebuf); 21662306a36Sopenharmony_ci if (err) 21762306a36Sopenharmony_ci return err; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci pr_info("reading 1st page of block %d\n", ebnum); 22062306a36Sopenharmony_ci memset(readbuf, 0, pgsize); 22162306a36Sopenharmony_ci err = mtdtest_read(mtd, addr0, pgsize, readbuf); 22262306a36Sopenharmony_ci if (err) 22362306a36Sopenharmony_ci return err; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci pr_info("verifying 1st page of block %d\n", ebnum); 22662306a36Sopenharmony_ci if (memcmp(writebuf, readbuf, pgsize)) { 22762306a36Sopenharmony_ci pr_err("verify failed!\n"); 22862306a36Sopenharmony_ci errcnt += 1; 22962306a36Sopenharmony_ci return -1; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci pr_info("erasing block %d\n", ebnum); 23362306a36Sopenharmony_ci err = mtdtest_erase_eraseblock(mtd, ebnum); 23462306a36Sopenharmony_ci if (err) 23562306a36Sopenharmony_ci return err; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci pr_info("writing 1st page of block %d\n", ebnum); 23862306a36Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, pgsize); 23962306a36Sopenharmony_ci strcpy(writebuf, "There is no data like this!"); 24062306a36Sopenharmony_ci err = mtdtest_write(mtd, addr0, pgsize, writebuf); 24162306a36Sopenharmony_ci if (err) 24262306a36Sopenharmony_ci return err; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci pr_info("erasing block %d\n", ebnum2); 24562306a36Sopenharmony_ci err = mtdtest_erase_eraseblock(mtd, ebnum2); 24662306a36Sopenharmony_ci if (err) 24762306a36Sopenharmony_ci return err; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci pr_info("reading 1st page of block %d\n", ebnum); 25062306a36Sopenharmony_ci memset(readbuf, 0, pgsize); 25162306a36Sopenharmony_ci err = mtdtest_read(mtd, addr0, pgsize, readbuf); 25262306a36Sopenharmony_ci if (err) 25362306a36Sopenharmony_ci return err; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci pr_info("verifying 1st page of block %d\n", ebnum); 25662306a36Sopenharmony_ci if (memcmp(writebuf, readbuf, pgsize)) { 25762306a36Sopenharmony_ci pr_err("verify failed!\n"); 25862306a36Sopenharmony_ci errcnt += 1; 25962306a36Sopenharmony_ci return -1; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!err) 26362306a36Sopenharmony_ci pr_info("erasecrosstest ok\n"); 26462306a36Sopenharmony_ci return err; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int erasetest(void) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci int err = 0, i, ebnum, ok = 1; 27062306a36Sopenharmony_ci loff_t addr0; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci pr_info("erasetest\n"); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci ebnum = 0; 27562306a36Sopenharmony_ci addr0 = 0; 27662306a36Sopenharmony_ci for (i = 0; i < ebcnt && bbt[i]; ++i) { 27762306a36Sopenharmony_ci addr0 += mtd->erasesize; 27862306a36Sopenharmony_ci ebnum += 1; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci pr_info("erasing block %d\n", ebnum); 28262306a36Sopenharmony_ci err = mtdtest_erase_eraseblock(mtd, ebnum); 28362306a36Sopenharmony_ci if (err) 28462306a36Sopenharmony_ci return err; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci pr_info("writing 1st page of block %d\n", ebnum); 28762306a36Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, pgsize); 28862306a36Sopenharmony_ci err = mtdtest_write(mtd, addr0, pgsize, writebuf); 28962306a36Sopenharmony_ci if (err) 29062306a36Sopenharmony_ci return err; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci pr_info("erasing block %d\n", ebnum); 29362306a36Sopenharmony_ci err = mtdtest_erase_eraseblock(mtd, ebnum); 29462306a36Sopenharmony_ci if (err) 29562306a36Sopenharmony_ci return err; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci pr_info("reading 1st page of block %d\n", ebnum); 29862306a36Sopenharmony_ci err = mtdtest_read(mtd, addr0, pgsize, twopages); 29962306a36Sopenharmony_ci if (err) 30062306a36Sopenharmony_ci return err; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci pr_info("verifying 1st page of block %d is all 0xff\n", 30362306a36Sopenharmony_ci ebnum); 30462306a36Sopenharmony_ci for (i = 0; i < pgsize; ++i) 30562306a36Sopenharmony_ci if (twopages[i] != 0xff) { 30662306a36Sopenharmony_ci pr_err("verifying all 0xff failed at %d\n", 30762306a36Sopenharmony_ci i); 30862306a36Sopenharmony_ci errcnt += 1; 30962306a36Sopenharmony_ci ok = 0; 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (ok && !err) 31462306a36Sopenharmony_ci pr_info("erasetest ok\n"); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return err; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int __init mtd_pagetest_init(void) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci int err = 0; 32262306a36Sopenharmony_ci uint64_t tmp; 32362306a36Sopenharmony_ci uint32_t i; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci printk(KERN_INFO "\n"); 32662306a36Sopenharmony_ci printk(KERN_INFO "=================================================\n"); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (dev < 0) { 32962306a36Sopenharmony_ci pr_info("Please specify a valid mtd-device via module parameter\n"); 33062306a36Sopenharmony_ci pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci pr_info("MTD device: %d\n", dev); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci mtd = get_mtd_device(NULL, dev); 33762306a36Sopenharmony_ci if (IS_ERR(mtd)) { 33862306a36Sopenharmony_ci err = PTR_ERR(mtd); 33962306a36Sopenharmony_ci pr_err("error: cannot get MTD device\n"); 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!mtd_type_is_nand(mtd)) { 34462306a36Sopenharmony_ci pr_info("this test requires NAND flash\n"); 34562306a36Sopenharmony_ci goto out; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci tmp = mtd->size; 34962306a36Sopenharmony_ci do_div(tmp, mtd->erasesize); 35062306a36Sopenharmony_ci ebcnt = tmp; 35162306a36Sopenharmony_ci pgcnt = mtd->erasesize / mtd->writesize; 35262306a36Sopenharmony_ci pgsize = mtd->writesize; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci pr_info("MTD device size %llu, eraseblock size %u, " 35562306a36Sopenharmony_ci "page size %u, count of eraseblocks %u, pages per " 35662306a36Sopenharmony_ci "eraseblock %u, OOB size %u\n", 35762306a36Sopenharmony_ci (unsigned long long)mtd->size, mtd->erasesize, 35862306a36Sopenharmony_ci pgsize, ebcnt, pgcnt, mtd->oobsize); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci err = -ENOMEM; 36162306a36Sopenharmony_ci bufsize = pgsize * 2; 36262306a36Sopenharmony_ci writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); 36362306a36Sopenharmony_ci if (!writebuf) 36462306a36Sopenharmony_ci goto out; 36562306a36Sopenharmony_ci twopages = kmalloc(bufsize, GFP_KERNEL); 36662306a36Sopenharmony_ci if (!twopages) 36762306a36Sopenharmony_ci goto out; 36862306a36Sopenharmony_ci boundary = kmalloc(bufsize, GFP_KERNEL); 36962306a36Sopenharmony_ci if (!boundary) 37062306a36Sopenharmony_ci goto out; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci bbt = kzalloc(ebcnt, GFP_KERNEL); 37362306a36Sopenharmony_ci if (!bbt) 37462306a36Sopenharmony_ci goto out; 37562306a36Sopenharmony_ci err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 37662306a36Sopenharmony_ci if (err) 37762306a36Sopenharmony_ci goto out; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Erase all eraseblocks */ 38062306a36Sopenharmony_ci pr_info("erasing whole device\n"); 38162306a36Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 38262306a36Sopenharmony_ci if (err) 38362306a36Sopenharmony_ci goto out; 38462306a36Sopenharmony_ci pr_info("erased %u eraseblocks\n", ebcnt); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Write all eraseblocks */ 38762306a36Sopenharmony_ci prandom_seed_state(&rnd_state, 1); 38862306a36Sopenharmony_ci pr_info("writing whole device\n"); 38962306a36Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 39062306a36Sopenharmony_ci if (bbt[i]) 39162306a36Sopenharmony_ci continue; 39262306a36Sopenharmony_ci err = write_eraseblock(i); 39362306a36Sopenharmony_ci if (err) 39462306a36Sopenharmony_ci goto out; 39562306a36Sopenharmony_ci if (i % 256 == 0) 39662306a36Sopenharmony_ci pr_info("written up to eraseblock %u\n", i); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci err = mtdtest_relax(); 39962306a36Sopenharmony_ci if (err) 40062306a36Sopenharmony_ci goto out; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci pr_info("written %u eraseblocks\n", i); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* Check all eraseblocks */ 40562306a36Sopenharmony_ci prandom_seed_state(&rnd_state, 1); 40662306a36Sopenharmony_ci pr_info("verifying all eraseblocks\n"); 40762306a36Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 40862306a36Sopenharmony_ci if (bbt[i]) 40962306a36Sopenharmony_ci continue; 41062306a36Sopenharmony_ci err = verify_eraseblock(i); 41162306a36Sopenharmony_ci if (err) 41262306a36Sopenharmony_ci goto out; 41362306a36Sopenharmony_ci if (i % 256 == 0) 41462306a36Sopenharmony_ci pr_info("verified up to eraseblock %u\n", i); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci err = mtdtest_relax(); 41762306a36Sopenharmony_ci if (err) 41862306a36Sopenharmony_ci goto out; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci pr_info("verified %u eraseblocks\n", i); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci err = crosstest(); 42362306a36Sopenharmony_ci if (err) 42462306a36Sopenharmony_ci goto out; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (ebcnt > 1) { 42762306a36Sopenharmony_ci err = erasecrosstest(); 42862306a36Sopenharmony_ci if (err) 42962306a36Sopenharmony_ci goto out; 43062306a36Sopenharmony_ci } else { 43162306a36Sopenharmony_ci pr_info("skipping erasecrosstest, 2 erase blocks needed\n"); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci err = erasetest(); 43562306a36Sopenharmony_ci if (err) 43662306a36Sopenharmony_ci goto out; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci pr_info("finished with %d errors\n", errcnt); 43962306a36Sopenharmony_ciout: 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci kfree(bbt); 44262306a36Sopenharmony_ci kfree(boundary); 44362306a36Sopenharmony_ci kfree(twopages); 44462306a36Sopenharmony_ci kfree(writebuf); 44562306a36Sopenharmony_ci put_mtd_device(mtd); 44662306a36Sopenharmony_ci if (err) 44762306a36Sopenharmony_ci pr_info("error %d occurred\n", err); 44862306a36Sopenharmony_ci printk(KERN_INFO "=================================================\n"); 44962306a36Sopenharmony_ci return err; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_cimodule_init(mtd_pagetest_init); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic void __exit mtd_pagetest_exit(void) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci return; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_cimodule_exit(mtd_pagetest_exit); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciMODULE_DESCRIPTION("NAND page test"); 46062306a36Sopenharmony_ciMODULE_AUTHOR("Adrian Hunter"); 46162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 462