mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v1 1/2] commands: mmc: add mmc-utils compatible enh_area set subcommand
@ 2026-06-17 10:34 Johannes Schneider
  2026-06-17 10:34 ` [PATCH v1 2/2] commands: mmc_extcsd: fix enhanced-area / GPP size display arithmetic Johannes Schneider
  2026-06-18  7:00 ` (subset) [PATCH v1 1/2] commands: mmc: add mmc-utils compatible enh_area set subcommand Sascha Hauer
  0 siblings, 2 replies; 5+ messages in thread
From: Johannes Schneider @ 2026-06-17 10:34 UTC (permalink / raw)
  To: barebox; +Cc: Johannes Schneider

Today "mmc enh_area /dev/mmcX" can only size the enhanced user data
area to the device-reported maximum (MAX_ENH_SIZE_MULT). For systems
that want a high-reliability prefix covering bootloader and system
images but keep the trailing user-data partition in default MLC/TLC
mode, an explicit size is required.

Extend the command with an "set" subcommand matching the Linux
mmc-utils ergonomics:

  mmc enh_area set [-c] <start_KiB> <length_KiB> /dev/mmcX

The length is rounded up to the device's enhanced-area unit
(HC_WP_GRP_SIZE * HC_ERASE_GRP_SIZE * 512 KiB) so a target region
is always fully covered, and validated against MAX_ENH_SIZE_MULT
before any EXT_CSD write. The actual provisioned size is printed.

The legacy "mmc enh_area [-c] /dev/mmcX" form keeps its existing
"fill the whole user area" behaviour.

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com>
---
 commands/mmc.c | 139 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 129 insertions(+), 10 deletions(-)

diff --git a/commands/mmc.c b/commands/mmc.c
index dafc3a755f..d379e6fea2 100644
--- a/commands/mmc.c
+++ b/commands/mmc.c
@@ -1,11 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
 #include <command.h>
+#include <errno.h>
 #include <mci.h>
 #include <stdio.h>
 #include <string.h>
 #include <getopt.h>
 #include <linux/kernel.h>
+#include <linux/kstrtox.h>
 #include <dma.h>
 
 static int mmc_enh_area_setmax(struct mci *mci, u8 *ext_csd)
@@ -56,6 +58,91 @@ static int mmc_enh_area_setmax(struct mci *mci, u8 *ext_csd)
 	return 0;
 }
 
+/*
+ * Provision a sized enhanced user data area at @start_kib of @length_kib
+ * bytes; length is rounded up to the device's WP-group unit. The one-shot
+ * PARTITION_SETTING_COMPLETED is not written here.
+ */
+static int mmc_enh_area_set(struct mci *mci, u8 *ext_csd,
+			    u64 start_kib, u64 length_kib)
+{
+	u32 hc_wp_grp = ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+	u32 hc_erase_grp = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+	u32 max_mult = (u32)ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT] |
+		       (u32)ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 1] << 8 |
+		       (u32)ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT + 2] << 16;
+	u64 unit_kib, start_sectors;
+	u32 size_mult;
+	int i, ret;
+
+	if (!hc_wp_grp || !hc_erase_grp) {
+		printf("Device reports zero HC_WP_GRP_SIZE / HC_ERASE_GRP_SIZE\n");
+		return -EINVAL;
+	}
+
+	/* JEDEC unit for ENH_START_ADDR / ENH_SIZE_MULT */
+	unit_kib = (u64)hc_wp_grp * hc_erase_grp * 512;
+
+	if (start_kib % unit_kib) {
+		printf("Start %llu KiB not a multiple of unit %llu KiB\n",
+		       (unsigned long long)start_kib,
+		       (unsigned long long)unit_kib);
+		return -EINVAL;
+	}
+
+	/* Round length up so the requested region is fully covered */
+	size_mult = (length_kib + unit_kib - 1) / unit_kib;
+
+	if (size_mult > max_mult) {
+		printf("Requested %llu KiB (mult=%u) exceeds MAX_ENH_SIZE_MULT=%u\n",
+		       (unsigned long long)length_kib, size_mult, max_mult);
+		return -EINVAL;
+	}
+
+	/* ENH_START_ADDR is in 512-byte sectors */
+	start_sectors = start_kib * 2;
+
+	ret = mci_switch(mci, EXT_CSD_ERASE_GROUP_DEF, 1);
+	if (ret) {
+		printf("Failure to write EXT_CSD_ERASE_GROUP_DEF\n");
+		return ret;
+	}
+
+	for (i = 0; i < 4; i++) {
+		ret = mci_switch(mci, EXT_CSD_ENH_START_ADDR + i,
+				 (start_sectors >> (8 * i)) & 0xff);
+		if (ret) {
+			printf("Failure to write EXT_CSD_ENH_START_ADDR[%d]\n", i);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < 3; i++) {
+		ret = mci_switch(mci, EXT_CSD_ENH_SIZE_MULT + i,
+				 (size_mult >> (8 * i)) & 0xff);
+		if (ret) {
+			printf("Failure to write EXT_CSD_ENH_SIZE_MULT[%d]\n", i);
+			return ret;
+		}
+	}
+
+	ret = mci_switch(mci, EXT_CSD_PARTITIONS_ATTRIBUTE,
+			 ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] |
+			 EXT_CSD_ENH_USR_MASK);
+	if (ret) {
+		printf("Failure to write EXT_CSD_PARTITIONS_ATTRIBUTE\n");
+		return ret;
+	}
+
+	printf("Enhanced user data area: start=%llu KiB, size=%llu KiB "
+	       "(mult=%u, unit=%llu KiB, max_mult=%u)\n",
+	       (unsigned long long)start_kib,
+	       (unsigned long long)size_mult * unit_kib,
+	       size_mult, (unsigned long long)unit_kib, max_mult);
+
+	return 0;
+}
+
 static int mmc_partitioning_complete(struct mci *mci)
 {
 	int ret;
@@ -67,16 +154,32 @@ static int mmc_partitioning_complete(struct mci *mci)
 	return ret;
 }
 
