diff mbox series

[5/6] mmc-utils: ffu: Allow ffu of large images

Message ID 20230625103814.105-6-avri.altman@wdc.com
State New
Headers show
Series mmc-utils: ffu: ffu of large images | expand

Commit Message

Avri Altman June 25, 2023, 10:38 a.m. UTC
ffu is done using a single multi-ioctl to carry the entire firmware
image. This is limiting the fw image size to be at most 512KB, as the
mmc driver restricts each single ioc data to be at most
MMC_IOC_MAX_BYTES.

the spec however, allows the fw image to be written using multiple write
commands.

To overcome this limitation, if the fw image is larger than 512KB,
split it into a series of 512KB chunks.

fixes: 1b8b13beb424 (mmc-utils: let FFU mode use CMD23 and CMD25)
Reported-by: Lund Austin <Austin.Lund@garmin.com>
Tested-by: Lund Austin <Austin.Lund@garmin.com>
Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 mmc_cmds.c | 36 +++++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/mmc_cmds.c b/mmc_cmds.c
index 0321118..a1adbde 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -2831,7 +2831,7 @@  int do_ffu(int nargs, char **argv)
 	unsigned int sect_size;
 	__u8 ext_csd[512];
 	__u8 *buf = NULL;
-	off_t fw_size;
+	off_t fw_size, bytes_left, off;
 	char *device;
 	struct mmc_ioc_multi_cmd *multi_cmd = NULL;
 
@@ -2877,7 +2877,7 @@  int do_ffu(int nargs, char **argv)
 	}
 
 	fw_size = lseek(img_fd, 0, SEEK_END);
-	if (fw_size > MMC_IOC_MAX_BYTES || fw_size == 0) {
+	if (fw_size == 0) {
 		fprintf(stderr, "Wrong firmware size");
 		goto out;
 	}
@@ -2906,8 +2906,6 @@  int do_ffu(int nargs, char **argv)
 	fill_switch_cmd(&multi_cmd->cmds[0], EXT_CSD_MODE_CONFIG,
 			EXT_CSD_FFU_MODE);
 
-	set_ffu_single_cmd(multi_cmd, ext_csd, fw_size, buf, 0);
-
 	/* return device into normal mode */
 	fill_switch_cmd(&multi_cmd->cmds[3], EXT_CSD_MODE_CONFIG,
 			EXT_CSD_NORMAL_MODE);
@@ -2921,14 +2919,30 @@  int do_ffu(int nargs, char **argv)
 	}
 
 do_retry:
-	/* send ioctl with multi-cmd */
-	ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);
+	bytes_left = fw_size;
+	off = 0;
+	while (bytes_left) {
+		unsigned int chunk_size = bytes_left < MMC_IOC_MAX_BYTES ?
+					  bytes_left : MMC_IOC_MAX_BYTES;
 
-	if (ret) {
-		perror("Multi-cmd ioctl");
-		/* In case multi-cmd ioctl failed before exiting from ffu mode */
-		ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[3]);
-		goto out;
+		/* prepare multi_cmd for FFU based on cmd to be used */
+		set_ffu_single_cmd(multi_cmd, ext_csd, chunk_size, buf, off);
+
+		/* send ioctl with multi-cmd */
+		ret = ioctl(dev_fd, MMC_IOC_MULTI_CMD, multi_cmd);
+
+		if (ret) {
+			perror("Multi-cmd ioctl");
+			/*
+			 * In case multi-cmd ioctl failed before exiting from
+			 * ffu mode
+			 */
+			ioctl(dev_fd, MMC_IOC_CMD, &multi_cmd->cmds[3]);
+			goto out;
+		}
+
+		bytes_left -= chunk_size;
+		off += chunk_size;
 	}
 
 	/*