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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
Tested-by: Lund Austin <Austin.Lund@xxxxxxxxxx>
Signed-off-by: Avri Altman <avri.altman@xxxxxxx>
---
 mmc_cmds.c | 36 +++++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

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;
 	}
 
 	/*
-- 
2.40.1




[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux