18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "mtd_test: " fmt 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/module.h> 58c2ecf20Sopenharmony_ci#include <linux/sched.h> 68c2ecf20Sopenharmony_ci#include <linux/printk.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "mtd_test.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ciint mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) 118c2ecf20Sopenharmony_ci{ 128c2ecf20Sopenharmony_ci int err; 138c2ecf20Sopenharmony_ci struct erase_info ei; 148c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci memset(&ei, 0, sizeof(struct erase_info)); 178c2ecf20Sopenharmony_ci ei.addr = addr; 188c2ecf20Sopenharmony_ci ei.len = mtd->erasesize; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci err = mtd_erase(mtd, &ei); 218c2ecf20Sopenharmony_ci if (err) { 228c2ecf20Sopenharmony_ci pr_info("error %d while erasing EB %d\n", err, ebnum); 238c2ecf20Sopenharmony_ci return err; 248c2ecf20Sopenharmony_ci } 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci int ret; 328c2ecf20Sopenharmony_ci loff_t addr = (loff_t)ebnum * mtd->erasesize; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci ret = mtd_block_isbad(mtd, addr); 358c2ecf20Sopenharmony_ci if (ret) 368c2ecf20Sopenharmony_ci pr_info("block %d is bad\n", ebnum); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return ret; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciint mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, 428c2ecf20Sopenharmony_ci unsigned int eb, int ebcnt) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int i, bad = 0; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (!mtd_can_have_bb(mtd)) 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci pr_info("scanning for bad eraseblocks\n"); 508c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 518c2ecf20Sopenharmony_ci bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0; 528c2ecf20Sopenharmony_ci if (bbt[i]) 538c2ecf20Sopenharmony_ci bad += 1; 548c2ecf20Sopenharmony_ci cond_resched(); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciint mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, 628c2ecf20Sopenharmony_ci unsigned int eb, int ebcnt) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci int err; 658c2ecf20Sopenharmony_ci unsigned int i; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci for (i = 0; i < ebcnt; ++i) { 688c2ecf20Sopenharmony_ci if (bbt[i]) 698c2ecf20Sopenharmony_ci continue; 708c2ecf20Sopenharmony_ci err = mtdtest_erase_eraseblock(mtd, eb + i); 718c2ecf20Sopenharmony_ci if (err) 728c2ecf20Sopenharmony_ci return err; 738c2ecf20Sopenharmony_ci cond_resched(); 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci size_t read; 828c2ecf20Sopenharmony_ci int err; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci err = mtd_read(mtd, addr, size, &read, buf); 858c2ecf20Sopenharmony_ci /* Ignore corrected ECC errors */ 868c2ecf20Sopenharmony_ci if (mtd_is_bitflip(err)) 878c2ecf20Sopenharmony_ci err = 0; 888c2ecf20Sopenharmony_ci if (!err && read != size) 898c2ecf20Sopenharmony_ci err = -EIO; 908c2ecf20Sopenharmony_ci if (err) 918c2ecf20Sopenharmony_ci pr_err("error: read failed at %#llx\n", addr); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return err; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, 978c2ecf20Sopenharmony_ci const void *buf) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci size_t written; 1008c2ecf20Sopenharmony_ci int err; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci err = mtd_write(mtd, addr, size, &written, buf); 1038c2ecf20Sopenharmony_ci if (!err && written != size) 1048c2ecf20Sopenharmony_ci err = -EIO; 1058c2ecf20Sopenharmony_ci if (err) 1068c2ecf20Sopenharmony_ci pr_err("error: write failed at %#llx\n", addr); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return err; 1098c2ecf20Sopenharmony_ci} 110