blob: 83189765eb051cb401b8eca53ab56bfcea0f80cb [file] [log] [blame]
Artem Bityutskiye73f2172008-12-08 13:34:16 +02001/*
2 * Copyright (C) 2006-2008 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Test page read and write on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
Vikram Narayananbb998412012-10-10 23:07:40 +053022#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
Artem Bityutskiye73f2172008-12-08 13:34:16 +020024#include <asm/div64.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/err.h>
29#include <linux/mtd/mtd.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090030#include <linux/slab.h>
Artem Bityutskiye73f2172008-12-08 13:34:16 +020031#include <linux/sched.h>
Akinobu Mita825b8cc2013-02-27 17:05:35 -080032#include <linux/random.h>
Artem Bityutskiye73f2172008-12-08 13:34:16 +020033
Akinobu Mita66b28182013-08-03 18:52:10 +090034#include "mtd_test.h"
35
Wolfram Sang74060602011-10-30 00:11:53 +020036static int dev = -EINVAL;
Artem Bityutskiye73f2172008-12-08 13:34:16 +020037module_param(dev, int, S_IRUGO);
38MODULE_PARM_DESC(dev, "MTD device number to use");
39
40static struct mtd_info *mtd;
41static unsigned char *twopages;
42static unsigned char *writebuf;
43static unsigned char *boundary;
44static unsigned char *bbt;
45
46static int pgsize;
47static int bufsize;
48static int ebcnt;
49static int pgcnt;
50static int errcnt;
Akinobu Mita825b8cc2013-02-27 17:05:35 -080051static struct rnd_state rnd_state;
Artem Bityutskiye73f2172008-12-08 13:34:16 +020052
Artem Bityutskiye73f2172008-12-08 13:34:16 +020053static int write_eraseblock(int ebnum)
54{
Akinobu Mita66b28182013-08-03 18:52:10 +090055 int err;
Artem Bityutskiye73f2172008-12-08 13:34:16 +020056 loff_t addr = ebnum * mtd->erasesize;
57
Akinobu Mita825b8cc2013-02-27 17:05:35 -080058 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
Artem Bityutskiye73f2172008-12-08 13:34:16 +020059 cond_resched();
Akinobu Mita66b28182013-08-03 18:52:10 +090060 err = mtdtest_write(mtd, addr, mtd->erasesize, writebuf);
61 if (err)
Vikram Narayananbb998412012-10-10 23:07:40 +053062 pr_err("error: write failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +020063 (long long)addr);
64
65 return err;
66}
67
68static int verify_eraseblock(int ebnum)
69{
70 uint32_t j;
Artem Bityutskiye73f2172008-12-08 13:34:16 +020071 int err = 0, i;
72 loff_t addr0, addrn;
73 loff_t addr = ebnum * mtd->erasesize;
74
75 addr0 = 0;
Roel Kluinc6f7e7b2009-07-31 16:21:01 +020076 for (i = 0; i < ebcnt && bbt[i]; ++i)
Artem Bityutskiye73f2172008-12-08 13:34:16 +020077 addr0 += mtd->erasesize;
78
79 addrn = mtd->size;
Roel Kluinc6f7e7b2009-07-31 16:21:01 +020080 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
Artem Bityutskiye73f2172008-12-08 13:34:16 +020081 addrn -= mtd->erasesize;
82
Akinobu Mita825b8cc2013-02-27 17:05:35 -080083 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
Artem Bityutskiye73f2172008-12-08 13:34:16 +020084 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
85 /* Do a read to set the internal dataRAMs to different data */
Akinobu Mita66b28182013-08-03 18:52:10 +090086 err = mtdtest_read(mtd, addr0, bufsize, twopages);
87 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +053088 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +020089 (long long)addr0);
90 return err;
91 }
Akinobu Mita66b28182013-08-03 18:52:10 +090092 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
93 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +053094 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +020095 (long long)(addrn - bufsize));
96 return err;
97 }
98 memset(twopages, 0, bufsize);
Akinobu Mita66b28182013-08-03 18:52:10 +090099 err = mtdtest_read(mtd, addr, bufsize, twopages);
100 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530101 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200102 (long long)addr);
103 break;
104 }
105 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530106 pr_err("error: verify failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200107 (long long)addr);
108 errcnt += 1;
109 }
110 }
111 /* Check boundary between eraseblocks */
112 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800113 struct rnd_state old_state = rnd_state;
114
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200115 /* Do a read to set the internal dataRAMs to different data */
Akinobu Mita66b28182013-08-03 18:52:10 +0900116 err = mtdtest_read(mtd, addr0, bufsize, twopages);
117 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530118 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200119 (long long)addr0);
120 return err;
121 }
Akinobu Mita66b28182013-08-03 18:52:10 +0900122 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
123 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530124 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200125 (long long)(addrn - bufsize));
126 return err;
127 }
128 memset(twopages, 0, bufsize);
Akinobu Mita66b28182013-08-03 18:52:10 +0900129 err = mtdtest_read(mtd, addr, bufsize, twopages);
130 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530131 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200132 (long long)addr);
133 return err;
134 }
135 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800136 prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200137 if (memcmp(twopages, boundary, bufsize)) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530138 pr_err("error: verify failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200139 (long long)addr);
140 errcnt += 1;
141 }
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800142 rnd_state = old_state;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200143 }
144 return err;
145}
146
147static int crosstest(void)
148{
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200149 int err = 0, i;
150 loff_t addr, addr0, addrn;
151 unsigned char *pp1, *pp2, *pp3, *pp4;
152
Vikram Narayananbb998412012-10-10 23:07:40 +0530153 pr_info("crosstest\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200154 pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
Brian Norris33777e62013-05-02 14:18:51 -0700155 if (!pp1)
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200156 return -ENOMEM;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200157 pp2 = pp1 + pgsize;
158 pp3 = pp2 + pgsize;
159 pp4 = pp3 + pgsize;
160 memset(pp1, 0, pgsize * 4);
161
162 addr0 = 0;
Roel Kluinc6f7e7b2009-07-31 16:21:01 +0200163 for (i = 0; i < ebcnt && bbt[i]; ++i)
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200164 addr0 += mtd->erasesize;
165
166 addrn = mtd->size;
Roel Kluinc6f7e7b2009-07-31 16:21:01 +0200167 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200168 addrn -= mtd->erasesize;
169
170 /* Read 2nd-to-last page to pp1 */
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200171 addr = addrn - pgsize - pgsize;
Akinobu Mita66b28182013-08-03 18:52:10 +0900172 err = mtdtest_read(mtd, addr, pgsize, pp1);
173 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530174 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200175 (long long)addr);
176 kfree(pp1);
177 return err;
178 }
179
180 /* Read 3rd-to-last page to pp1 */
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200181 addr = addrn - pgsize - pgsize - pgsize;
Akinobu Mita66b28182013-08-03 18:52:10 +0900182 err = mtdtest_read(mtd, addr, pgsize, pp1);
183 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530184 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200185 (long long)addr);
186 kfree(pp1);
187 return err;
188 }
189
190 /* Read first page to pp2 */
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200191 addr = addr0;
Vikram Narayananbb998412012-10-10 23:07:40 +0530192 pr_info("reading page at %#llx\n", (long long)addr);
Akinobu Mita66b28182013-08-03 18:52:10 +0900193 err = mtdtest_read(mtd, addr, pgsize, pp2);
194 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530195 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200196 (long long)addr);
197 kfree(pp1);
198 return err;
199 }
200
201 /* Read last page to pp3 */
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200202 addr = addrn - pgsize;
Vikram Narayananbb998412012-10-10 23:07:40 +0530203 pr_info("reading page at %#llx\n", (long long)addr);
Akinobu Mita66b28182013-08-03 18:52:10 +0900204 err = mtdtest_read(mtd, addr, pgsize, pp3);
205 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530206 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200207 (long long)addr);
208 kfree(pp1);
209 return err;
210 }
211
212 /* Read first page again to pp4 */
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200213 addr = addr0;
Vikram Narayananbb998412012-10-10 23:07:40 +0530214 pr_info("reading page at %#llx\n", (long long)addr);
Akinobu Mita66b28182013-08-03 18:52:10 +0900215 err = mtdtest_read(mtd, addr, pgsize, pp4);
216 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530217 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200218 (long long)addr);
219 kfree(pp1);
220 return err;
221 }
222
223 /* pp2 and pp4 should be the same */
Vikram Narayananbb998412012-10-10 23:07:40 +0530224 pr_info("verifying pages read at %#llx match\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200225 (long long)addr0);
226 if (memcmp(pp2, pp4, pgsize)) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530227 pr_err("verify failed!\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200228 errcnt += 1;
229 } else if (!err)
Vikram Narayananbb998412012-10-10 23:07:40 +0530230 pr_info("crosstest ok\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200231 kfree(pp1);
232 return err;
233}
234
235static int erasecrosstest(void)
236{
Roel Kluin7fc14bc2010-07-13 13:24:31 +0300237 int err = 0, i, ebnum, ebnum2;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200238 loff_t addr0;
239 char *readbuf = twopages;
240
Vikram Narayananbb998412012-10-10 23:07:40 +0530241 pr_info("erasecrosstest\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200242
243 ebnum = 0;
244 addr0 = 0;
Roel Kluinc6f7e7b2009-07-31 16:21:01 +0200245 for (i = 0; i < ebcnt && bbt[i]; ++i) {
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200246 addr0 += mtd->erasesize;
247 ebnum += 1;
248 }
249
250 ebnum2 = ebcnt - 1;
251 while (ebnum2 && bbt[ebnum2])
252 ebnum2 -= 1;
253
Vikram Narayananbb998412012-10-10 23:07:40 +0530254 pr_info("erasing block %d\n", ebnum);
Akinobu Mita66b28182013-08-03 18:52:10 +0900255 err = mtdtest_erase_eraseblock(mtd, ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200256 if (err)
257 return err;
258
Vikram Narayananbb998412012-10-10 23:07:40 +0530259 pr_info("writing 1st page of block %d\n", ebnum);
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800260 prandom_bytes_state(&rnd_state, writebuf, pgsize);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200261 strcpy(writebuf, "There is no data like this!");
Akinobu Mita66b28182013-08-03 18:52:10 +0900262 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
263 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530264 pr_info("error: write failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200265 (long long)addr0);
Akinobu Mita66b28182013-08-03 18:52:10 +0900266 return err;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200267 }
268
Vikram Narayananbb998412012-10-10 23:07:40 +0530269 pr_info("reading 1st page of block %d\n", ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200270 memset(readbuf, 0, pgsize);
Akinobu Mita66b28182013-08-03 18:52:10 +0900271 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
272 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530273 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200274 (long long)addr0);
Akinobu Mita66b28182013-08-03 18:52:10 +0900275 return err;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200276 }
277
Vikram Narayananbb998412012-10-10 23:07:40 +0530278 pr_info("verifying 1st page of block %d\n", ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200279 if (memcmp(writebuf, readbuf, pgsize)) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530280 pr_err("verify failed!\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200281 errcnt += 1;
Roel Kluin7fc14bc2010-07-13 13:24:31 +0300282 return -1;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200283 }
284
Vikram Narayananbb998412012-10-10 23:07:40 +0530285 pr_info("erasing block %d\n", ebnum);
Akinobu Mita66b28182013-08-03 18:52:10 +0900286 err = mtdtest_erase_eraseblock(mtd, ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200287 if (err)
288 return err;
289
Vikram Narayananbb998412012-10-10 23:07:40 +0530290 pr_info("writing 1st page of block %d\n", ebnum);
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800291 prandom_bytes_state(&rnd_state, writebuf, pgsize);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200292 strcpy(writebuf, "There is no data like this!");
Akinobu Mita66b28182013-08-03 18:52:10 +0900293 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
294 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530295 pr_err("error: write failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200296 (long long)addr0);
Akinobu Mita66b28182013-08-03 18:52:10 +0900297 return err;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200298 }
299
Vikram Narayananbb998412012-10-10 23:07:40 +0530300 pr_info("erasing block %d\n", ebnum2);
Akinobu Mita66b28182013-08-03 18:52:10 +0900301 err = mtdtest_erase_eraseblock(mtd, ebnum2);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200302 if (err)
303 return err;
304
Vikram Narayananbb998412012-10-10 23:07:40 +0530305 pr_info("reading 1st page of block %d\n", ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200306 memset(readbuf, 0, pgsize);
Akinobu Mita66b28182013-08-03 18:52:10 +0900307 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
308 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530309 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200310 (long long)addr0);
Akinobu Mita66b28182013-08-03 18:52:10 +0900311 return err;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200312 }
313
Vikram Narayananbb998412012-10-10 23:07:40 +0530314 pr_info("verifying 1st page of block %d\n", ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200315 if (memcmp(writebuf, readbuf, pgsize)) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530316 pr_err("verify failed!\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200317 errcnt += 1;
Roel Kluin7fc14bc2010-07-13 13:24:31 +0300318 return -1;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200319 }
320
Roel Kluin7fc14bc2010-07-13 13:24:31 +0300321 if (!err)
Vikram Narayananbb998412012-10-10 23:07:40 +0530322 pr_info("erasecrosstest ok\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200323 return err;
324}
325
326static int erasetest(void)
327{
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200328 int err = 0, i, ebnum, ok = 1;
329 loff_t addr0;
330
Vikram Narayananbb998412012-10-10 23:07:40 +0530331 pr_info("erasetest\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200332
333 ebnum = 0;
334 addr0 = 0;
Roel Kluinc6f7e7b2009-07-31 16:21:01 +0200335 for (i = 0; i < ebcnt && bbt[i]; ++i) {
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200336 addr0 += mtd->erasesize;
337 ebnum += 1;
338 }
339
Vikram Narayananbb998412012-10-10 23:07:40 +0530340 pr_info("erasing block %d\n", ebnum);
Akinobu Mita66b28182013-08-03 18:52:10 +0900341 err = mtdtest_erase_eraseblock(mtd, ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200342 if (err)
343 return err;
344
Vikram Narayananbb998412012-10-10 23:07:40 +0530345 pr_info("writing 1st page of block %d\n", ebnum);
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800346 prandom_bytes_state(&rnd_state, writebuf, pgsize);
Akinobu Mita66b28182013-08-03 18:52:10 +0900347 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
348 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530349 pr_err("error: write failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200350 (long long)addr0);
Akinobu Mita66b28182013-08-03 18:52:10 +0900351 return err;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200352 }
353
Vikram Narayananbb998412012-10-10 23:07:40 +0530354 pr_info("erasing block %d\n", ebnum);
Akinobu Mita66b28182013-08-03 18:52:10 +0900355 err = mtdtest_erase_eraseblock(mtd, ebnum);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200356 if (err)
357 return err;
358
Vikram Narayananbb998412012-10-10 23:07:40 +0530359 pr_info("reading 1st page of block %d\n", ebnum);
Akinobu Mita66b28182013-08-03 18:52:10 +0900360 err = mtdtest_read(mtd, addr0, pgsize, twopages);
361 if (err) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530362 pr_err("error: read failed at %#llx\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200363 (long long)addr0);
Akinobu Mita66b28182013-08-03 18:52:10 +0900364 return err;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200365 }
366
Vikram Narayananbb998412012-10-10 23:07:40 +0530367 pr_info("verifying 1st page of block %d is all 0xff\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200368 ebnum);
369 for (i = 0; i < pgsize; ++i)
370 if (twopages[i] != 0xff) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530371 pr_err("verifying all 0xff failed at %d\n",
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200372 i);
373 errcnt += 1;
374 ok = 0;
375 break;
376 }
377
378 if (ok && !err)
Vikram Narayananbb998412012-10-10 23:07:40 +0530379 pr_info("erasetest ok\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200380
381 return err;
382}
383
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200384static int __init mtd_pagetest_init(void)
385{
386 int err = 0;
387 uint64_t tmp;
388 uint32_t i;
389
390 printk(KERN_INFO "\n");
391 printk(KERN_INFO "=================================================\n");
Wolfram Sang74060602011-10-30 00:11:53 +0200392
393 if (dev < 0) {
Masanari Iida064a7692012-11-09 23:20:58 +0900394 pr_info("Please specify a valid mtd-device via module parameter\n");
Vikram Narayananbb998412012-10-10 23:07:40 +0530395 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
Wolfram Sang74060602011-10-30 00:11:53 +0200396 return -EINVAL;
397 }
398
Vikram Narayananbb998412012-10-10 23:07:40 +0530399 pr_info("MTD device: %d\n", dev);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200400
401 mtd = get_mtd_device(NULL, dev);
402 if (IS_ERR(mtd)) {
403 err = PTR_ERR(mtd);
Vikram Narayananbb998412012-10-10 23:07:40 +0530404 pr_err("error: cannot get MTD device\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200405 return err;
406 }
407
408 if (mtd->type != MTD_NANDFLASH) {
Vikram Narayananbb998412012-10-10 23:07:40 +0530409 pr_info("this test requires NAND flash\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200410 goto out;
411 }
412
413 tmp = mtd->size;
414 do_div(tmp, mtd->erasesize);
415 ebcnt = tmp;
416 pgcnt = mtd->erasesize / mtd->writesize;
Artem Bityutskiy4c2b8a62009-11-27 16:58:08 +0200417 pgsize = mtd->writesize;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200418
Vikram Narayananbb998412012-10-10 23:07:40 +0530419 pr_info("MTD device size %llu, eraseblock size %u, "
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200420 "page size %u, count of eraseblocks %u, pages per "
421 "eraseblock %u, OOB size %u\n",
422 (unsigned long long)mtd->size, mtd->erasesize,
423 pgsize, ebcnt, pgcnt, mtd->oobsize);
424
425 err = -ENOMEM;
426 bufsize = pgsize * 2;
427 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
Brian Norris33777e62013-05-02 14:18:51 -0700428 if (!writebuf)
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200429 goto out;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200430 twopages = kmalloc(bufsize, GFP_KERNEL);
Brian Norris33777e62013-05-02 14:18:51 -0700431 if (!twopages)
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200432 goto out;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200433 boundary = kmalloc(bufsize, GFP_KERNEL);
Brian Norris33777e62013-05-02 14:18:51 -0700434 if (!boundary)
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200435 goto out;
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200436
Akinobu Mita66b28182013-08-03 18:52:10 +0900437 bbt = kzalloc(ebcnt, GFP_KERNEL);
438 if (!bbt)
439 goto out;
440 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200441 if (err)
442 goto out;
443
444 /* Erase all eraseblocks */
Vikram Narayananbb998412012-10-10 23:07:40 +0530445 pr_info("erasing whole device\n");
Akinobu Mita66b28182013-08-03 18:52:10 +0900446 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
447 if (err)
448 goto out;
449 pr_info("erased %u eraseblocks\n", ebcnt);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200450
451 /* Write all eraseblocks */
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800452 prandom_seed_state(&rnd_state, 1);
Vikram Narayananbb998412012-10-10 23:07:40 +0530453 pr_info("writing whole device\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200454 for (i = 0; i < ebcnt; ++i) {
455 if (bbt[i])
456 continue;
457 err = write_eraseblock(i);
458 if (err)
459 goto out;
460 if (i % 256 == 0)
Vikram Narayananbb998412012-10-10 23:07:40 +0530461 pr_info("written up to eraseblock %u\n", i);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200462 cond_resched();
463 }
Vikram Narayananbb998412012-10-10 23:07:40 +0530464 pr_info("written %u eraseblocks\n", i);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200465
466 /* Check all eraseblocks */
Akinobu Mita825b8cc2013-02-27 17:05:35 -0800467 prandom_seed_state(&rnd_state, 1);
Vikram Narayananbb998412012-10-10 23:07:40 +0530468 pr_info("verifying all eraseblocks\n");
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200469 for (i = 0; i < ebcnt; ++i) {
470 if (bbt[i])
471 continue;
472 err = verify_eraseblock(i);
473 if (err)
474 goto out;
475 if (i % 256 == 0)
Vikram Narayananbb998412012-10-10 23:07:40 +0530476 pr_info("verified up to eraseblock %u\n", i);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200477 cond_resched();
478 }
Vikram Narayananbb998412012-10-10 23:07:40 +0530479 pr_info("verified %u eraseblocks\n", i);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200480
481 err = crosstest();
482 if (err)
483 goto out;
484
485 err = erasecrosstest();
486 if (err)
487 goto out;
488
489 err = erasetest();
490 if (err)
491 goto out;
492
Vikram Narayananbb998412012-10-10 23:07:40 +0530493 pr_info("finished with %d errors\n", errcnt);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200494out:
495
496 kfree(bbt);
497 kfree(boundary);
498 kfree(twopages);
499 kfree(writebuf);
500 put_mtd_device(mtd);
501 if (err)
Vikram Narayananbb998412012-10-10 23:07:40 +0530502 pr_info("error %d occurred\n", err);
Artem Bityutskiye73f2172008-12-08 13:34:16 +0200503 printk(KERN_INFO "=================================================\n");
504 return err;
505}
506module_init(mtd_pagetest_init);
507
508static void __exit mtd_pagetest_exit(void)
509{
510 return;
511}
512module_exit(mtd_pagetest_exit);
513
514MODULE_DESCRIPTION("NAND page test");
515MODULE_AUTHOR("Adrian Hunter");
516MODULE_LICENSE("GPL");