mtd_is_aligned_with_block_size() divides by mtd->erasesize, which a device of type MTD_RAM does not have, so "mtd read", "mtd write", "mtd dump" and "mtd erase" all end in a division by zero.
Take a missing erase size as "nothing to align to", and refuse an erase on the condition mtd_erase() refuses on, before the line announcing it divides through mtd_div_by_eb(). The test sits in test/cmd/ as the mtd command walks a global list that outlives the device tree a driver model test replaces. Signed-off-by: Heiko Schocher <[email protected]> --- checkpatch asks for a blank line after the test function, before the CMD_TEST() that registers it. But in test/cmd/ all over is without a blank line, so ignore this warning. Changes in v3: - New patch. Patch 1 only covers mtd_erase(), the mtd command divides by the erase size before it ever gets there. MAINTAINERS | 1 + cmd/mtd.c | 14 +++++++++ test/cmd/Makefile | 3 ++ test/cmd/mtd.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 test/cmd/mtd.c diff --git a/MAINTAINERS b/MAINTAINERS index f3fe3597d6e..83d040b3e75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1668,6 +1668,7 @@ M: Heiko Schocher <[email protected]> S: Maintained F: drivers/mtd/devices/mchp23k256.c F: drivers/mtd/devices/mchp23k256_sandbox.c +F: test/cmd/mtd.c F: test/dm/mchp23k256.c SPI-NOR diff --git a/cmd/mtd.c b/cmd/mtd.c index ed827accfb5..1f3a9ad0779 100644 --- a/cmd/mtd.c +++ b/cmd/mtd.c @@ -53,6 +53,10 @@ static bool mtd_is_aligned_with_min_io_size(struct mtd_info *mtd, u64 size) static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size) { + /* A device with no erase blocks, a RAM say, has nothing to align to */ + if (!mtd->erasesize) + return true; + return !do_div(size, mtd->erasesize); } @@ -642,6 +646,16 @@ static int do_mtd_erase(struct cmd_tbl *cmdtp, int flag, int argc, if (IS_ERR_OR_NULL(mtd)) return CMD_RET_FAILURE; + /* + * The same condition mtd_erase() refuses on. Every step below works + * in units of the erase size, so there is nothing to do here either. + */ + if (!mtd->erasesize || !mtd->_erase) { + printf("%s cannot erase\n", mtd->name); + ret = CMD_RET_FAILURE; + goto out_put_mtd; + } + scrub = strstr(argv[0], ".dontskipbad"); argc -= 2; diff --git a/test/cmd/Makefile b/test/cmd/Makefile index e734933d5f7..4afd83d836f 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -28,6 +28,9 @@ obj-$(CONFIG_CMD_LOADM) += loadm.o obj-$(CONFIG_CMD_MEMINFO) += meminfo.o obj-$(CONFIG_CMD_MEMORY) += mem_copy.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o +ifdef CONFIG_CMD_MTD +obj-$(CONFIG_MTD_MCHP23K256_SANDBOX) += mtd.o +endif obj-$(CONFIG_CMD_PART) += part.o ifdef CONFIG_CMD_PCI obj-$(CONFIG_CMD_PCI_MPS) += pci_mps.o diff --git a/test/cmd/mtd.c b/test/cmd/mtd.c new file mode 100644 index 00000000000..a17377bc570 --- /dev/null +++ b/test/cmd/mtd.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for the mtd command on a device without an erase size + * + * Copyright (C) 2026 Heiko Schocher, Nabla Software Engineering <[email protected]> + */ + +#include <command.h> +#include <console.h> +#include <dm.h> +#include <mapmem.h> +#include <mtd.h> +#include <dm/test.h> +#include <linux/mtd/mtd.h> +#include <test/cmd.h> +#include <test/test.h> +#include <test/ut.h> + +/* The SPI SRAM of the test device tree, an MTD device of type MTD_RAM */ +#define MTD_RAM_PATH "/spi@1/sram@0" + +#define MTD_RAM_SRC 0x0 +#define MTD_RAM_DST 0x100 + +/* Neither offset nor length is a multiple of any usual erase block */ +#define MTD_RAM_OFFSET 0x1f +#define MTD_RAM_LEN 0x64 + +static int cmd_test_mtd_ram(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mtd_info *mtd; + u8 *out, *in; + int i; + + ut_assertok(uclass_get_device_by_ofnode(UCLASS_MTD, + ofnode_path(MTD_RAM_PATH), + &dev)); + mtd = dev_get_uclass_priv(dev); + ut_asserteq(0, mtd->erasesize); + + /* + * The first MTD command probes all devices, so output from other + * drivers during probing is irrelevant to this test. + */ + ut_assertok(run_command("mtd list", 0)); + console_record_reset(); + + out = map_sysmem(MTD_RAM_SRC, MTD_RAM_LEN); + in = map_sysmem(MTD_RAM_DST, MTD_RAM_LEN); + for (i = 0; i < MTD_RAM_LEN; i++) + out[i] = 0x5a + i; + memset(in, 0, MTD_RAM_LEN); + + ut_assertok(run_commandf("mtd write %s 0x%x 0x%x 0x%x", mtd->name, + MTD_RAM_SRC, MTD_RAM_OFFSET, MTD_RAM_LEN)); + ut_assert_nextline("Writing %d byte(s) at offset 0x%08x", MTD_RAM_LEN, + MTD_RAM_OFFSET); + ut_assert_console_end(); + + ut_assertok(run_commandf("mtd read %s 0x%x 0x%x 0x%x", mtd->name, + MTD_RAM_DST, MTD_RAM_OFFSET, MTD_RAM_LEN)); + ut_assert_nextline("Reading %d byte(s) at offset 0x%08x", MTD_RAM_LEN, + MTD_RAM_OFFSET); + ut_assert_console_end(); + ut_asserteq_mem(out, in, MTD_RAM_LEN); + + /* The erase has to be refused, not divided by the missing block size */ + ut_asserteq(1, run_commandf("mtd erase %s 0x%x 0x%x", mtd->name, + MTD_RAM_OFFSET, MTD_RAM_LEN)); + ut_assert_nextline("%s cannot erase", mtd->name); + ut_assert_console_end(); + + unmap_sysmem(in); + unmap_sysmem(out); + + return 0; +} +CMD_TEST(cmd_test_mtd_ram, UTF_CONSOLE); -- 2.55.0
