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