linux/drivers/mtd/tests/mtd_subpagetest.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006-2007 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 sub-page read and write on MTD device.
  18 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  19 *
  20 */
  21
  22#include <linux/init.h>
  23#include <linux/module.h>
  24#include <linux/moduleparam.h>
  25#include <linux/err.h>
  26#include <linux/mtd/mtd.h>
  27#include <linux/sched.h>
  28
  29#define PRINT_PREF KERN_INFO "mtd_subpagetest: "
  30
  31static int dev;
  32module_param(dev, int, S_IRUGO);
  33MODULE_PARM_DESC(dev, "MTD device number to use");
  34
  35static struct mtd_info *mtd;
  36static unsigned char *writebuf;
  37static unsigned char *readbuf;
  38static unsigned char *bbt;
  39
  40static int subpgsize;
  41static int bufsize;
  42static int ebcnt;
  43static int pgcnt;
  44static int errcnt;
  45static unsigned long next = 1;
  46
  47static inline unsigned int simple_rand(void)
  48{
  49        next = next * 1103515245 + 12345;
  50        return (unsigned int)((next / 65536) % 32768);
  51}
  52
  53static inline void simple_srand(unsigned long seed)
  54{
  55        next = seed;
  56}
  57
  58static void set_random_data(unsigned char *buf, size_t len)
  59{
  60        size_t i;
  61
  62        for (i = 0; i < len; ++i)
  63                buf[i] = simple_rand();
  64}
  65
  66static inline void clear_data(unsigned char *buf, size_t len)
  67{
  68        memset(buf, 0, len);
  69}
  70
  71static int erase_eraseblock(int ebnum)
  72{
  73        int err;
  74        struct erase_info ei;
  75        loff_t addr = ebnum * mtd->erasesize;
  76
  77        memset(&ei, 0, sizeof(struct erase_info));
  78        ei.mtd  = mtd;
  79        ei.addr = addr;
  80        ei.len  = mtd->erasesize;
  81
  82        err = mtd->erase(mtd, &ei);
  83        if (err) {
  84                printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
  85                return err;
  86        }
  87
  88        if (ei.state == MTD_ERASE_FAILED) {
  89                printk(PRINT_PREF "some erase error occurred at EB %d\n",
  90                       ebnum);
  91                return -EIO;
  92        }
  93
  94        return 0;
  95}
  96
  97static int erase_whole_device(void)
  98{
  99        int err;
 100        unsigned int i;
 101
 102        printk(PRINT_PREF "erasing whole device\n");
 103        for (i = 0; i < ebcnt; ++i) {
 104                if (bbt[i])
 105                        continue;
 106                err = erase_eraseblock(i);
 107                if (err)
 108                        return err;
 109                cond_resched();
 110        }
 111        printk(PRINT_PREF "erased %u eraseblocks\n", i);
 112        return 0;
 113}
 114
 115static int write_eraseblock(int ebnum)
 116{
 117        size_t written = 0;
 118        int err = 0;
 119        loff_t addr = ebnum * mtd->erasesize;
 120
 121        set_random_data(writebuf, subpgsize);
 122        err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
 123        if (unlikely(err || written != subpgsize)) {
 124                printk(PRINT_PREF "error: write failed at %#llx\n",
 125                       (long long)addr);
 126                if (written != subpgsize) {
 127                        printk(PRINT_PREF "  write size: %#x\n", subpgsize);
 128                        printk(PRINT_PREF "  written: %#zx\n", written);
 129                }
 130                return err ? err : -1;
 131        }
 132
 133        addr += subpgsize;
 134
 135        set_random_data(writebuf, subpgsize);
 136        err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
 137        if (unlikely(err || written != subpgsize)) {
 138                printk(PRINT_PREF "error: write failed at %#llx\n",
 139                       (long long)addr);
 140                if (written != subpgsize) {
 141                        printk(PRINT_PREF "  write size: %#x\n", subpgsize);
 142                        printk(PRINT_PREF "  written: %#zx\n", written);
 143                }
 144                return err ? err : -1;
 145        }
 146
 147        return err;
 148}
 149
 150static int write_eraseblock2(int ebnum)
 151{
 152        size_t written = 0;
 153        int err = 0, k;
 154        loff_t addr = ebnum * mtd->erasesize;
 155
 156        for (k = 1; k < 33; ++k) {
 157                if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
 158                        break;
 159                set_random_data(writebuf, subpgsize * k);
 160                err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf);
 161                if (unlikely(err || written != subpgsize * k)) {
 162                        printk(PRINT_PREF "error: write failed at %#llx\n",
 163                               (long long)addr);
 164                        if (written != subpgsize) {
 165                                printk(PRINT_PREF "  write size: %#x\n",
 166                                       subpgsize * k);
 167                                printk(PRINT_PREF "  written: %#08zx\n",
 168                                       written);
 169                        }
 170                        return err ? err : -1;
 171                }
 172                addr += subpgsize * k;
 173        }
 174
 175        return err;
 176}
 177
 178static void print_subpage(unsigned char *p)
 179{
 180        int i, j;
 181
 182        for (i = 0; i < subpgsize; ) {
 183                for (j = 0; i < subpgsize && j < 32; ++i, ++j)
 184                        printk("%02x", *p++);
 185                printk("\n");
 186        }
 187}
 188
 189static int verify_eraseblock(int ebnum)
 190{
 191        size_t read = 0;
 192        int err = 0;
 193        loff_t addr = ebnum * mtd->erasesize;
 194
 195        set_random_data(writebuf, subpgsize);
 196        clear_data(readbuf, subpgsize);
 197        read = 0;
 198        err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 199        if (unlikely(err || read != subpgsize)) {
 200                if (err == -EUCLEAN && read == subpgsize) {
 201                        printk(PRINT_PREF "ECC correction at %#llx\n",
 202                               (long long)addr);
 203                        err = 0;
 204                } else {
 205                        printk(PRINT_PREF "error: read failed at %#llx\n",
 206                               (long long)addr);
 207                        return err ? err : -1;
 208                }
 209        }
 210        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 211                printk(PRINT_PREF "error: verify failed at %#llx\n",
 212                       (long long)addr);
 213                printk(PRINT_PREF "------------- written----------------\n");
 214                print_subpage(writebuf);
 215                printk(PRINT_PREF "------------- read ------------------\n");
 216                print_subpage(readbuf);
 217                printk(PRINT_PREF "-------------------------------------\n");
 218                errcnt += 1;
 219        }
 220
 221        addr += subpgsize;
 222
 223        set_random_data(writebuf, subpgsize);
 224        clear_data(readbuf, subpgsize);
 225        read = 0;
 226        err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 227        if (unlikely(err || read != subpgsize)) {
 228                if (err == -EUCLEAN && read == subpgsize) {
 229                        printk(PRINT_PREF "ECC correction at %#llx\n",
 230                               (long long)addr);
 231                        err = 0;
 232                } else {
 233                        printk(PRINT_PREF "error: read failed at %#llx\n",
 234                               (long long)addr);
 235                        return err ? err : -1;
 236                }
 237        }
 238        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 239                printk(PRINT_PREF "error: verify failed at %#llx\n",
 240                       (long long)addr);
 241                printk(PRINT_PREF "------------- written----------------\n");
 242                print_subpage(writebuf);
 243                printk(PRINT_PREF "------------- read ------------------\n");
 244                print_subpage(readbuf);
 245                printk(PRINT_PREF "-------------------------------------\n");
 246                errcnt += 1;
 247        }
 248
 249        return err;
 250}
 251
 252static int verify_eraseblock2(int ebnum)
 253{
 254        size_t read = 0;
 255        int err = 0, k;
 256        loff_t addr = ebnum * mtd->erasesize;
 257
 258        for (k = 1; k < 33; ++k) {
 259                if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
 260                        break;
 261                set_random_data(writebuf, subpgsize * k);
 262                clear_data(readbuf, subpgsize * k);
 263                read = 0;
 264                err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);
 265                if (unlikely(err || read != subpgsize * k)) {
 266                        if (err == -EUCLEAN && read == subpgsize * k) {
 267                                printk(PRINT_PREF "ECC correction at %#llx\n",
 268                                       (long long)addr);
 269                                err = 0;
 270                        } else {
 271                                printk(PRINT_PREF "error: read failed at "
 272                                       "%#llx\n", (long long)addr);
 273                                return err ? err : -1;
 274                        }
 275                }
 276                if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
 277                        printk(PRINT_PREF "error: verify failed at %#llx\n",
 278                               (long long)addr);
 279                        errcnt += 1;
 280                }
 281                addr += subpgsize * k;
 282        }
 283
 284        return err;
 285}
 286
 287static int verify_eraseblock_ff(int ebnum)
 288{
 289        uint32_t j;
 290        size_t read = 0;
 291        int err = 0;
 292        loff_t addr = ebnum * mtd->erasesize;
 293
 294        memset(writebuf, 0xff, subpgsize);
 295        for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
 296                clear_data(readbuf, subpgsize);
 297                read = 0;
 298                err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 299                if (unlikely(err || read != subpgsize)) {
 300                        if (err == -EUCLEAN && read == subpgsize) {
 301                                printk(PRINT_PREF "ECC correction at %#llx\n",
 302                                       (long long)addr);
 303                                err = 0;
 304                        } else {
 305                                printk(PRINT_PREF "error: read failed at "
 306                                       "%#llx\n", (long long)addr);
 307                                return err ? err : -1;
 308                        }
 309                }
 310                if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 311                        printk(PRINT_PREF "error: verify 0xff failed at "
 312                               "%#llx\n", (long long)addr);
 313                        errcnt += 1;
 314                }
 315                addr += subpgsize;
 316        }
 317
 318        return err;
 319}
 320
 321static int verify_all_eraseblocks_ff(void)
 322{
 323        int err;
 324        unsigned int i;
 325
 326        printk(PRINT_PREF "verifying all eraseblocks for 0xff\n");
 327        for (i = 0; i < ebcnt; ++i) {
 328                if (bbt[i])
 329                        continue;
 330                err = verify_eraseblock_ff(i);
 331                if (err)
 332                        return err;
 333                if (i % 256 == 0)
 334                        printk(PRINT_PREF "verified up to eraseblock %u\n", i);
 335                cond_resched();
 336        }
 337        printk(PRINT_PREF "verified %u eraseblocks\n", i);
 338        return 0;
 339}
 340
 341static int is_block_bad(int ebnum)
 342{
 343        loff_t addr = ebnum * mtd->erasesize;
 344        int ret;
 345
 346        ret = mtd->block_isbad(mtd, addr);
 347        if (ret)
 348                printk(PRINT_PREF "block %d is bad\n", ebnum);
 349        return ret;
 350}
 351
 352static int scan_for_bad_eraseblocks(void)
 353{
 354        int i, bad = 0;
 355
 356        bbt = kmalloc(ebcnt, GFP_KERNEL);
 357        if (!bbt) {
 358                printk(PRINT_PREF "error: cannot allocate memory\n");
 359                return -ENOMEM;
 360        }
 361        memset(bbt, 0 , ebcnt);
 362
 363        printk(PRINT_PREF "scanning for bad eraseblocks\n");
 364        for (i = 0; i < ebcnt; ++i) {
 365                bbt[i] = is_block_bad(i) ? 1 : 0;
 366                if (bbt[i])
 367                        bad += 1;
 368                cond_resched();
 369        }
 370        printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
 371        return 0;
 372}
 373
 374static int __init mtd_subpagetest_init(void)
 375{
 376        int err = 0;
 377        uint32_t i;
 378        uint64_t tmp;
 379
 380        printk(KERN_INFO "\n");
 381        printk(KERN_INFO "=================================================\n");
 382        printk(PRINT_PREF "MTD device: %d\n", dev);
 383
 384        mtd = get_mtd_device(NULL, dev);
 385        if (IS_ERR(mtd)) {
 386                err = PTR_ERR(mtd);
 387                printk(PRINT_PREF "error: cannot get MTD device\n");
 388                return err;
 389        }
 390
 391        if (mtd->type != MTD_NANDFLASH) {
 392                printk(PRINT_PREF "this test requires NAND flash\n");
 393                goto out;
 394        }
 395
 396        subpgsize = mtd->writesize >> mtd->subpage_sft;
 397        printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
 398               "page size %u, subpage size %u, count of eraseblocks %u, "
 399               "pages per eraseblock %u, OOB size %u\n",
 400               (unsigned long long)mtd->size, mtd->erasesize,
 401               mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
 402
 403        err = -ENOMEM;
 404        bufsize = subpgsize * 32;
 405        writebuf = kmalloc(bufsize, GFP_KERNEL);
 406        if (!writebuf) {
 407                printk(PRINT_PREF "error: cannot allocate memory\n");
 408                goto out;
 409        }
 410        readbuf = kmalloc(bufsize, GFP_KERNEL);
 411        if (!readbuf) {
 412                printk(PRINT_PREF "error: cannot allocate memory\n");
 413                goto out;
 414        }
 415
 416        tmp = mtd->size;
 417        do_div(tmp, mtd->erasesize);
 418        ebcnt = tmp;
 419        pgcnt = mtd->erasesize / mtd->writesize;
 420
 421        err = scan_for_bad_eraseblocks();
 422        if (err)
 423                goto out;
 424
 425        err = erase_whole_device();
 426        if (err)
 427                goto out;
 428
 429        printk(PRINT_PREF "writing whole device\n");
 430        simple_srand(1);
 431        for (i = 0; i < ebcnt; ++i) {
 432                if (bbt[i])
 433                        continue;
 434                err = write_eraseblock(i);
 435                if (unlikely(err))
 436                        goto out;
 437                if (i % 256 == 0)
 438                        printk(PRINT_PREF "written up to eraseblock %u\n", i);
 439                cond_resched();
 440        }
 441        printk(PRINT_PREF "written %u eraseblocks\n", i);
 442
 443        simple_srand(1);
 444        printk(PRINT_PREF "verifying all eraseblocks\n");
 445        for (i = 0; i < ebcnt; ++i) {
 446                if (bbt[i])
 447                        continue;
 448                err = verify_eraseblock(i);
 449                if (unlikely(err))
 450                        goto out;
 451                if (i % 256 == 0)
 452                        printk(PRINT_PREF "verified up to eraseblock %u\n", i);
 453                cond_resched();
 454        }
 455        printk(PRINT_PREF "verified %u eraseblocks\n", i);
 456
 457        err = erase_whole_device();
 458        if (err)
 459                goto out;
 460
 461        err = verify_all_eraseblocks_ff();
 462        if (err)
 463                goto out;
 464
 465        /* Write all eraseblocks */
 466        simple_srand(3);
 467        printk(PRINT_PREF "writing whole device\n");
 468        for (i = 0; i < ebcnt; ++i) {
 469                if (bbt[i])
 470                        continue;
 471                err = write_eraseblock2(i);
 472                if (unlikely(err))
 473                        goto out;
 474                if (i % 256 == 0)
 475                        printk(PRINT_PREF "written up to eraseblock %u\n", i);
 476                cond_resched();
 477        }
 478        printk(PRINT_PREF "written %u eraseblocks\n", i);
 479
 480        /* Check all eraseblocks */
 481        simple_srand(3);
 482        printk(PRINT_PREF "verifying all eraseblocks\n");
 483        for (i = 0; i < ebcnt; ++i) {
 484                if (bbt[i])
 485                        continue;
 486                err = verify_eraseblock2(i);
 487                if (unlikely(err))
 488                        goto out;
 489                if (i % 256 == 0)
 490                        printk(PRINT_PREF "verified up to eraseblock %u\n", i);
 491                cond_resched();
 492        }
 493        printk(PRINT_PREF "verified %u eraseblocks\n", i);
 494
 495        err = erase_whole_device();
 496        if (err)
 497                goto out;
 498
 499        err = verify_all_eraseblocks_ff();
 500        if (err)
 501                goto out;
 502
 503        printk(PRINT_PREF "finished with %d errors\n", errcnt);
 504
 505out:
 506        kfree(bbt);
 507        kfree(readbuf);
 508        kfree(writebuf);
 509        put_mtd_device(mtd);
 510        if (err)
 511                printk(PRINT_PREF "error %d occurred\n", err);
 512        printk(KERN_INFO "=================================================\n");
 513        return err;
 514}
 515module_init(mtd_subpagetest_init);
 516
 517static void __exit mtd_subpagetest_exit(void)
 518{
 519        return;
 520}
 521module_exit(mtd_subpagetest_exit);
 522
 523MODULE_DESCRIPTION("Subpage test module");
 524MODULE_AUTHOR("Adrian Hunter");
 525MODULE_LICENSE("GPL");
 526