-/* enh_area [-c] /dev/mmcX */
+/*
+ * enh_area [-c] /dev/mmcX
+ *     -> fill the entire user area (legacy)
+ * enh_area set [-c] <start_KiB> <length_KiB> /dev/mmcX
+ *     -> sized, mmc-utils compatible
+ */
 static int do_mmc_enh_area(int argc, char *argv[])
 {
 	const char *devpath;
 	struct mci *mci;
 	u8 *ext_csd;
+	u64 start_kib = 0, length_kib = 0;
+	bool sized = false;
 	int set_completed = 0;
 	int opt;
 	int ret;
 
+	if (argc >= 2 && !strcmp(argv[1], "set")) {
+		sized = true;
+		/* Shift past "set" so getopt() and the trailing positional
+		 * arguments line up the same way as for the legacy form. */
+		argv++;
+		argc--;
+	}
+
+	optind = 1;
 	while ((opt = getopt(argc, argv, "c")) > 0) {
 		switch (opt) {
 		case 'c':
@@ -86,13 +189,25 @@ static int do_mmc_enh_area(int argc, char *argv[])
 		}
 	}
 
-	if (argc - optind != 1) {
-		printf("Usage: mmc enh_area [-c] /dev/mmcX\n");
-		return COMMAND_ERROR_USAGE;
+	if (sized) {
+		if (argc - optind != 3) {
+			printf("Usage: mmc enh_area set [-c] <start_KiB> <length_KiB> /dev/mmcX\n");
+			return COMMAND_ERROR_USAGE;
+		}
+		if (kstrtou64(argv[optind], 0, &start_kib) ||
+		    kstrtou64(argv[optind + 1], 0, &length_kib)) {
+			printf("Invalid start/length value\n");
+			return COMMAND_ERROR_USAGE;
+		}
+		devpath = argv[optind + 2];
+	} else {
+		if (argc - optind != 1) {
+			printf("Usage: mmc enh_area [-c] /dev/mmcX\n");
+			return COMMAND_ERROR_USAGE;
+		}
+		devpath = argv[optind];
 	}
 
-	devpath = argv[optind];
-
 	mci = mci_get_device_by_devpath(devpath);
 	if (!mci) {
 		printf("Failure to open %s as mci device\n", devpath);
@@ -113,7 +228,10 @@ static int do_mmc_enh_area(int argc, char *argv[])
 		goto error;
 	}
 
-	ret = mmc_enh_area_setmax(mci, ext_csd);
+	if (sized)
+		ret = mmc_enh_area_set(mci, ext_csd, start_kib, length_kib);
+	else
+		ret = mmc_enh_area_setmax(mci, ext_csd);
 	if (ret)
 		goto error;
 
@@ -273,8 +391,9 @@ static int do_mmc(int argc, char *argv[])
 BAREBOX_CMD_HELP_START(mmc)
 BAREBOX_CMD_HELP_TEXT("Modifies mmc properties.")
 BAREBOX_CMD_HELP_TEXT("")
-BAREBOX_CMD_HELP_TEXT("The subcommand enh_area creates an enhanced area of")
-BAREBOX_CMD_HELP_TEXT("maximal size.")
+BAREBOX_CMD_HELP_TEXT("Subcommand enh_area without arguments creates an enhanced")
+BAREBOX_CMD_HELP_TEXT("area of maximal size; enh_area set provisions a region of the")
+BAREBOX_CMD_HELP_TEXT("requested length (rounded up to the device's enhanced-area unit).")
 BAREBOX_CMD_HELP_TEXT("Note, with -c this is an irreversible action.")
 BAREBOX_CMD_HELP_OPT("-c", "complete partitioning (deprecated)")
 BAREBOX_CMD_HELP_TEXT("")
@@ -285,7 +404,7 @@ BAREBOX_CMD_HELP_END
 
 BAREBOX_CMD_START(mmc)
 	.cmd = do_mmc,
-	BAREBOX_CMD_OPTS("partition_complete|write_reliability|enh_area [-c] /dev/mmcX")
+	BAREBOX_CMD_OPTS("partition_complete|write_reliability|enh_area [set [-c] <start_KiB> <length_KiB>|[-c]] /dev/mmcX")
 	BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
 	BAREBOX_CMD_HELP(cmd_mmc_help)
 BAREBOX_CMD_END

base-commit: c92603e91031b09f28bff7b69f29fea89ee544b9
-- 
2.43.0




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-06-18  8:45 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-17 10:34 [PATCH v1 1/2] commands: mmc: add mmc-utils compatible enh_area set subcommand Johannes Schneider
2026-06-17 10:34 ` [PATCH v1 2/2] commands: mmc_extcsd: fix enhanced-area / GPP size display arithmetic Johannes Schneider
2026-06-17 10:51   ` Ahmad Fatoum
2026-06-18  7:00   ` (subset) " Sascha Hauer
2026-06-18  7:00 ` (subset) [PATCH v1 1/2] commands: mmc: add mmc-utils compatible enh_area set subcommand Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox