Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> */ #include <nand.h> #include <part.h> #include <rand.h> #include <dm/test.h> #include <test/test.h> #include <test/ut.h> #include <linux/mtd/mtd.h> #include <linux/mtd/rawnand.h> static int run_test_nand(struct unit_test_state *uts, int dev, bool end) { nand_erase_options_t opts = { }; struct mtd_info *mtd; size_t length; loff_t size; char *buf; int *gold; u8 oob[NAND_MAX_OOBSIZE]; int i; loff_t off = 0; mtd_oob_ops_t ops = { }; /* Seed RNG for bit errors */ srand((off >> 32) ^ off ^ ~dev); mtd = get_nand_dev_by_index(dev); ut_assertnonnull(mtd); size = mtd->erasesize * 4; length = size; buf = malloc(size); ut_assertnonnull(buf); gold = malloc(size); ut_assertnonnull(gold); /* Mark a block as bad */ ut_assertok(mtd_block_markbad(mtd, off + mtd->erasesize)); /* Erase some stuff */ if (end) off = mtd->size - size - mtd->erasesize; opts.offset = off; opts.length = size; opts.spread = 1; opts.lim = U32_MAX; ut_assertok(nand_erase_opts(mtd, &opts)); /* Make sure everything is erased */ memset(gold, 0xff, size); ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf)); ut_asserteq(size, length); ut_asserteq_mem(gold, buf, size); /* ...but our bad block marker is still there */ ops.oobbuf = oob; ops.ooblen = mtd->oobsize; ut_assertok(mtd_read_oob(mtd, mtd->erasesize, &ops)); ut_asserteq(0, oob[mtd_to_nand(mtd)->badblockpos]); /* Generate some data and write it */ for (i = 0; i < size / sizeof(int); i++) gold[i] = rand(); ut_assertok(nand_write_skip_bad(mtd, off, &length, NULL, U64_MAX, (void *)gold, 0)); ut_asserteq(size, length); /* Verify */ ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf)); ut_asserteq(size, length); ut_asserteq_mem(gold, buf, size); /* Erase some blocks */ memset(((char *)gold) + mtd->erasesize, 0xff, mtd->erasesize * 2); opts.offset = off + mtd->erasesize; opts.length = mtd->erasesize * 2; ut_assertok(nand_erase_opts(mtd, &opts)); /* Verify */ ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf)); ut_asserteq(size, length); ut_asserteq_mem(gold, buf, size); return 0; } static int dm_test_nand0_start(struct unit_test_state *uts) { ut_assertok(run_test_nand(uts, 0, false)); return 0; } DM_TEST(dm_test_nand0_start, UTF_SCAN_FDT); static int dm_test_nand1_start(struct unit_test_state *uts) { ut_assertok(run_test_nand(uts, 1, false)); return 0; } DM_TEST(dm_test_nand1_start, UTF_SCAN_FDT); static int dm_test_nand0_end(struct unit_test_state *uts) { ut_assertok(run_test_nand(uts, 0, true)); return 0; } DM_TEST(dm_test_nand0_end, UTF_SCAN_FDT); static int dm_test_nand1_end(struct unit_test_state *uts) { ut_assertok(run_test_nand(uts, 1, true)); return 0; } DM_TEST(dm_test_nand1_end, UTF_SCAN_FDT); |