162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#define pr_fmt(fmt) "mtd_test: " fmt 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/sched.h> 662306a36Sopenharmony_ci#include <linux/printk.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "mtd_test.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciint mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci int err; 1362306a36Sopenharmony_ci struct erase_info ei; 1462306a36Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci memset(&ei, 0, sizeof(struct erase_info)); 1762306a36Sopenharmony_ci ei.addr = addr; 1862306a36Sopenharmony_ci ei.len = mtd->erasesize; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci err = mtd_erase(mtd, &ei); 2162306a36Sopenharmony_ci if (err) { 2262306a36Sopenharmony_ci pr_info("error %d while erasing EB %d\n", err, ebnum); 2362306a36Sopenharmony_ci return err; 2462306a36Sopenharmony_ci } 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci int ret; 3262306a36Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci ret = mtd_block_isbad(mtd, addr); 3562306a36Sopenharmony_ci if (ret) 3662306a36Sopenharmony_ci pr_info("block %d is bad\n", ebnum); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return ret; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciint mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, 4262306a36Sopenharmony_ci unsigned int eb, int ebcnt) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci int i, bad = 0; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (!mtd_can_have_bb(mtd)) 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci pr_info("scanning for bad eraseblocks\n"); 5062306a36Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 5162306a36Sopenharmony_ci bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0; 5262306a36Sopenharmony_ci if (bbt[i]) 5362306a36Sopenharmony_ci bad += 1; 5462306a36Sopenharmony_ci cond_resched(); 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ciint mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, 6262306a36Sopenharmony_ci unsigned int eb, int ebcnt) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci int err; 6562306a36Sopenharmony_ci unsigned int i; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 6862306a36Sopenharmony_ci if (bbt[i]) 6962306a36Sopenharmony_ci continue; 7062306a36Sopenharmony_ci err = mtdtest_erase_eraseblock(mtd, eb + i); 7162306a36Sopenharmony_ci if (err) 7262306a36Sopenharmony_ci return err; 7362306a36Sopenharmony_ci cond_resched(); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciint mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci size_t read; 8262306a36Sopenharmony_ci int err; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci err = mtd_read(mtd, addr, size, &read, buf); 8562306a36Sopenharmony_ci /* Ignore corrected ECC errors */ 8662306a36Sopenharmony_ci if (mtd_is_bitflip(err)) 8762306a36Sopenharmony_ci err = 0; 8862306a36Sopenharmony_ci if (!err && read != size) 8962306a36Sopenharmony_ci err = -EIO; 9062306a36Sopenharmony_ci if (err) 9162306a36Sopenharmony_ci pr_err("error: read failed at %#llx\n", addr); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return err; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciint mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, 9762306a36Sopenharmony_ci const void *buf) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci size_t written; 10062306a36Sopenharmony_ci int err; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci err = mtd_write(mtd, addr, size, &written, buf); 10362306a36Sopenharmony_ci if (!err && written != size) 10462306a36Sopenharmony_ci err = -EIO; 10562306a36Sopenharmony_ci if (err) 10662306a36Sopenharmony_ci pr_err("error: write failed at %#llx\n", addr); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return err; 10962306a36Sopenharmony_ci} 110