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