pagetest.c (10390B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2006-2008 Nokia Corporation 4 * 5 * Test page read and write on MTD device. 6 * 7 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 8 */ 9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 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> 18#include <linux/slab.h> 19#include <linux/sched.h> 20#include <linux/random.h> 21 22#include "mtd_test.h" 23 24static int dev = -EINVAL; 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; 39static struct rnd_state rnd_state; 40 41static int write_eraseblock(int ebnum) 42{ 43 loff_t addr = (loff_t)ebnum * mtd->erasesize; 44 45 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); 46 cond_resched(); 47 return mtdtest_write(mtd, addr, mtd->erasesize, writebuf); 48} 49 50static int verify_eraseblock(int ebnum) 51{ 52 uint32_t j; 53 int err = 0, i; 54 loff_t addr0, addrn; 55 loff_t addr = (loff_t)ebnum * mtd->erasesize; 56 57 addr0 = 0; 58 for (i = 0; i < ebcnt && bbt[i]; ++i) 59 addr0 += mtd->erasesize; 60 61 addrn = mtd->size; 62 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i) 63 addrn -= mtd->erasesize; 64 65 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); 66 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { 67 /* Do a read to set the internal dataRAMs to different data */ 68 err = mtdtest_read(mtd, addr0, bufsize, twopages); 69 if (err) 70 return err; 71 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages); 72 if (err) 73 return err; 74 memset(twopages, 0, bufsize); 75 err = mtdtest_read(mtd, addr, bufsize, twopages); 76 if (err) 77 break; 78 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { 79 pr_err("error: verify failed at %#llx\n", 80 (long long)addr); 81 errcnt += 1; 82 } 83 } 84 /* Check boundary between eraseblocks */ 85 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) { 86 struct rnd_state old_state = rnd_state; 87 88 /* Do a read to set the internal dataRAMs to different data */ 89 err = mtdtest_read(mtd, addr0, bufsize, twopages); 90 if (err) 91 return err; 92 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages); 93 if (err) 94 return err; 95 memset(twopages, 0, bufsize); 96 err = mtdtest_read(mtd, addr, bufsize, twopages); 97 if (err) 98 return err; 99 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); 100 prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize); 101 if (memcmp(twopages, boundary, bufsize)) { 102 pr_err("error: verify failed at %#llx\n", 103 (long long)addr); 104 errcnt += 1; 105 } 106 rnd_state = old_state; 107 } 108 return err; 109} 110 111static int crosstest(void) 112{ 113 int err = 0, i; 114 loff_t addr, addr0, addrn; 115 unsigned char *pp1, *pp2, *pp3, *pp4; 116 117 pr_info("crosstest\n"); 118 pp1 = kcalloc(pgsize, 4, GFP_KERNEL); 119 if (!pp1) 120 return -ENOMEM; 121 pp2 = pp1 + pgsize; 122 pp3 = pp2 + pgsize; 123 pp4 = pp3 + pgsize; 124 125 addr0 = 0; 126 for (i = 0; i < ebcnt && bbt[i]; ++i) 127 addr0 += mtd->erasesize; 128 129 addrn = mtd->size; 130 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i) 131 addrn -= mtd->erasesize; 132 133 /* Read 2nd-to-last page to pp1 */ 134 addr = addrn - pgsize - pgsize; 135 err = mtdtest_read(mtd, addr, pgsize, pp1); 136 if (err) { 137 kfree(pp1); 138 return err; 139 } 140 141 /* Read 3rd-to-last page to pp1 */ 142 addr = addrn - pgsize - pgsize - pgsize; 143 err = mtdtest_read(mtd, addr, pgsize, pp1); 144 if (err) { 145 kfree(pp1); 146 return err; 147 } 148 149 /* Read first page to pp2 */ 150 addr = addr0; 151 pr_info("reading page at %#llx\n", (long long)addr); 152 err = mtdtest_read(mtd, addr, pgsize, pp2); 153 if (err) { 154 kfree(pp1); 155 return err; 156 } 157 158 /* Read last page to pp3 */ 159 addr = addrn - pgsize; 160 pr_info("reading page at %#llx\n", (long long)addr); 161 err = mtdtest_read(mtd, addr, pgsize, pp3); 162 if (err) { 163 kfree(pp1); 164 return err; 165 } 166 167 /* Read first page again to pp4 */ 168 addr = addr0; 169 pr_info("reading page at %#llx\n", (long long)addr); 170 err = mtdtest_read(mtd, addr, pgsize, pp4); 171 if (err) { 172 kfree(pp1); 173 return err; 174 } 175 176 /* pp2 and pp4 should be the same */ 177 pr_info("verifying pages read at %#llx match\n", 178 (long long)addr0); 179 if (memcmp(pp2, pp4, pgsize)) { 180 pr_err("verify failed!\n"); 181 errcnt += 1; 182 } else if (!err) 183 pr_info("crosstest ok\n"); 184 kfree(pp1); 185 return err; 186} 187 188static int erasecrosstest(void) 189{ 190 int err = 0, i, ebnum, ebnum2; 191 loff_t addr0; 192 char *readbuf = twopages; 193 194 pr_info("erasecrosstest\n"); 195 196 ebnum = 0; 197 addr0 = 0; 198 for (i = 0; i < ebcnt && bbt[i]; ++i) { 199 addr0 += mtd->erasesize; 200 ebnum += 1; 201 } 202 203 ebnum2 = ebcnt - 1; 204 while (ebnum2 && bbt[ebnum2]) 205 ebnum2 -= 1; 206 207 pr_info("erasing block %d\n", ebnum); 208 err = mtdtest_erase_eraseblock(mtd, ebnum); 209 if (err) 210 return err; 211 212 pr_info("writing 1st page of block %d\n", ebnum); 213 prandom_bytes_state(&rnd_state, writebuf, pgsize); 214 strcpy(writebuf, "There is no data like this!"); 215 err = mtdtest_write(mtd, addr0, pgsize, writebuf); 216 if (err) 217 return err; 218 219 pr_info("reading 1st page of block %d\n", ebnum); 220 memset(readbuf, 0, pgsize); 221 err = mtdtest_read(mtd, addr0, pgsize, readbuf); 222 if (err) 223 return err; 224 225 pr_info("verifying 1st page of block %d\n", ebnum); 226 if (memcmp(writebuf, readbuf, pgsize)) { 227 pr_err("verify failed!\n"); 228 errcnt += 1; 229 return -1; 230 } 231 232 pr_info("erasing block %d\n", ebnum); 233 err = mtdtest_erase_eraseblock(mtd, ebnum); 234 if (err) 235 return err; 236 237 pr_info("writing 1st page of block %d\n", ebnum); 238 prandom_bytes_state(&rnd_state, writebuf, pgsize); 239 strcpy(writebuf, "There is no data like this!"); 240 err = mtdtest_write(mtd, addr0, pgsize, writebuf); 241 if (err) 242 return err; 243 244 pr_info("erasing block %d\n", ebnum2); 245 err = mtdtest_erase_eraseblock(mtd, ebnum2); 246 if (err) 247 return err; 248 249 pr_info("reading 1st page of block %d\n", ebnum); 250 memset(readbuf, 0, pgsize); 251 err = mtdtest_read(mtd, addr0, pgsize, readbuf); 252 if (err) 253 return err; 254 255 pr_info("verifying 1st page of block %d\n", ebnum); 256 if (memcmp(writebuf, readbuf, pgsize)) { 257 pr_err("verify failed!\n"); 258 errcnt += 1; 259 return -1; 260 } 261 262 if (!err) 263 pr_info("erasecrosstest ok\n"); 264 return err; 265} 266 267static int erasetest(void) 268{ 269 int err = 0, i, ebnum, ok = 1; 270 loff_t addr0; 271 272 pr_info("erasetest\n"); 273 274 ebnum = 0; 275 addr0 = 0; 276 for (i = 0; i < ebcnt && bbt[i]; ++i) { 277 addr0 += mtd->erasesize; 278 ebnum += 1; 279 } 280 281 pr_info("erasing block %d\n", ebnum); 282 err = mtdtest_erase_eraseblock(mtd, ebnum); 283 if (err) 284 return err; 285 286 pr_info("writing 1st page of block %d\n", ebnum); 287 prandom_bytes_state(&rnd_state, writebuf, pgsize); 288 err = mtdtest_write(mtd, addr0, pgsize, writebuf); 289 if (err) 290 return err; 291 292 pr_info("erasing block %d\n", ebnum); 293 err = mtdtest_erase_eraseblock(mtd, ebnum); 294 if (err) 295 return err; 296 297 pr_info("reading 1st page of block %d\n", ebnum); 298 err = mtdtest_read(mtd, addr0, pgsize, twopages); 299 if (err) 300 return err; 301 302 pr_info("verifying 1st page of block %d is all 0xff\n", 303 ebnum); 304 for (i = 0; i < pgsize; ++i) 305 if (twopages[i] != 0xff) { 306 pr_err("verifying all 0xff failed at %d\n", 307 i); 308 errcnt += 1; 309 ok = 0; 310 break; 311 } 312 313 if (ok && !err) 314 pr_info("erasetest ok\n"); 315 316 return err; 317} 318 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"); 327 328 if (dev < 0) { 329 pr_info("Please specify a valid mtd-device via module parameter\n"); 330 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 331 return -EINVAL; 332 } 333 334 pr_info("MTD device: %d\n", dev); 335 336 mtd = get_mtd_device(NULL, dev); 337 if (IS_ERR(mtd)) { 338 err = PTR_ERR(mtd); 339 pr_err("error: cannot get MTD device\n"); 340 return err; 341 } 342 343 if (!mtd_type_is_nand(mtd)) { 344 pr_info("this test requires NAND flash\n"); 345 goto out; 346 } 347 348 tmp = mtd->size; 349 do_div(tmp, mtd->erasesize); 350 ebcnt = tmp; 351 pgcnt = mtd->erasesize / mtd->writesize; 352 pgsize = mtd->writesize; 353 354 pr_info("MTD device size %llu, eraseblock size %u, " 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); 363 if (!writebuf) 364 goto out; 365 twopages = kmalloc(bufsize, GFP_KERNEL); 366 if (!twopages) 367 goto out; 368 boundary = kmalloc(bufsize, GFP_KERNEL); 369 if (!boundary) 370 goto out; 371 372 bbt = kzalloc(ebcnt, GFP_KERNEL); 373 if (!bbt) 374 goto out; 375 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 376 if (err) 377 goto out; 378 379 /* Erase all eraseblocks */ 380 pr_info("erasing whole device\n"); 381 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 382 if (err) 383 goto out; 384 pr_info("erased %u eraseblocks\n", ebcnt); 385 386 /* Write all eraseblocks */ 387 prandom_seed_state(&rnd_state, 1); 388 pr_info("writing whole device\n"); 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) 396 pr_info("written up to eraseblock %u\n", i); 397 398 err = mtdtest_relax(); 399 if (err) 400 goto out; 401 } 402 pr_info("written %u eraseblocks\n", i); 403 404 /* Check all eraseblocks */ 405 prandom_seed_state(&rnd_state, 1); 406 pr_info("verifying all eraseblocks\n"); 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) 414 pr_info("verified up to eraseblock %u\n", i); 415 416 err = mtdtest_relax(); 417 if (err) 418 goto out; 419 } 420 pr_info("verified %u eraseblocks\n", i); 421 422 err = crosstest(); 423 if (err) 424 goto out; 425 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 } 433 434 err = erasetest(); 435 if (err) 436 goto out; 437 438 pr_info("finished with %d errors\n", errcnt); 439out: 440 441 kfree(bbt); 442 kfree(boundary); 443 kfree(twopages); 444 kfree(writebuf); 445 put_mtd_device(mtd); 446 if (err) 447 pr_info("error %d occurred\n", err); 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");