blob: c7e09850503eab63ade5488e3f1e5aa62f58eca3 [file] [log] [blame]
// 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);