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

Reply via email to