Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Copyright (C) 2006-2008 Artem Bityutskiy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Copyright (C) 2006-2008 Jarkko Lavinen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2006-2008 Adrian Hunter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * WARNING: this test program may kill your flash and your device. Do not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * use it unless you know what you do. Authors are not responsible for any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * damage caused by this program.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/ktime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/random.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include "mtd_test.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #define RETRIES 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) static int eb = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) module_param(eb, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) static int ebcnt = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) module_param(ebcnt, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static int pgcnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) module_param(pgcnt, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) static int dev = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) module_param(dev, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) MODULE_PARM_DESC(dev, "MTD device number to use");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) static int gran = 512;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) module_param(gran, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) MODULE_PARM_DESC(gran, "how often the status information should be printed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) static int check = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) module_param(check, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) MODULE_PARM_DESC(check, "if the written data should be checked");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) static unsigned int cycles_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) module_param(cycles_count, uint, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 			       "(infinite by default)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) static int random_pattern;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) module_param(random_pattern, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) MODULE_PARM_DESC(random_pattern, "if choose random pattern to program");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) static struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) /* This buffer contains random pattern */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) static unsigned char *patt_random;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) /* This buffer contains 0x555555...0xAAAAAA... pattern */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) static unsigned char *patt_5A5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) /* This buffer contains 0xAAAAAA...0x555555... pattern */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) static unsigned char *patt_A5A;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) /* This buffer contains all 0xFF bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) static unsigned char *patt_FF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) /* This a temporary buffer is use when checking data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) static unsigned char *check_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) /* How many erase cycles were done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) static unsigned int erase_cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) static int pgsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static ktime_t start, finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) static void report_corrupt(unsigned char *read, unsigned char *written);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) static inline void start_timing(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	start = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) static inline void stop_timing(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	finish = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)  * Check that the contents of eraseblock number @enbum is equivalent to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)  * @buf buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) static inline int check_eraseblock(int ebnum, unsigned char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	int err, retries = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	size_t read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	size_t len = mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	if (pgcnt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		len = pgcnt * pgsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) retry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	err = mtd_read(mtd, addr, len, &read, check_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	if (mtd_is_bitflip(err))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		pr_err("single bit flip occurred at EB %d "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		       "MTD reported that it was fixed.\n", ebnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	else if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		pr_err("error %d while reading EB %d, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		       "read %zd\n", err, ebnum, read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	if (read != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		pr_err("failed to read %zd bytes from EB %d, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		       "read only %zd, but no error reported\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		       len, ebnum, read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	if (memcmp(buf, check_buf, len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		pr_err("read wrong data from EB %d\n", ebnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		report_corrupt(check_buf, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 		if (retries++ < RETRIES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 			/* Try read again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 			yield();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 			pr_info("re-try reading data from EB %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 			       ebnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			goto retry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 			pr_info("retried %d times, still errors, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 			       "give-up\n", RETRIES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	if (retries != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		pr_info("only attempt number %d was OK (!!!)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		       retries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static inline int write_pattern(int ebnum, void *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	size_t written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	size_t len = mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	if (pgcnt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 		addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 		len = pgcnt * pgsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	err = mtd_write(mtd, addr, len, &written, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		pr_err("error %d while writing EB %d, written %zd"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		      " bytes\n", err, ebnum, written);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	if (written != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		pr_info("written only %zd bytes of %zd, but no error"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		       " reported\n", written, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static int __init tort_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	int err = 0, i, infinite = !cycles_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	unsigned char *bad_ebs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	printk(KERN_INFO "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	printk(KERN_INFO "=================================================\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	pr_info("Warning: this program is trying to wear out your "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	       "flash, stop it if this is not wanted.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	if (dev < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		pr_info("Please specify a valid mtd-device via module parameter\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	pr_info("MTD device: %d\n", dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	pr_info("torture %d eraseblocks (%d-%d) of mtd%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	       ebcnt, eb, eb + ebcnt - 1, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	if (pgcnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 		pr_info("torturing just %d pages per eraseblock\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 			pgcnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	pr_info("write verify %s\n", check ? "enabled" : "disabled");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	mtd = get_mtd_device(NULL, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	if (IS_ERR(mtd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 		err = PTR_ERR(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		pr_err("error: cannot get MTD device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	if (mtd->writesize == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		pr_info("not NAND flash, assume page size is 512 "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		       "bytes.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		pgsize = 512;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		pgsize = mtd->writesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		pr_err("error: invalid pgcnt value %d\n", pgcnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		goto out_mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	patt_random = kmalloc(mtd->erasesize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	if (!patt_random)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		goto out_mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	if (!patt_5A5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		goto out_patt_random;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	if (!patt_A5A)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 		goto out_patt_5A5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	if (!patt_FF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		goto out_patt_A5A;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	if (!check_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		goto out_patt_FF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	bad_ebs = kzalloc(ebcnt, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	if (!bad_ebs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 		goto out_check_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	/* Initialize patterns */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	memset(patt_FF, 0xFF, mtd->erasesize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	for (i = 0; i < mtd->erasesize / pgsize; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		if (!(i & 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 			memset(patt_5A5 + i * pgsize, 0x55, pgsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 			memset(patt_A5A + i * pgsize, 0xAA, pgsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 			memset(patt_5A5 + i * pgsize, 0xAA, pgsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 			memset(patt_A5A + i * pgsize, 0x55, pgsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	prandom_bytes(patt_random, mtd->erasesize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	err = mtdtest_scan_for_bad_eraseblocks(mtd, bad_ebs, eb, ebcnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	start_timing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 		void *patt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		err = mtdtest_erase_good_eraseblocks(mtd, bad_ebs, eb, ebcnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 		/* Check if the eraseblocks contain only 0xFF bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		if (check) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 			for (i = eb; i < eb + ebcnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 				if (bad_ebs[i - eb])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 					continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 				err = check_eraseblock(i, patt_FF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 				if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 					pr_info("verify failed"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 					       " for 0xFF... pattern\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 					goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 				err = mtdtest_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 				if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 					goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 		/* Write the pattern */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 		for (i = eb; i < eb + ebcnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			if (bad_ebs[i - eb])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 			if ((eb + erase_cycles) & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 				patt = patt_5A5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 				patt = patt_A5A;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 			if (random_pattern)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 				patt = patt_random;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 			err = write_pattern(i, patt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 			if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 				goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 			err = mtdtest_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 			if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 				goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		/* Verify what we wrote */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 		if (check) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 			for (i = eb; i < eb + ebcnt; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 				if (bad_ebs[i - eb])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 					continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 				if ((eb + erase_cycles) & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 					patt = patt_5A5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 				else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 					patt = patt_A5A;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 				if (random_pattern)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 					patt = patt_random;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 				err = check_eraseblock(i, patt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 				if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 					if (random_pattern) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 						pr_info("verify failed for random pattern\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 						goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 					}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 					pr_info("verify failed for %s"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 					       " pattern\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 					       ((eb + erase_cycles) & 1) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 					       "0x55AA55..." : "0xAA55AA...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 					goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 				err = mtdtest_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 				if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 					goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		erase_cycles += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 		if (erase_cycles % gran == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 			long ms;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 			stop_timing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 			ms = ktime_ms_delta(finish, start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 			pr_info("%08u erase cycles done, took %lu "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 			       "milliseconds (%lu seconds)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 			       erase_cycles, ms, ms / 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 			start_timing();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		if (!infinite && --cycles_count == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	pr_info("finished after %u erase cycles\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	       erase_cycles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	kfree(bad_ebs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) out_check_buf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	kfree(check_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) out_patt_FF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 	kfree(patt_FF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) out_patt_A5A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 	kfree(patt_A5A);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) out_patt_5A5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	kfree(patt_5A5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) out_patt_random:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	kfree(patt_random);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) out_mtd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	put_mtd_device(mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		pr_info("error %d occurred during torturing\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	printk(KERN_INFO "=================================================\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) module_init(tort_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) static void __exit tort_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) module_exit(tort_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) static int countdiffs(unsigned char *buf, unsigned char *check_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		      unsigned offset, unsigned len, unsigned *bytesp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 		      unsigned *bitsp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) static void print_bufs(unsigned char *read, unsigned char *written, int start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 		       int len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)  * Report the detailed information about how the read EB differs from what was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)  * written.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) static void report_corrupt(unsigned char *read, unsigned char *written)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	int bytes, bits, pages, first;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	int offset, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	size_t check_len = mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 	if (pgcnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		check_len = pgcnt * pgsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	bytes = bits = pages = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	for (i = 0; i < check_len; i += pgsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		if (countdiffs(written, read, i, pgsize, &bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 			       &bits) >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 			pages++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	pr_info("verify fails on %d pages, %d bytes/%d bits\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	       pages, bytes, bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	pr_info("The following is a list of all differences between"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	       " what was read from flash and what was expected\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	for (i = 0; i < check_len; i += pgsize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 		cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 		bytes = bits = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		first = countdiffs(written, read, i, pgsize, &bytes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 				   &bits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 		if (first < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 		printk("-------------------------------------------------------"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		       "----------------------------------\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		pr_info("Page %zd has %d bytes/%d bits failing verify,"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 		       " starting at offset 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 		       (mtd->erasesize - check_len + i) / pgsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		       bytes, bits, first);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 		offset = first & ~0x7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 		len = ((first + bytes) | 0x7) + 1 - offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 		print_bufs(read, written, offset, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) static void print_bufs(unsigned char *read, unsigned char *written, int start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 		       int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	int i = 0, j1, j2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 	char *diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 	printk("Offset       Read                          Written\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	while (i < len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 		printk("0x%08x: ", start + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 		diff = "   ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 		for (j1 = 0; j1 < 8 && i + j1 < len; j1++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 			printk(" %02x", read[start + i + j1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 			if (read[start + i + j1] != written[start + i + j1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 				diff = "***";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		while (j1 < 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 			printk(" ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 			j1 += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 		printk("  %s ", diff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 		for (j2 = 0; j2 < 8 && i + j2 < len; j2++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 			printk(" %02x", written[start + i + j2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 		printk("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 		i += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)  * Count the number of differing bytes and bits and return the first differing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)  * offset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static int countdiffs(unsigned char *buf, unsigned char *check_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 		      unsigned offset, unsigned len, unsigned *bytesp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 		      unsigned *bitsp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	unsigned i, bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	int first = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	for (i = offset; i < offset + len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 		if (buf[i] != check_buf[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 			first = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	while (i < offset + len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 		if (buf[i] != check_buf[i]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 			(*bytesp)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 			bit = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 			while (bit < 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 				if ((buf[i] & bit) != (check_buf[i] & bit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 					(*bitsp)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 				bit <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 		i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	return first;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) MODULE_DESCRIPTION("Eraseblock torturing module");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) MODULE_LICENSE("GPL");