blob: 0b992fdce1c91746ece91212b5d1e29c652f9718 [file] [log] [blame]
Sean Andersonbc8e8a42023-11-04 16:37:52 -04001// 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);