xref: /OK3568_Linux_fs/kernel/drivers/mtd/tests/readtest.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2006-2008 Nokia Corporation
4  *
5  * Check MTD device read.
6  *
7  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
8  */
9 
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/err.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/slab.h>
18 #include <linux/sched.h>
19 
20 #include "mtd_test.h"
21 
22 static int dev = -EINVAL;
23 module_param(dev, int, S_IRUGO);
24 MODULE_PARM_DESC(dev, "MTD device number to use");
25 
26 static unsigned int cycles_count = 1;
27 module_param(cycles_count, uint, S_IRUGO);
28 MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "
29 			       "(infinite by default)");
30 
31 static struct mtd_info *mtd;
32 static unsigned char *iobuf;
33 static unsigned char *iobuf1;
34 static unsigned char *bbt;
35 
36 static int pgsize;
37 static int ebcnt;
38 static int pgcnt;
39 
read_eraseblock_by_page(int ebnum)40 static int read_eraseblock_by_page(int ebnum)
41 {
42 	int i, ret, err = 0;
43 	loff_t addr = (loff_t)ebnum * mtd->erasesize;
44 	void *buf = iobuf;
45 	void *oobbuf = iobuf1;
46 
47 	for (i = 0; i < pgcnt; i++) {
48 		memset(buf, 0 , pgsize);
49 		ret = mtdtest_read(mtd, addr, pgsize, buf);
50 		if (ret) {
51 			if (!err)
52 				err = ret;
53 		}
54 		if (mtd->oobsize) {
55 			struct mtd_oob_ops ops;
56 
57 			ops.mode      = MTD_OPS_PLACE_OOB;
58 			ops.len       = 0;
59 			ops.retlen    = 0;
60 			ops.ooblen    = mtd->oobsize;
61 			ops.oobretlen = 0;
62 			ops.ooboffs   = 0;
63 			ops.datbuf    = NULL;
64 			ops.oobbuf    = oobbuf;
65 			ret = mtd_read_oob(mtd, addr, &ops);
66 			if ((ret && !mtd_is_bitflip(ret)) ||
67 					ops.oobretlen != mtd->oobsize) {
68 				pr_err("error: read oob failed at "
69 						  "%#llx\n", (long long)addr);
70 				if (!err)
71 					err = ret;
72 				if (!err)
73 					err = -EINVAL;
74 			}
75 			oobbuf += mtd->oobsize;
76 		}
77 		addr += pgsize;
78 		buf += pgsize;
79 	}
80 
81 	return err;
82 }
83 
dump_eraseblock(int ebnum)84 static void dump_eraseblock(int ebnum)
85 {
86 	int i, j, n;
87 	char line[128];
88 	int pg, oob;
89 
90 	pr_info("dumping eraseblock %d\n", ebnum);
91 	n = mtd->erasesize;
92 	for (i = 0; i < n;) {
93 		char *p = line;
94 
95 		p += sprintf(p, "%05x: ", i);
96 		for (j = 0; j < 32 && i < n; j++, i++)
97 			p += sprintf(p, "%02x", (unsigned int)iobuf[i]);
98 		printk(KERN_CRIT "%s\n", line);
99 		cond_resched();
100 	}
101 	if (!mtd->oobsize)
102 		return;
103 	pr_info("dumping oob from eraseblock %d\n", ebnum);
104 	n = mtd->oobsize;
105 	for (pg = 0, i = 0; pg < pgcnt; pg++)
106 		for (oob = 0; oob < n;) {
107 			char *p = line;
108 
109 			p += sprintf(p, "%05x: ", i);
110 			for (j = 0; j < 32 && oob < n; j++, oob++, i++)
111 				p += sprintf(p, "%02x",
112 					     (unsigned int)iobuf1[i]);
113 			printk(KERN_CRIT "%s\n", line);
114 			cond_resched();
115 		}
116 }
117 
mtd_readtest_init(void)118 static int __init mtd_readtest_init(void)
119 {
120 	uint64_t tmp;
121 	int err, i;
122 
123 	printk(KERN_INFO "\n");
124 	printk(KERN_INFO "=================================================\n");
125 
126 	if (dev < 0) {
127 		pr_info("Please specify a valid mtd-device via module parameter\n");
128 		return -EINVAL;
129 	}
130 
131 	pr_info("MTD device: %d\n", dev);
132 
133 	mtd = get_mtd_device(NULL, dev);
134 	if (IS_ERR(mtd)) {
135 		err = PTR_ERR(mtd);
136 		pr_err("error: Cannot get MTD device\n");
137 		return err;
138 	}
139 
140 	if (mtd->writesize == 1) {
141 		pr_info("not NAND flash, assume page size is 512 "
142 		       "bytes.\n");
143 		pgsize = 512;
144 	} else
145 		pgsize = mtd->writesize;
146 
147 	tmp = mtd->size;
148 	do_div(tmp, mtd->erasesize);
149 	ebcnt = tmp;
150 	pgcnt = mtd->erasesize / pgsize;
151 
152 	pr_info("MTD device size %llu, eraseblock size %u, "
153 	       "page size %u, count of eraseblocks %u, pages per "
154 	       "eraseblock %u, OOB size %u\n",
155 	       (unsigned long long)mtd->size, mtd->erasesize,
156 	       pgsize, ebcnt, pgcnt, mtd->oobsize);
157 
158 	err = -ENOMEM;
159 	iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
160 	if (!iobuf)
161 		goto out;
162 	iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
163 	if (!iobuf1)
164 		goto out;
165 
166 	bbt = kzalloc(ebcnt, GFP_KERNEL);
167 	if (!bbt)
168 		goto out;
169 	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
170 	if (err)
171 		goto out;
172 
173 	/* Read all eraseblocks 1 page at a time */
174 	pr_info("testing page read\n");
175 	while (cycles_count--) {
176 		pr_info("Number of remaining cycles %d\n", cycles_count);
177 		for (i = 0; i < ebcnt; ++i) {
178 			int ret;
179 
180 			if (bbt[i])
181 				continue;
182 			ret = read_eraseblock_by_page(i);
183 			if (ret) {
184 				dump_eraseblock(i);
185 				if (!err)
186 					err = ret;
187 			}
188 
189 			ret = mtdtest_relax();
190 			if (ret) {
191 				err = ret;
192 				goto out;
193 			}
194 		}
195 	}
196 
197 	if (err)
198 		pr_info("finished with errors\n");
199 	else
200 		pr_info("finished\n");
201 
202 out:
203 
204 	kfree(iobuf);
205 	kfree(iobuf1);
206 	kfree(bbt);
207 	put_mtd_device(mtd);
208 	if (err)
209 		pr_info("error %d occurred\n", err);
210 	printk(KERN_INFO "=================================================\n");
211 	return err;
212 }
213 module_init(mtd_readtest_init);
214 
mtd_readtest_exit(void)215 static void __exit mtd_readtest_exit(void)
216 {
217 	return;
218 }
219 module_exit(mtd_readtest_exit);
220 
221 MODULE_DESCRIPTION("Read test module");
222 MODULE_AUTHOR("Adrian Hunter");
223 MODULE_LICENSE("GPL");
224