// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2023 Sean Anderson */ #include #include #include #include #include #include #include #include static int dm_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; } #define DM_NAND_TEST(dev) \ static int dm_test_nand##dev##_start(struct unit_test_state *uts) \ { \ return dm_test_nand(uts, dev, false); \ } \ DM_TEST(dm_test_nand##dev##_start, UT_TESTF_SCAN_FDT); \ static int dm_test_nand##dev##_end(struct unit_test_state *uts) \ { \ return dm_test_nand(uts, dev, true); \ } \ DM_TEST(dm_test_nand##dev##_end, UT_TESTF_SCAN_FDT) DM_NAND_TEST(0); DM_NAND_TEST(1);