18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007 Nokia Corporation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Test sub-page read and write on MTD device. 68c2ecf20Sopenharmony_ci * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/sched.h> 188c2ecf20Sopenharmony_ci#include <linux/random.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "mtd_test.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int dev = -EINVAL; 238c2ecf20Sopenharmony_cimodule_param(dev, int, S_IRUGO); 248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dev, "MTD device number to use"); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic struct mtd_info *mtd; 278c2ecf20Sopenharmony_cistatic unsigned char *writebuf; 288c2ecf20Sopenharmony_cistatic unsigned char *readbuf; 298c2ecf20Sopenharmony_cistatic unsigned char *bbt; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int subpgsize; 328c2ecf20Sopenharmony_cistatic int bufsize; 338c2ecf20Sopenharmony_cistatic int ebcnt; 348c2ecf20Sopenharmony_cistatic int pgcnt; 358c2ecf20Sopenharmony_cistatic int errcnt; 368c2ecf20Sopenharmony_cistatic struct rnd_state rnd_state; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline void clear_data(unsigned char *buf, size_t len) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci memset(buf, 0, len); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int write_eraseblock(int ebnum) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci size_t written; 468c2ecf20Sopenharmony_ci int err = 0; 478c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, subpgsize); 508c2ecf20Sopenharmony_ci err = mtd_write(mtd, addr, subpgsize, &written, writebuf); 518c2ecf20Sopenharmony_ci if (unlikely(err || written != subpgsize)) { 528c2ecf20Sopenharmony_ci pr_err("error: write failed at %#llx\n", 538c2ecf20Sopenharmony_ci (long long)addr); 548c2ecf20Sopenharmony_ci if (written != subpgsize) { 558c2ecf20Sopenharmony_ci pr_err(" write size: %#x\n", subpgsize); 568c2ecf20Sopenharmony_ci pr_err(" written: %#zx\n", written); 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci return err ? err : -1; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci addr += subpgsize; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, subpgsize); 648c2ecf20Sopenharmony_ci err = mtd_write(mtd, addr, subpgsize, &written, writebuf); 658c2ecf20Sopenharmony_ci if (unlikely(err || written != subpgsize)) { 668c2ecf20Sopenharmony_ci pr_err("error: write failed at %#llx\n", 678c2ecf20Sopenharmony_ci (long long)addr); 688c2ecf20Sopenharmony_ci if (written != subpgsize) { 698c2ecf20Sopenharmony_ci pr_err(" write size: %#x\n", subpgsize); 708c2ecf20Sopenharmony_ci pr_err(" written: %#zx\n", written); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci return err ? err : -1; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return err; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int write_eraseblock2(int ebnum) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci size_t written; 818c2ecf20Sopenharmony_ci int err = 0, k; 828c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci for (k = 1; k < 33; ++k) { 858c2ecf20Sopenharmony_ci if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); 888c2ecf20Sopenharmony_ci err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); 898c2ecf20Sopenharmony_ci if (unlikely(err || written != subpgsize * k)) { 908c2ecf20Sopenharmony_ci pr_err("error: write failed at %#llx\n", 918c2ecf20Sopenharmony_ci (long long)addr); 928c2ecf20Sopenharmony_ci if (written != subpgsize * k) { 938c2ecf20Sopenharmony_ci pr_err(" write size: %#x\n", 948c2ecf20Sopenharmony_ci subpgsize * k); 958c2ecf20Sopenharmony_ci pr_err(" written: %#08zx\n", 968c2ecf20Sopenharmony_ci written); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci return err ? err : -1; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci addr += subpgsize * k; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return err; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void print_subpage(unsigned char *p) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int i, j; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci for (i = 0; i < subpgsize; ) { 1118c2ecf20Sopenharmony_ci for (j = 0; i < subpgsize && j < 32; ++i, ++j) 1128c2ecf20Sopenharmony_ci printk("%02x", *p++); 1138c2ecf20Sopenharmony_ci printk("\n"); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int verify_eraseblock(int ebnum) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci size_t read; 1208c2ecf20Sopenharmony_ci int err = 0; 1218c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, subpgsize); 1248c2ecf20Sopenharmony_ci clear_data(readbuf, subpgsize); 1258c2ecf20Sopenharmony_ci err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 1268c2ecf20Sopenharmony_ci if (unlikely(err || read != subpgsize)) { 1278c2ecf20Sopenharmony_ci if (mtd_is_bitflip(err) && read == subpgsize) { 1288c2ecf20Sopenharmony_ci pr_info("ECC correction at %#llx\n", 1298c2ecf20Sopenharmony_ci (long long)addr); 1308c2ecf20Sopenharmony_ci err = 0; 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci pr_err("error: read failed at %#llx\n", 1338c2ecf20Sopenharmony_ci (long long)addr); 1348c2ecf20Sopenharmony_ci return err ? err : -1; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 1388c2ecf20Sopenharmony_ci pr_err("error: verify failed at %#llx\n", 1398c2ecf20Sopenharmony_ci (long long)addr); 1408c2ecf20Sopenharmony_ci pr_info("------------- written----------------\n"); 1418c2ecf20Sopenharmony_ci print_subpage(writebuf); 1428c2ecf20Sopenharmony_ci pr_info("------------- read ------------------\n"); 1438c2ecf20Sopenharmony_ci print_subpage(readbuf); 1448c2ecf20Sopenharmony_ci pr_info("-------------------------------------\n"); 1458c2ecf20Sopenharmony_ci errcnt += 1; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci addr += subpgsize; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, subpgsize); 1518c2ecf20Sopenharmony_ci clear_data(readbuf, subpgsize); 1528c2ecf20Sopenharmony_ci err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 1538c2ecf20Sopenharmony_ci if (unlikely(err || read != subpgsize)) { 1548c2ecf20Sopenharmony_ci if (mtd_is_bitflip(err) && read == subpgsize) { 1558c2ecf20Sopenharmony_ci pr_info("ECC correction at %#llx\n", 1568c2ecf20Sopenharmony_ci (long long)addr); 1578c2ecf20Sopenharmony_ci err = 0; 1588c2ecf20Sopenharmony_ci } else { 1598c2ecf20Sopenharmony_ci pr_err("error: read failed at %#llx\n", 1608c2ecf20Sopenharmony_ci (long long)addr); 1618c2ecf20Sopenharmony_ci return err ? err : -1; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 1658c2ecf20Sopenharmony_ci pr_info("error: verify failed at %#llx\n", 1668c2ecf20Sopenharmony_ci (long long)addr); 1678c2ecf20Sopenharmony_ci pr_info("------------- written----------------\n"); 1688c2ecf20Sopenharmony_ci print_subpage(writebuf); 1698c2ecf20Sopenharmony_ci pr_info("------------- read ------------------\n"); 1708c2ecf20Sopenharmony_ci print_subpage(readbuf); 1718c2ecf20Sopenharmony_ci pr_info("-------------------------------------\n"); 1728c2ecf20Sopenharmony_ci errcnt += 1; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return err; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int verify_eraseblock2(int ebnum) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci size_t read; 1818c2ecf20Sopenharmony_ci int err = 0, k; 1828c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci for (k = 1; k < 33; ++k) { 1858c2ecf20Sopenharmony_ci if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); 1888c2ecf20Sopenharmony_ci clear_data(readbuf, subpgsize * k); 1898c2ecf20Sopenharmony_ci err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf); 1908c2ecf20Sopenharmony_ci if (unlikely(err || read != subpgsize * k)) { 1918c2ecf20Sopenharmony_ci if (mtd_is_bitflip(err) && read == subpgsize * k) { 1928c2ecf20Sopenharmony_ci pr_info("ECC correction at %#llx\n", 1938c2ecf20Sopenharmony_ci (long long)addr); 1948c2ecf20Sopenharmony_ci err = 0; 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci pr_err("error: read failed at " 1978c2ecf20Sopenharmony_ci "%#llx\n", (long long)addr); 1988c2ecf20Sopenharmony_ci return err ? err : -1; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { 2028c2ecf20Sopenharmony_ci pr_err("error: verify failed at %#llx\n", 2038c2ecf20Sopenharmony_ci (long long)addr); 2048c2ecf20Sopenharmony_ci errcnt += 1; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci addr += subpgsize * k; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return err; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int verify_eraseblock_ff(int ebnum) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci uint32_t j; 2158c2ecf20Sopenharmony_ci size_t read; 2168c2ecf20Sopenharmony_ci int err = 0; 2178c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci memset(writebuf, 0xff, subpgsize); 2208c2ecf20Sopenharmony_ci for (j = 0; j < mtd->erasesize / subpgsize; ++j) { 2218c2ecf20Sopenharmony_ci clear_data(readbuf, subpgsize); 2228c2ecf20Sopenharmony_ci err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 2238c2ecf20Sopenharmony_ci if (unlikely(err || read != subpgsize)) { 2248c2ecf20Sopenharmony_ci if (mtd_is_bitflip(err) && read == subpgsize) { 2258c2ecf20Sopenharmony_ci pr_info("ECC correction at %#llx\n", 2268c2ecf20Sopenharmony_ci (long long)addr); 2278c2ecf20Sopenharmony_ci err = 0; 2288c2ecf20Sopenharmony_ci } else { 2298c2ecf20Sopenharmony_ci pr_err("error: read failed at " 2308c2ecf20Sopenharmony_ci "%#llx\n", (long long)addr); 2318c2ecf20Sopenharmony_ci return err ? err : -1; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 2358c2ecf20Sopenharmony_ci pr_err("error: verify 0xff failed at " 2368c2ecf20Sopenharmony_ci "%#llx\n", (long long)addr); 2378c2ecf20Sopenharmony_ci errcnt += 1; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci addr += subpgsize; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return err; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int verify_all_eraseblocks_ff(void) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int err; 2488c2ecf20Sopenharmony_ci unsigned int i; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci pr_info("verifying all eraseblocks for 0xff\n"); 2518c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 2528c2ecf20Sopenharmony_ci if (bbt[i]) 2538c2ecf20Sopenharmony_ci continue; 2548c2ecf20Sopenharmony_ci err = verify_eraseblock_ff(i); 2558c2ecf20Sopenharmony_ci if (err) 2568c2ecf20Sopenharmony_ci return err; 2578c2ecf20Sopenharmony_ci if (i % 256 == 0) 2588c2ecf20Sopenharmony_ci pr_info("verified up to eraseblock %u\n", i); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci err = mtdtest_relax(); 2618c2ecf20Sopenharmony_ci if (err) 2628c2ecf20Sopenharmony_ci return err; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci pr_info("verified %u eraseblocks\n", i); 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int __init mtd_subpagetest_init(void) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci int err = 0; 2718c2ecf20Sopenharmony_ci uint32_t i; 2728c2ecf20Sopenharmony_ci uint64_t tmp; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci printk(KERN_INFO "\n"); 2758c2ecf20Sopenharmony_ci printk(KERN_INFO "=================================================\n"); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (dev < 0) { 2788c2ecf20Sopenharmony_ci pr_info("Please specify a valid mtd-device via module parameter\n"); 2798c2ecf20Sopenharmony_ci pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 2808c2ecf20Sopenharmony_ci return -EINVAL; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci pr_info("MTD device: %d\n", dev); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci mtd = get_mtd_device(NULL, dev); 2868c2ecf20Sopenharmony_ci if (IS_ERR(mtd)) { 2878c2ecf20Sopenharmony_ci err = PTR_ERR(mtd); 2888c2ecf20Sopenharmony_ci pr_err("error: cannot get MTD device\n"); 2898c2ecf20Sopenharmony_ci return err; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (!mtd_type_is_nand(mtd)) { 2938c2ecf20Sopenharmony_ci pr_info("this test requires NAND flash\n"); 2948c2ecf20Sopenharmony_ci goto out; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci subpgsize = mtd->writesize >> mtd->subpage_sft; 2988c2ecf20Sopenharmony_ci tmp = mtd->size; 2998c2ecf20Sopenharmony_ci do_div(tmp, mtd->erasesize); 3008c2ecf20Sopenharmony_ci ebcnt = tmp; 3018c2ecf20Sopenharmony_ci pgcnt = mtd->erasesize / mtd->writesize; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci pr_info("MTD device size %llu, eraseblock size %u, " 3048c2ecf20Sopenharmony_ci "page size %u, subpage size %u, count of eraseblocks %u, " 3058c2ecf20Sopenharmony_ci "pages per eraseblock %u, OOB size %u\n", 3068c2ecf20Sopenharmony_ci (unsigned long long)mtd->size, mtd->erasesize, 3078c2ecf20Sopenharmony_ci mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci err = -ENOMEM; 3108c2ecf20Sopenharmony_ci bufsize = subpgsize * 32; 3118c2ecf20Sopenharmony_ci writebuf = kmalloc(bufsize, GFP_KERNEL); 3128c2ecf20Sopenharmony_ci if (!writebuf) 3138c2ecf20Sopenharmony_ci goto out; 3148c2ecf20Sopenharmony_ci readbuf = kmalloc(bufsize, GFP_KERNEL); 3158c2ecf20Sopenharmony_ci if (!readbuf) 3168c2ecf20Sopenharmony_ci goto out; 3178c2ecf20Sopenharmony_ci bbt = kzalloc(ebcnt, GFP_KERNEL); 3188c2ecf20Sopenharmony_ci if (!bbt) 3198c2ecf20Sopenharmony_ci goto out; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 3228c2ecf20Sopenharmony_ci if (err) 3238c2ecf20Sopenharmony_ci goto out; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 3268c2ecf20Sopenharmony_ci if (err) 3278c2ecf20Sopenharmony_ci goto out; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci pr_info("writing whole device\n"); 3308c2ecf20Sopenharmony_ci prandom_seed_state(&rnd_state, 1); 3318c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 3328c2ecf20Sopenharmony_ci if (bbt[i]) 3338c2ecf20Sopenharmony_ci continue; 3348c2ecf20Sopenharmony_ci err = write_eraseblock(i); 3358c2ecf20Sopenharmony_ci if (unlikely(err)) 3368c2ecf20Sopenharmony_ci goto out; 3378c2ecf20Sopenharmony_ci if (i % 256 == 0) 3388c2ecf20Sopenharmony_ci pr_info("written up to eraseblock %u\n", i); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci err = mtdtest_relax(); 3418c2ecf20Sopenharmony_ci if (err) 3428c2ecf20Sopenharmony_ci goto out; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci pr_info("written %u eraseblocks\n", i); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci prandom_seed_state(&rnd_state, 1); 3478c2ecf20Sopenharmony_ci pr_info("verifying all eraseblocks\n"); 3488c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 3498c2ecf20Sopenharmony_ci if (bbt[i]) 3508c2ecf20Sopenharmony_ci continue; 3518c2ecf20Sopenharmony_ci err = verify_eraseblock(i); 3528c2ecf20Sopenharmony_ci if (unlikely(err)) 3538c2ecf20Sopenharmony_ci goto out; 3548c2ecf20Sopenharmony_ci if (i % 256 == 0) 3558c2ecf20Sopenharmony_ci pr_info("verified up to eraseblock %u\n", i); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci err = mtdtest_relax(); 3588c2ecf20Sopenharmony_ci if (err) 3598c2ecf20Sopenharmony_ci goto out; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci pr_info("verified %u eraseblocks\n", i); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 3648c2ecf20Sopenharmony_ci if (err) 3658c2ecf20Sopenharmony_ci goto out; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci err = verify_all_eraseblocks_ff(); 3688c2ecf20Sopenharmony_ci if (err) 3698c2ecf20Sopenharmony_ci goto out; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Write all eraseblocks */ 3728c2ecf20Sopenharmony_ci prandom_seed_state(&rnd_state, 3); 3738c2ecf20Sopenharmony_ci pr_info("writing whole device\n"); 3748c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 3758c2ecf20Sopenharmony_ci if (bbt[i]) 3768c2ecf20Sopenharmony_ci continue; 3778c2ecf20Sopenharmony_ci err = write_eraseblock2(i); 3788c2ecf20Sopenharmony_ci if (unlikely(err)) 3798c2ecf20Sopenharmony_ci goto out; 3808c2ecf20Sopenharmony_ci if (i % 256 == 0) 3818c2ecf20Sopenharmony_ci pr_info("written up to eraseblock %u\n", i); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci err = mtdtest_relax(); 3848c2ecf20Sopenharmony_ci if (err) 3858c2ecf20Sopenharmony_ci goto out; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci pr_info("written %u eraseblocks\n", i); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Check all eraseblocks */ 3908c2ecf20Sopenharmony_ci prandom_seed_state(&rnd_state, 3); 3918c2ecf20Sopenharmony_ci pr_info("verifying all eraseblocks\n"); 3928c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 3938c2ecf20Sopenharmony_ci if (bbt[i]) 3948c2ecf20Sopenharmony_ci continue; 3958c2ecf20Sopenharmony_ci err = verify_eraseblock2(i); 3968c2ecf20Sopenharmony_ci if (unlikely(err)) 3978c2ecf20Sopenharmony_ci goto out; 3988c2ecf20Sopenharmony_ci if (i % 256 == 0) 3998c2ecf20Sopenharmony_ci pr_info("verified up to eraseblock %u\n", i); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci err = mtdtest_relax(); 4028c2ecf20Sopenharmony_ci if (err) 4038c2ecf20Sopenharmony_ci goto out; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci pr_info("verified %u eraseblocks\n", i); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 4088c2ecf20Sopenharmony_ci if (err) 4098c2ecf20Sopenharmony_ci goto out; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci err = verify_all_eraseblocks_ff(); 4128c2ecf20Sopenharmony_ci if (err) 4138c2ecf20Sopenharmony_ci goto out; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci pr_info("finished with %d errors\n", errcnt); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciout: 4188c2ecf20Sopenharmony_ci kfree(bbt); 4198c2ecf20Sopenharmony_ci kfree(readbuf); 4208c2ecf20Sopenharmony_ci kfree(writebuf); 4218c2ecf20Sopenharmony_ci put_mtd_device(mtd); 4228c2ecf20Sopenharmony_ci if (err) 4238c2ecf20Sopenharmony_ci pr_info("error %d occurred\n", err); 4248c2ecf20Sopenharmony_ci printk(KERN_INFO "=================================================\n"); 4258c2ecf20Sopenharmony_ci return err; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_cimodule_init(mtd_subpagetest_init); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic void __exit mtd_subpagetest_exit(void) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci return; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_cimodule_exit(mtd_subpagetest_exit); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Subpage test module"); 4368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Adrian Hunter"); 4378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 438