Merge tag 'pci-v5.3-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
[linux-2.6-block.git] / drivers / mtd / tests / pagetest.c
CommitLineData
4cd10358 1// SPDX-License-Identifier: GPL-2.0-only
e73f2174
AB
2/*
3 * Copyright (C) 2006-2008 Nokia Corporation
4 *
e73f2174
AB
5 * Test page read and write on MTD device.
6 *
7 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
8 */
9
bb998419
VN
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
e73f2174
AB
12#include <asm/div64.h>
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/err.h>
17#include <linux/mtd/mtd.h>
5a0e3ad6 18#include <linux/slab.h>
e73f2174 19#include <linux/sched.h>
825b8ccb 20#include <linux/random.h>
e73f2174 21
66b28183
AM
22#include "mtd_test.h"
23
7406060e 24static int dev = -EINVAL;
e73f2174
AB
25module_param(dev, int, S_IRUGO);
26MODULE_PARM_DESC(dev, "MTD device number to use");
27
28static struct mtd_info *mtd;
29static unsigned char *twopages;
30static unsigned char *writebuf;
31static unsigned char *boundary;
32static unsigned char *bbt;
33
34static int pgsize;
35static int bufsize;
36static int ebcnt;
37static int pgcnt;
38static int errcnt;
825b8ccb 39static struct rnd_state rnd_state;
e73f2174 40
e73f2174
AB
41static int write_eraseblock(int ebnum)
42{
1001ff7a 43 loff_t addr = (loff_t)ebnum * mtd->erasesize;
e73f2174 44
825b8ccb 45 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
e73f2174 46 cond_resched();
8a9f4aa3 47 return mtdtest_write(mtd, addr, mtd->erasesize, writebuf);
e73f2174
AB
48}
49
50static int verify_eraseblock(int ebnum)
51{
52 uint32_t j;
e73f2174
AB
53 int err = 0, i;
54 loff_t addr0, addrn;
1001ff7a 55 loff_t addr = (loff_t)ebnum * mtd->erasesize;
e73f2174
AB
56
57 addr0 = 0;
c6f7e7be 58 for (i = 0; i < ebcnt && bbt[i]; ++i)
e73f2174
AB
59 addr0 += mtd->erasesize;
60
61 addrn = mtd->size;
c6f7e7be 62 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
e73f2174
AB
63 addrn -= mtd->erasesize;
64
825b8ccb 65 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
e73f2174
AB
66 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
67 /* Do a read to set the internal dataRAMs to different data */
66b28183 68 err = mtdtest_read(mtd, addr0, bufsize, twopages);
abc173ad 69 if (err)
e73f2174 70 return err;
66b28183 71 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
abc173ad 72 if (err)
e73f2174 73 return err;
e73f2174 74 memset(twopages, 0, bufsize);
66b28183 75 err = mtdtest_read(mtd, addr, bufsize, twopages);
abc173ad 76 if (err)
e73f2174 77 break;
e73f2174 78 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
bb998419 79 pr_err("error: verify failed at %#llx\n",
e73f2174
AB
80 (long long)addr);
81 errcnt += 1;
82 }
83 }
84 /* Check boundary between eraseblocks */
85 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
825b8ccb
AM
86 struct rnd_state old_state = rnd_state;
87
e73f2174 88 /* Do a read to set the internal dataRAMs to different data */
66b28183 89 err = mtdtest_read(mtd, addr0, bufsize, twopages);
abc173ad 90 if (err)
e73f2174 91 return err;
66b28183 92 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
abc173ad 93 if (err)
e73f2174 94 return err;
e73f2174 95 memset(twopages, 0, bufsize);
66b28183 96 err = mtdtest_read(mtd, addr, bufsize, twopages);
abc173ad 97 if (err)
e73f2174 98 return err;
e73f2174 99 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
825b8ccb 100 prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
e73f2174 101 if (memcmp(twopages, boundary, bufsize)) {
bb998419 102 pr_err("error: verify failed at %#llx\n",
e73f2174
AB
103 (long long)addr);
104 errcnt += 1;
105 }
825b8ccb 106 rnd_state = old_state;
e73f2174
AB
107 }
108 return err;
109}
110
111static int crosstest(void)
112{
e73f2174
AB
113 int err = 0, i;
114 loff_t addr, addr0, addrn;
115 unsigned char *pp1, *pp2, *pp3, *pp4;
116
bb998419 117 pr_info("crosstest\n");
6396bb22 118 pp1 = kcalloc(pgsize, 4, GFP_KERNEL);
33777e66 119 if (!pp1)
e73f2174 120 return -ENOMEM;
e73f2174
AB
121 pp2 = pp1 + pgsize;
122 pp3 = pp2 + pgsize;
123 pp4 = pp3 + pgsize;
e73f2174
AB
124
125 addr0 = 0;
c6f7e7be 126 for (i = 0; i < ebcnt && bbt[i]; ++i)
e73f2174
AB
127 addr0 += mtd->erasesize;
128
129 addrn = mtd->size;
c6f7e7be 130 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
e73f2174
AB
131 addrn -= mtd->erasesize;
132
133 /* Read 2nd-to-last page to pp1 */
e73f2174 134 addr = addrn - pgsize - pgsize;
66b28183
AM
135 err = mtdtest_read(mtd, addr, pgsize, pp1);
136 if (err) {
e73f2174
AB
137 kfree(pp1);
138 return err;
139 }
140
141 /* Read 3rd-to-last page to pp1 */
e73f2174 142 addr = addrn - pgsize - pgsize - pgsize;
66b28183
AM
143 err = mtdtest_read(mtd, addr, pgsize, pp1);
144 if (err) {
e73f2174
AB
145 kfree(pp1);
146 return err;
147 }
148
149 /* Read first page to pp2 */
e73f2174 150 addr = addr0;
bb998419 151 pr_info("reading page at %#llx\n", (long long)addr);
66b28183
AM
152 err = mtdtest_read(mtd, addr, pgsize, pp2);
153 if (err) {
e73f2174
AB
154 kfree(pp1);
155 return err;
156 }
157
158 /* Read last page to pp3 */
e73f2174 159 addr = addrn - pgsize;
bb998419 160 pr_info("reading page at %#llx\n", (long long)addr);
66b28183
AM
161 err = mtdtest_read(mtd, addr, pgsize, pp3);
162 if (err) {
e73f2174
AB
163 kfree(pp1);
164 return err;
165 }
166
167 /* Read first page again to pp4 */
e73f2174 168 addr = addr0;
bb998419 169 pr_info("reading page at %#llx\n", (long long)addr);
66b28183
AM
170 err = mtdtest_read(mtd, addr, pgsize, pp4);
171 if (err) {
e73f2174
AB
172 kfree(pp1);
173 return err;
174 }
175
176 /* pp2 and pp4 should be the same */
bb998419 177 pr_info("verifying pages read at %#llx match\n",
e73f2174
AB
178 (long long)addr0);
179 if (memcmp(pp2, pp4, pgsize)) {
bb998419 180 pr_err("verify failed!\n");
e73f2174
AB
181 errcnt += 1;
182 } else if (!err)
bb998419 183 pr_info("crosstest ok\n");
e73f2174
AB
184 kfree(pp1);
185 return err;
186}
187
188static int erasecrosstest(void)
189{
7fc14bce 190 int err = 0, i, ebnum, ebnum2;
e73f2174
AB
191 loff_t addr0;
192 char *readbuf = twopages;
193
bb998419 194 pr_info("erasecrosstest\n");
e73f2174
AB
195
196 ebnum = 0;
197 addr0 = 0;
c6f7e7be 198 for (i = 0; i < ebcnt && bbt[i]; ++i) {
e73f2174
AB
199 addr0 += mtd->erasesize;
200 ebnum += 1;
201 }
202
203 ebnum2 = ebcnt - 1;
204 while (ebnum2 && bbt[ebnum2])
205 ebnum2 -= 1;
206
bb998419 207 pr_info("erasing block %d\n", ebnum);
66b28183 208 err = mtdtest_erase_eraseblock(mtd, ebnum);
e73f2174
AB
209 if (err)
210 return err;
211
bb998419 212 pr_info("writing 1st page of block %d\n", ebnum);
825b8ccb 213 prandom_bytes_state(&rnd_state, writebuf, pgsize);
e73f2174 214 strcpy(writebuf, "There is no data like this!");
66b28183 215 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
8a9f4aa3 216 if (err)
66b28183 217 return err;
e73f2174 218
bb998419 219 pr_info("reading 1st page of block %d\n", ebnum);
e73f2174 220 memset(readbuf, 0, pgsize);
66b28183 221 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
abc173ad 222 if (err)
66b28183 223 return err;
e73f2174 224
bb998419 225 pr_info("verifying 1st page of block %d\n", ebnum);
e73f2174 226 if (memcmp(writebuf, readbuf, pgsize)) {
bb998419 227 pr_err("verify failed!\n");
e73f2174 228 errcnt += 1;
7fc14bce 229 return -1;
e73f2174
AB
230 }
231
bb998419 232 pr_info("erasing block %d\n", ebnum);
66b28183 233 err = mtdtest_erase_eraseblock(mtd, ebnum);
e73f2174
AB
234 if (err)
235 return err;
236
bb998419 237 pr_info("writing 1st page of block %d\n", ebnum);
825b8ccb 238 prandom_bytes_state(&rnd_state, writebuf, pgsize);
e73f2174 239 strcpy(writebuf, "There is no data like this!");
66b28183 240 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
8a9f4aa3 241 if (err)
66b28183 242 return err;
e73f2174 243
bb998419 244 pr_info("erasing block %d\n", ebnum2);
66b28183 245 err = mtdtest_erase_eraseblock(mtd, ebnum2);
e73f2174
AB
246 if (err)
247 return err;
248
bb998419 249 pr_info("reading 1st page of block %d\n", ebnum);
e73f2174 250 memset(readbuf, 0, pgsize);
66b28183 251 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
abc173ad 252 if (err)
66b28183 253 return err;
e73f2174 254
bb998419 255 pr_info("verifying 1st page of block %d\n", ebnum);
e73f2174 256 if (memcmp(writebuf, readbuf, pgsize)) {
bb998419 257 pr_err("verify failed!\n");
e73f2174 258 errcnt += 1;
7fc14bce 259 return -1;
e73f2174
AB
260 }
261
7fc14bce 262 if (!err)
bb998419 263 pr_info("erasecrosstest ok\n");
e73f2174
AB
264 return err;
265}
266
267static int erasetest(void)
268{
e73f2174
AB
269 int err = 0, i, ebnum, ok = 1;
270 loff_t addr0;
271
bb998419 272 pr_info("erasetest\n");
e73f2174
AB
273
274 ebnum = 0;
275 addr0 = 0;
c6f7e7be 276 for (i = 0; i < ebcnt && bbt[i]; ++i) {
e73f2174
AB
277 addr0 += mtd->erasesize;
278 ebnum += 1;
279 }
280
bb998419 281 pr_info("erasing block %d\n", ebnum);
66b28183 282 err = mtdtest_erase_eraseblock(mtd, ebnum);
e73f2174
AB
283 if (err)
284 return err;
285
bb998419 286 pr_info("writing 1st page of block %d\n", ebnum);
825b8ccb 287 prandom_bytes_state(&rnd_state, writebuf, pgsize);
66b28183 288 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
8a9f4aa3 289 if (err)
66b28183 290 return err;
e73f2174 291
bb998419 292 pr_info("erasing block %d\n", ebnum);
66b28183 293 err = mtdtest_erase_eraseblock(mtd, ebnum);
e73f2174
AB
294 if (err)
295 return err;
296
bb998419 297 pr_info("reading 1st page of block %d\n", ebnum);
66b28183 298 err = mtdtest_read(mtd, addr0, pgsize, twopages);
abc173ad 299 if (err)
66b28183 300 return err;
e73f2174 301
bb998419 302 pr_info("verifying 1st page of block %d is all 0xff\n",
e73f2174
AB
303 ebnum);
304 for (i = 0; i < pgsize; ++i)
305 if (twopages[i] != 0xff) {
bb998419 306 pr_err("verifying all 0xff failed at %d\n",
e73f2174
AB
307 i);
308 errcnt += 1;
309 ok = 0;
310 break;
311 }
312
313 if (ok && !err)
bb998419 314 pr_info("erasetest ok\n");
e73f2174
AB
315
316 return err;
317}
318
e73f2174
AB
319static int __init mtd_pagetest_init(void)
320{
321 int err = 0;
322 uint64_t tmp;
323 uint32_t i;
324
325 printk(KERN_INFO "\n");
326 printk(KERN_INFO "=================================================\n");
7406060e
WS
327
328 if (dev < 0) {
064a7694 329 pr_info("Please specify a valid mtd-device via module parameter\n");
bb998419 330 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
7406060e
WS
331 return -EINVAL;
332 }
333
bb998419 334 pr_info("MTD device: %d\n", dev);
e73f2174
AB
335
336 mtd = get_mtd_device(NULL, dev);
337 if (IS_ERR(mtd)) {
338 err = PTR_ERR(mtd);
bb998419 339 pr_err("error: cannot get MTD device\n");
e73f2174
AB
340 return err;
341 }
342
818b9739 343 if (!mtd_type_is_nand(mtd)) {
bb998419 344 pr_info("this test requires NAND flash\n");
e73f2174
AB
345 goto out;
346 }
347
348 tmp = mtd->size;
349 do_div(tmp, mtd->erasesize);
350 ebcnt = tmp;
351 pgcnt = mtd->erasesize / mtd->writesize;
4c2b8a62 352 pgsize = mtd->writesize;
e73f2174 353
bb998419 354 pr_info("MTD device size %llu, eraseblock size %u, "
e73f2174
AB
355 "page size %u, count of eraseblocks %u, pages per "
356 "eraseblock %u, OOB size %u\n",
357 (unsigned long long)mtd->size, mtd->erasesize,
358 pgsize, ebcnt, pgcnt, mtd->oobsize);
359
360 err = -ENOMEM;
361 bufsize = pgsize * 2;
362 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
33777e66 363 if (!writebuf)
e73f2174 364 goto out;
e73f2174 365 twopages = kmalloc(bufsize, GFP_KERNEL);
33777e66 366 if (!twopages)
e73f2174 367 goto out;
e73f2174 368 boundary = kmalloc(bufsize, GFP_KERNEL);
33777e66 369 if (!boundary)
e73f2174 370 goto out;
e73f2174 371
66b28183
AM
372 bbt = kzalloc(ebcnt, GFP_KERNEL);
373 if (!bbt)
374 goto out;
375 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
e73f2174
AB
376 if (err)
377 goto out;
378
379 /* Erase all eraseblocks */
bb998419 380 pr_info("erasing whole device\n");
66b28183
AM
381 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
382 if (err)
383 goto out;
384 pr_info("erased %u eraseblocks\n", ebcnt);
e73f2174
AB
385
386 /* Write all eraseblocks */
825b8ccb 387 prandom_seed_state(&rnd_state, 1);
bb998419 388 pr_info("writing whole device\n");
e73f2174
AB
389 for (i = 0; i < ebcnt; ++i) {
390 if (bbt[i])
391 continue;
392 err = write_eraseblock(i);
393 if (err)
394 goto out;
395 if (i % 256 == 0)
bb998419 396 pr_info("written up to eraseblock %u\n", i);
2a6a28e7
RW
397
398 err = mtdtest_relax();
399 if (err)
400 goto out;
e73f2174 401 }
bb998419 402 pr_info("written %u eraseblocks\n", i);
e73f2174
AB
403
404 /* Check all eraseblocks */
825b8ccb 405 prandom_seed_state(&rnd_state, 1);
bb998419 406 pr_info("verifying all eraseblocks\n");
e73f2174
AB
407 for (i = 0; i < ebcnt; ++i) {
408 if (bbt[i])
409 continue;
410 err = verify_eraseblock(i);
411 if (err)
412 goto out;
413 if (i % 256 == 0)
bb998419 414 pr_info("verified up to eraseblock %u\n", i);
2a6a28e7
RW
415
416 err = mtdtest_relax();
417 if (err)
418 goto out;
e73f2174 419 }
bb998419 420 pr_info("verified %u eraseblocks\n", i);
e73f2174
AB
421
422 err = crosstest();
423 if (err)
424 goto out;
425
148a1a5d
SA
426 if (ebcnt > 1) {
427 err = erasecrosstest();
428 if (err)
429 goto out;
430 } else {
431 pr_info("skipping erasecrosstest, 2 erase blocks needed\n");
432 }
e73f2174
AB
433
434 err = erasetest();
435 if (err)
436 goto out;
437
bb998419 438 pr_info("finished with %d errors\n", errcnt);
e73f2174
AB
439out:
440
441 kfree(bbt);
442 kfree(boundary);
443 kfree(twopages);
444 kfree(writebuf);
445 put_mtd_device(mtd);
446 if (err)
bb998419 447 pr_info("error %d occurred\n", err);
e73f2174
AB
448 printk(KERN_INFO "=================================================\n");
449 return err;
450}
451module_init(mtd_pagetest_init);
452
453static void __exit mtd_pagetest_exit(void)
454{
455 return;
456}
457module_exit(mtd_pagetest_exit);
458
459MODULE_DESCRIPTION("NAND page test");
460MODULE_AUTHOR("Adrian Hunter");
461MODULE_LICENSE("GPL");