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