linux/drivers/mtd/tests/subpagetest.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2006-2007 Nokia Corporation
   4 *
   5 * Test sub-page read and write on MTD device.
   6 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
   7 */
   8
   9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10
  11#include <linux/init.h>
  12#include <linux/module.h>
  13#include <linux/moduleparam.h>
  14#include <linux/err.h>
  15#include <linux/mtd/mtd.h>
  16#include <linux/slab.h>
  17#include <linux/sched.h>
  18#include <linux/random.h>
  19
  20#include "mtd_test.h"
  21
  22static int dev = -EINVAL;
  23module_param(dev, int, S_IRUGO);
  24MODULE_PARM_DESC(dev, "MTD device number to use");
  25
  26static struct mtd_info *mtd;
  27static unsigned char *writebuf;
  28static unsigned char *readbuf;
  29static unsigned char *bbt;
  30
  31static int subpgsize;
  32static int bufsize;
  33static int ebcnt;
  34static int pgcnt;
  35static int errcnt;
  36static struct rnd_state rnd_state;
  37
  38static inline void clear_data(unsigned char *buf, size_t len)
  39{
  40        memset(buf, 0, len);
  41}
  42
  43static int write_eraseblock(int ebnum)
  44{
  45        size_t written;
  46        int err = 0;
  47        loff_t addr = (loff_t)ebnum * mtd->erasesize;
  48
  49        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
  50        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
  51        if (unlikely(err || written != subpgsize)) {
  52                pr_err("error: write failed at %#llx\n",
  53                       (long long)addr);
  54                if (written != subpgsize) {
  55                        pr_err("  write size: %#x\n", subpgsize);
  56                        pr_err("  written: %#zx\n", written);
  57                }
  58                return err ? err : -1;
  59        }
  60
  61        addr += subpgsize;
  62
  63        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
  64        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
  65        if (unlikely(err || written != subpgsize)) {
  66                pr_err("error: write failed at %#llx\n",
  67                       (long long)addr);
  68                if (written != subpgsize) {
  69                        pr_err("  write size: %#x\n", subpgsize);
  70                        pr_err("  written: %#zx\n", written);
  71                }
  72                return err ? err : -1;
  73        }
  74
  75        return err;
  76}
  77
  78static int write_eraseblock2(int ebnum)
  79{
  80        size_t written;
  81        int err = 0, k;
  82        loff_t addr = (loff_t)ebnum * mtd->erasesize;
  83
  84        for (k = 1; k < 33; ++k) {
  85                if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
  86                        break;
  87                prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
  88                err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
  89                if (unlikely(err || written != subpgsize * k)) {
  90                        pr_err("error: write failed at %#llx\n",
  91                               (long long)addr);
  92                        if (written != subpgsize * k) {
  93                                pr_err("  write size: %#x\n",
  94                                       subpgsize * k);
  95                                pr_err("  written: %#08zx\n",
  96                                       written);
  97                        }
  98                        return err ? err : -1;
  99                }
 100                addr += subpgsize * k;
 101        }
 102
 103        return err;
 104}
 105
 106static void print_subpage(unsigned char *p)
 107{
 108        int i, j;
 109
 110        for (i = 0; i < subpgsize; ) {
 111                for (j = 0; i < subpgsize && j < 32; ++i, ++j)
 112                        printk("%02x", *p++);
 113                printk("\n");
 114        }
 115}
 116
 117static int verify_eraseblock(int ebnum)
 118{
 119        size_t read;
 120        int err = 0;
 121        loff_t addr = (loff_t)ebnum * mtd->erasesize;
 122
 123        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
 124        clear_data(readbuf, subpgsize);
 125        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
 126        if (unlikely(err || read != subpgsize)) {
 127                if (mtd_is_bitflip(err) && read == subpgsize) {
 128                        pr_info("ECC correction at %#llx\n",
 129                               (long long)addr);
 130                        err = 0;
 131                } else {
 132                        pr_err("error: read failed at %#llx\n",
 133                               (long long)addr);
 134                        return err ? err : -1;
 135                }
 136        }
 137        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 138                pr_err("error: verify failed at %#llx\n",
 139                       (long long)addr);
 140                pr_info("------------- written----------------\n");
 141                print_subpage(writebuf);
 142                pr_info("------------- read ------------------\n");
 143                print_subpage(readbuf);
 144                pr_info("-------------------------------------\n");
 145                errcnt += 1;
 146        }
 147
 148        addr += subpgsize;
 149
 150        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
 151        clear_data(readbuf, subpgsize);
 152        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
 153        if (unlikely(err || read != subpgsize)) {
 154                if (mtd_is_bitflip(err) && read == subpgsize) {
 155                        pr_info("ECC correction at %#llx\n",
 156                               (long long)addr);
 157                        err = 0;
 158                } else {
 159                        pr_err("error: read failed at %#llx\n",
 160                               (long long)addr);
 161                        return err ? err : -1;
 162                }
 163        }
 164        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 165                pr_info("error: verify failed at %#llx\n",
 166                       (long long)addr);
 167                pr_info("------------- written----------------\n");
 168                print_subpage(writebuf);
 169                pr_info("------------- read ------------------\n");
 170                print_subpage(readbuf);
 171                pr_info("-------------------------------------\n");
 172                errcnt += 1;
 173        }
 174
 175        return err;
 176}
 177
 178static int verify_eraseblock2(int ebnum)
 179{
 180        size_t read;
 181        int err = 0, k;
 182        loff_t addr = (loff_t)ebnum * mtd->erasesize;
 183
 184        for (k = 1; k < 33; ++k) {
 185                if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
 186                        break;
 187                prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
 188                clear_data(readbuf, subpgsize * k);
 189                err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
 190                if (unlikely(err || read != subpgsize * k)) {
 191                        if (mtd_is_bitflip(err) && read == subpgsize * k) {
 192                                pr_info("ECC correction at %#llx\n",
 193                                       (long long)addr);
 194                                err = 0;
 195                        } else {
 196                                pr_err("error: read failed at "
 197                                       "%#llx\n", (long long)addr);
 198                                return err ? err : -1;
 199                        }
 200                }
 201                if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
 202                        pr_err("error: verify failed at %#llx\n",
 203                               (long long)addr);
 204                        errcnt += 1;
 205                }
 206                addr += subpgsize * k;
 207        }
 208
 209        return err;
 210}
 211
 212static int verify_eraseblock_ff(int ebnum)
 213{
 214        uint32_t j;
 215        size_t read;
 216        int err = 0;
 217        loff_t addr = (loff_t)ebnum * mtd->erasesize;
 218
 219        memset(writebuf, 0xff, subpgsize);
 220        for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
 221                clear_data(readbuf, subpgsize);
 222                err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
 223                if (unlikely(err || read != subpgsize)) {
 224                        if (mtd_is_bitflip(err) && read == subpgsize) {
 225                                pr_info("ECC correction at %#llx\n",
 226                                       (long long)addr);
 227                                err = 0;
 228                        } else {
 229                                pr_err("error: read failed at "
 230                                       "%#llx\n", (long long)addr);
 231                                return err ? err : -1;
 232                        }
 233                }
 234                if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 235                        pr_err("error: verify 0xff failed at "
 236                               "%#llx\n", (long long)addr);
 237                        errcnt += 1;
 238                }
 239                addr += subpgsize;
 240        }
 241
 242        return err;
 243}
 244
 245static int verify_all_eraseblocks_ff(void)
 246{
 247        int err;
 248        unsigned int i;
 249
 250        pr_info("verifying all eraseblocks for 0xff\n");
 251        for (i = 0; i < ebcnt; ++i) {
 252                if (bbt[i])
 253                        continue;
 254                err = verify_eraseblock_ff(i);
 255                if (err)
 256                        return err;
 257                if (i % 256 == 0)
 258                        pr_info("verified up to eraseblock %u\n", i);
 259
 260                err = mtdtest_relax();
 261                if (err)
 262                        return err;
 263        }
 264        pr_info("verified %u eraseblocks\n", i);
 265        return 0;
 266}
 267
 268static int __init mtd_subpagetest_init(void)
 269{
 270        int err = 0;
 271        uint32_t i;
 272        uint64_t tmp;
 273
 274        printk(KERN_INFO "\n");
 275        printk(KERN_INFO "=================================================\n");
 276
 277        if (dev < 0) {
 278                pr_info("Please specify a valid mtd-device via module parameter\n");
 279                pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
 280                return -EINVAL;
 281        }
 282
 283        pr_info("MTD device: %d\n", dev);
 284
 285        mtd = get_mtd_device(NULL, dev);
 286        if (IS_ERR(mtd)) {
 287                err = PTR_ERR(mtd);
 288                pr_err("error: cannot get MTD device\n");
 289                return err;
 290        }
 291
 292        if (!mtd_type_is_nand(mtd)) {
 293                pr_info("this test requires NAND flash\n");
 294                goto out;
 295        }
 296
 297        subpgsize = mtd->writesize >> mtd->subpage_sft;
 298        tmp = mtd->size;
 299        do_div(tmp, mtd->erasesize);
 300        ebcnt = tmp;
 301        pgcnt = mtd->erasesize / mtd->writesize;
 302
 303        pr_info("MTD device size %llu, eraseblock size %u, "
 304               "page size %u, subpage size %u, count of eraseblocks %u, "
 305               "pages per eraseblock %u, OOB size %u\n",
 306               (unsigned long long)mtd->size, mtd->erasesize,
 307               mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
 308
 309        err = -ENOMEM;
 310        bufsize = subpgsize * 32;
 311        writebuf = kmalloc(bufsize, GFP_KERNEL);
 312        if (!writebuf)
 313                goto out;
 314        readbuf = kmalloc(bufsize, GFP_KERNEL);
 315        if (!readbuf)
 316                goto out;
 317        bbt = kzalloc(ebcnt, GFP_KERNEL);
 318        if (!bbt)
 319                goto out;
 320
 321        err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
 322        if (err)
 323                goto out;
 324
 325        err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 326        if (err)
 327                goto out;
 328
 329        pr_info("writing whole device\n");
 330        prandom_seed_state(&rnd_state, 1);
 331        for (i = 0; i < ebcnt; ++i) {
 332                if (bbt[i])
 333                        continue;
 334                err = write_eraseblock(i);
 335                if (unlikely(err))
 336                        goto out;
 337                if (i % 256 == 0)
 338                        pr_info("written up to eraseblock %u\n", i);
 339
 340                err = mtdtest_relax();
 341                if (err)
 342                        goto out;
 343        }
 344        pr_info("written %u eraseblocks\n", i);
 345
 346        prandom_seed_state(&rnd_state, 1);
 347        pr_info("verifying all eraseblocks\n");
 348        for (i = 0; i < ebcnt; ++i) {
 349                if (bbt[i])
 350                        continue;
 351                err = verify_eraseblock(i);
 352                if (unlikely(err))
 353                        goto out;
 354                if (i % 256 == 0)
 355                        pr_info("verified up to eraseblock %u\n", i);
 356
 357                err = mtdtest_relax();
 358                if (err)
 359                        goto out;
 360        }
 361        pr_info("verified %u eraseblocks\n", i);
 362
 363        err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 364        if (err)
 365                goto out;
 366
 367        err = verify_all_eraseblocks_ff();
 368        if (err)
 369                goto out;
 370
 371        /* Write all eraseblocks */
 372        prandom_seed_state(&rnd_state, 3);
 373        pr_info("writing whole device\n");
 374        for (i = 0; i < ebcnt; ++i) {
 375                if (bbt[i])
 376                        continue;
 377                err = write_eraseblock2(i);
 378                if (unlikely(err))
 379                        goto out;
 380                if (i % 256 == 0)
 381                        pr_info("written up to eraseblock %u\n", i);
 382
 383                err = mtdtest_relax();
 384                if (err)
 385                        goto out;
 386        }
 387        pr_info("written %u eraseblocks\n", i);
 388
 389        /* Check all eraseblocks */
 390        prandom_seed_state(&rnd_state, 3);
 391        pr_info("verifying all eraseblocks\n");
 392        for (i = 0; i < ebcnt; ++i) {
 393                if (bbt[i])
 394                        continue;
 395                err = verify_eraseblock2(i);
 396                if (unlikely(err))
 397                        goto out;
 398                if (i % 256 == 0)
 399                        pr_info("verified up to eraseblock %u\n", i);
 400
 401                err = mtdtest_relax();
 402                if (err)
 403                        goto out;
 404        }
 405        pr_info("verified %u eraseblocks\n", i);
 406
 407        err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 408        if (err)
 409                goto out;
 410
 411        err = verify_all_eraseblocks_ff();
 412        if (err)
 413                goto out;
 414
 415        pr_info("finished with %d errors\n", errcnt);
 416
 417out:
 418        kfree(bbt);
 419        kfree(readbuf);
 420        kfree(writebuf);
 421        put_mtd_device(mtd);
 422        if (err)
 423                pr_info("error %d occurred\n", err);
 424        printk(KERN_INFO "=================================================\n");
 425        return err;
 426}
 427module_init(mtd_subpagetest_init);
 428
 429static void __exit mtd_subpagetest_exit(void)
 430{
 431        return;
 432}
 433module_exit(mtd_subpagetest_exit);
 434
 435MODULE_DESCRIPTION("Subpage test module");
 436MODULE_AUTHOR("Adrian Hunter");
 437MODULE_LICENSE("GPL");
 438