static int write_eraseblock(int ebnum) { size_t written = 0; int err = 0; loff_t addr = ebnum * mtd->erasesize; set_random_data(writebuf, subpgsize); err = mtd->write(mtd, addr, subpgsize, &written, writebuf); if (unlikely(err || written != subpgsize)) { printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { printk(PRINT_PREF " write size: %#x\n", subpgsize); printk(PRINT_PREF " written: %#zx\n", written); } return err ? err : -1; } addr += subpgsize; set_random_data(writebuf, subpgsize); err = mtd->write(mtd, addr, subpgsize, &written, writebuf); if (unlikely(err || written != subpgsize)) { printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { printk(PRINT_PREF " write size: %#x\n", subpgsize); printk(PRINT_PREF " written: %#zx\n", written); } return err ? err : -1; } return err; }
static int verify_eraseblock_in_one_go(int ebnum) { struct mtd_oob_ops ops; int err = 0; loff_t addr = ebnum * mtd->erasesize; size_t len = mtd->ecclayout->oobavail * pgcnt; set_random_data(writebuf, len); ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = len; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd->read_oob(mtd, addr, &ops); if (err || ops.oobretlen != len) { printk(PRINT_PREF "error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf, writebuf, len)) { 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"); return -1; } } return err; }
static int write_eraseblock(int ebnum) { int i; struct mtd_oob_ops ops; int err = 0; loff_t addr = ebnum * mtd->erasesize; for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; ops.oobretlen = 0; ops.ooboffs = use_offset; ops.datbuf = NULL; ops.oobbuf = writebuf; err = mtd->write_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { printk(PRINT_PREF "error: writeoob failed at %#llx\n", (long long)addr); printk(PRINT_PREF "error: use_len %d, use_offset %d\n", use_len, use_offset); errcnt += 1; return err ? err : -1; } if (vary_offset) do_vary_offset(); } return err; }
static int verify_eraseblock2(int ebnum) { size_t read = 0; int err = 0, k; loff_t addr = ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) break; set_random_data(writebuf, subpgsize * k); clear_data(readbuf, subpgsize * k); read = 0; err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf); if (unlikely(err || read != subpgsize * k)) { if (err == -EUCLEAN && read == subpgsize * k) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; } else { printk(PRINT_PREF "error: read failed at " "%#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } addr += subpgsize * k; } return err; }
static int write_eraseblock2(int ebnum) { size_t written = 0; int err = 0, k; loff_t addr = ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) break; set_random_data(writebuf, subpgsize * k); err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf); if (unlikely(err || written != subpgsize * k)) { printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { printk(PRINT_PREF " write size: %#x\n", subpgsize * k); printk(PRINT_PREF " written: %#08zx\n", written); } return err ? err : -1; } addr += subpgsize * k; } return err; }
static int erasetest(void) { size_t read = 0, written = 0; int err = 0, i, ebnum, ok = 1; loff_t addr0; printk(PRINT_PREF "erasetest\n"); ebnum = 0; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) { addr0 += mtd->erasesize; ebnum += 1; } printk(PRINT_PREF "erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); set_random_data(writebuf, pgsize); err = mtd->write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } printk(PRINT_PREF "erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); err = mtd->read(mtd, addr0, pgsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n", ebnum); for (i = 0; i < pgsize; ++i) if (twopages[i] != 0xff) { printk(PRINT_PREF "verifying all 0xff failed at %d\n", i); errcnt += 1; ok = 0; break; } if (ok && !err) printk(PRINT_PREF "erasetest ok\n"); return err; }
static int write_eraseblock(int ebnum) { int err = 0; size_t written = 0; loff_t addr = ebnum * mtd->erasesize; set_random_data(writebuf, mtd->erasesize); cond_resched(); err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf); if (err || written != mtd->erasesize) printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr); 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; }
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; }
static int verify_eraseblock(int ebnum) { int i; struct mtd_oob_ops ops; int err = 0; loff_t addr = ebnum * mtd->erasesize; for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; ops.oobretlen = 0; ops.ooboffs = use_offset; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd->read_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { printk(PRINT_PREF "error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf, writebuf, use_len)) { 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"); return -1; } } if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { int k; ops.mode = MTD_OOB_AUTO; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd->read_oob(mtd, addr, &ops); if (err || ops.oobretlen != mtd->ecclayout->oobavail) { printk(PRINT_PREF "error: readoob failed at " "%#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf + use_offset, writebuf, use_len)) { 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"); return -1; } } for (k = 0; k < use_offset; ++k) if (readbuf[k] != 0xff) { printk(PRINT_PREF "error: verify 0xff " "failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { printk(PRINT_PREF "error: too " "many errors\n"); return -1; } } for (k = use_offset + use_len; k < mtd->ecclayout->oobavail; ++k) if (readbuf[k] != 0xff) { printk(PRINT_PREF "error: verify 0xff " "failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { printk(PRINT_PREF "error: too " "many errors\n"); return -1; } } } if (vary_offset) do_vary_offset(); } return err; }
static int verify_eraseblock(int ebnum) { size_t read = 0; int err = 0; loff_t addr = ebnum * mtd->erasesize; set_random_data(writebuf, subpgsize); clear_data(readbuf, subpgsize); read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { if (err == -EUCLEAN && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; } else { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); printk(PRINT_PREF "------------- written----------------\n"); print_subpage(writebuf); printk(PRINT_PREF "------------- read ------------------\n"); print_subpage(readbuf); printk(PRINT_PREF "-------------------------------------\n"); errcnt += 1; } addr += subpgsize; set_random_data(writebuf, subpgsize); clear_data(readbuf, subpgsize); read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { if (err == -EUCLEAN && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; } else { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); printk(PRINT_PREF "------------- written----------------\n"); print_subpage(writebuf); printk(PRINT_PREF "------------- read ------------------\n"); print_subpage(readbuf); printk(PRINT_PREF "-------------------------------------\n"); errcnt += 1; } return err; }
static int erasecrosstest(void) { size_t read = 0, written = 0; int err = 0, i, ebnum, ebnum2; loff_t addr0; char *readbuf = twopages; #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "erasecrosstest\n"); #else ; #endif ebnum = 0; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) { addr0 += mtd->erasesize; ebnum += 1; } ebnum2 = ebcnt - 1; while (ebnum2 && bbt[ebnum2]) ebnum2 -= 1; #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "erasing block %d\n", ebnum); #else ; #endif err = erase_eraseblock(ebnum); if (err) return err; #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); #else ; #endif set_random_data(writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtd->write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr0); #else ; #endif return err ? err : -1; } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); #else ; #endif memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); if (err == -EUCLEAN) err = 0; if (err || read != pgsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); #else ; #endif return err ? err : -1; } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); #else ; #endif if (memcmp(writebuf, readbuf, pgsize)) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "verify failed!\n"); #else ; #endif errcnt += 1; return -1; } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "erasing block %d\n", ebnum); #else ; #endif err = erase_eraseblock(ebnum); if (err) return err; #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); #else ; #endif set_random_data(writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtd->write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr0); #else ; #endif return err ? err : -1; } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "erasing block %d\n", ebnum2); #else ; #endif err = erase_eraseblock(ebnum2); if (err) return err; #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); #else ; #endif memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); if (err == -EUCLEAN) err = 0; if (err || read != pgsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); #else ; #endif return err ? err : -1; } #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); #else ; #endif if (memcmp(writebuf, readbuf, pgsize)) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "verify failed!\n"); #else ; #endif errcnt += 1; return -1; } if (!err) #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "erasecrosstest ok\n"); #else ; #endif return err; }
static int verify_eraseblock(int ebnum) { uint32_t j; size_t read = 0; int err = 0, i; loff_t addr0, addrn; loff_t addr = ebnum * mtd->erasesize; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) addr0 += mtd->erasesize; addrn = mtd->size; for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i) addrn -= mtd->erasesize; set_random_data(writebuf, mtd->erasesize); for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); #else ; #endif return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)(addrn - bufsize)); #else ; #endif return err; } memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr); #else ; #endif break; } if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); #else ; #endif errcnt += 1; } } /* Check boundary between eraseblocks */ if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) { unsigned long oldnext = next; /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); #else ; #endif return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)(addrn - bufsize)); #else ; #endif return err; } memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr); #else ; #endif return err; } memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); set_random_data(boundary + pgsize, pgsize); if (memcmp(twopages, boundary, bufsize)) { #ifdef CONFIG_DEBUG_PRINTK printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); #else ; #endif errcnt += 1; } next = oldnext; } 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 verify_eraseblock(int ebnum) { uint32_t j; size_t read = 0; int err = 0, i; loff_t addr0, addrn; loff_t addr = ebnum * mtd->erasesize; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) addr0 += mtd->erasesize; addrn = mtd->size; for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i) addrn -= mtd->erasesize; set_random_data(writebuf, mtd->erasesize); for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { err = mtd->read(mtd, addr0, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)(addrn - bufsize)); return err; } memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr); break; } if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } } if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) { unsigned long oldnext = next; err = mtd->read(mtd, addr0, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)(addrn - bufsize)); return err; } memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); if (err == -EUCLEAN) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr); return err; } memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); set_random_data(boundary + pgsize, pgsize); if (memcmp(twopages, boundary, bufsize)) { printk(PRINT_PREF "error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } next = oldnext; } 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; }