[U-Boot] [PATCH] env_mmc: add support for redundant environment

Michael Heimpold mhei at heimpold.de
Wed Apr 10 22:36:19 CEST 2013


This patch add support for storing the environment redundant on
mmc devices. Substantially it re-uses the logic from the NAND implementation,
that means using an incremental counter for marking newer data.

Signed-off-by: Michael Heimpold <mhei at heimpold.de>
---
 board/freescale/common/sdhc_boot.c |    2 +-
 common/env_mmc.c                   |  133 +++++++++++++++++++++++++++++++++---
 2 files changed, 124 insertions(+), 11 deletions(-)

diff --git a/board/freescale/common/sdhc_boot.c b/board/freescale/common/sdhc_boot.c
index e432318..fd0e910 100644
--- a/board/freescale/common/sdhc_boot.c
+++ b/board/freescale/common/sdhc_boot.c
@@ -32,7 +32,7 @@
 #define ESDHC_BOOT_IMAGE_SIZE	0x48
 #define ESDHC_BOOT_IMAGE_ADDR	0x50
 
-int mmc_get_env_addr(struct mmc *mmc, u32 *env_addr)
+int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
 {
 	u8 *tmp_buf;
 	u32 blklen, code_offset, code_len, n;
diff --git a/common/env_mmc.c b/common/env_mmc.c
index f568013..68f0530 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -32,6 +32,11 @@
 #include <search.h>
 #include <errno.h>
 
+#if defined(CONFIG_ENV_SIZE_REDUND) &&  \
+	(CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
+#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
+#endif
+
 char *env_name_spec = "MMC";
 
 #ifdef ENV_IS_EMBEDDED
@@ -48,9 +53,13 @@ DECLARE_GLOBAL_DATA_PTR;
 #define CONFIG_ENV_OFFSET 0
 #endif
 
-__weak int mmc_get_env_addr(struct mmc *mmc, u32 *env_addr)
+__weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
 {
 	*env_addr = CONFIG_ENV_OFFSET;
+#ifdef CONFIG_ENV_OFFSET_REDUND
+	if (copy)
+		*env_addr = CONFIG_ENV_OFFSET_REDUND;
+#endif
 	return 0;
 }
 
@@ -112,6 +121,10 @@ static inline int write_env(struct mmc *mmc, unsigned long size,
 	return (n == blk_cnt) ? 0 : -1;
 }
 
+#ifdef CONFIG_ENV_OFFSET_REDUND
+static unsigned char env_flags;
+#endif
+
 int saveenv(void)
 {
 	env_t *env_new = (env_t *)env_buf;
@@ -119,16 +132,11 @@ int saveenv(void)
 	char	*res;
 	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
 	u32	offset;
-	int	ret;
+	int	ret, copy = 0;
 
 	if (init_mmc_for_env(mmc))
 		return 1;
 
-	if (mmc_get_env_addr(mmc, &offset)) {
-		ret = 1;
-		goto fini;
-	}
-
 	res = (char *)env_new->data;
 	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
@@ -136,9 +144,22 @@ int saveenv(void)
 		ret = 1;
 		goto fini;
 	}
-
 	env_new->crc = crc32(0, env_new->data, ENV_SIZE);
-	printf("Writing to MMC(%d)... ", CONFIG_SYS_MMC_ENV_DEV);
+
+#ifdef CONFIG_ENV_OFFSET_REDUND
+	env_new->flags	= ++env_flags; /* increase the serial */
+
+	if (gd->env_valid == 1)
+		copy = 1;
+#endif
+
+	if (mmc_get_env_addr(mmc, copy, &offset)) {
+		ret = 1;
+		goto fini;
+	}
+
+	printf("Writing to %sMMC(%d)... ", copy ? "redundant " : "",
+	       CONFIG_SYS_MMC_ENV_DEV);
 	if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
 		puts("failed\n");
 		ret = 1;
@@ -148,6 +169,10 @@ int saveenv(void)
 	puts("done\n");
 	ret = 0;
 
+#ifdef CONFIG_ENV_OFFSET_REDUND
+	gd->env_valid = gd->env_valid == 2 ? 1 : 2;
+#endif
+
 fini:
 	fini_mmc_for_env(mmc);
 	return ret;
@@ -168,6 +193,93 @@ static inline int read_env(struct mmc *mmc, unsigned long size,
 	return (n == blk_cnt) ? 0 : -1;
 }
 
+#ifdef CONFIG_ENV_OFFSET_REDUND
+void env_relocate_spec(void)
+{
+#if !defined(ENV_IS_EMBEDDED)
+	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
+	u32 offset1, offset2;
+	int read1_fail = 0, read2_fail = 0;
+	int crc1_ok = 0, crc2_ok = 0;
+	env_t *ep, *tmp_env1, *tmp_env2;
+	int ret;
+
+	tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
+	tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
+	if (tmp_env1 == NULL || tmp_env2 == NULL) {
+		puts("Can't allocate buffers for environment\n");
+		ret = 1;
+		goto err;
+	}
+
+	if (init_mmc_for_env(mmc)) {
+		ret = 1;
+		goto err;
+	}
+
+	if (mmc_get_env_addr(mmc, 0, &offset1) ||
+	    mmc_get_env_addr(mmc, 1, &offset2)) {
+		ret = 1;
+		goto fini;
+	}
+
+	read1_fail = read_env(mmc, CONFIG_ENV_SIZE, offset1, tmp_env1);
+	read2_fail = read_env(mmc, CONFIG_ENV_SIZE, offset2, tmp_env2);
+
+	if (read1_fail && read2_fail)
+		puts("*** Error - No Valid Environment Area found\n");
+	else if (read1_fail || read2_fail)
+		puts("*** Warning - some problems detected "
+		     "reading environment; recovered successfully\n");
+
+	crc1_ok = !read1_fail &&
+		(crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
+	crc2_ok = !read2_fail &&
+		(crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
+
+	if (!crc1_ok && !crc2_ok) {
+		ret = 1;
+		goto fini;
+	} else if (crc1_ok && !crc2_ok) {
+		gd->env_valid = 1;
+	} else if (!crc1_ok && crc2_ok) {
+		gd->env_valid = 2;
+	} else {
+		/* both ok - check serial */
+		if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
+			gd->env_valid = 2;
+		else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
+			gd->env_valid = 1;
+		else if (tmp_env1->flags > tmp_env2->flags)
+			gd->env_valid = 1;
+		else if (tmp_env2->flags > tmp_env1->flags)
+			gd->env_valid = 2;
+		else /* flags are equal - almost impossible */
+			gd->env_valid = 1;
+	}
+
+	free(env_ptr);
+
+	if (gd->env_valid == 1)
+		ep = tmp_env1;
+	else
+		ep = tmp_env2;
+
+	env_flags = ep->flags;
+	env_import((char *)ep, 0);
+	ret = 0;
+
+fini:
+	fini_mmc_for_env(mmc);
+err:
+	if (ret)
+		set_default_env(NULL);
+
+	free(tmp_env1);
+	free(tmp_env2);
+#endif
+}
+#else /* ! CONFIG_ENV_OFFSET_REDUND */
 void env_relocate_spec(void)
 {
 #if !defined(ENV_IS_EMBEDDED)
@@ -180,7 +292,7 @@ void env_relocate_spec(void)
 		goto err;
 	}
 
-	if (mmc_get_env_addr(mmc, &offset)) {
+	if (mmc_get_env_addr(mmc, 0, &offset)) {
 		ret = 1;
 		goto fini;
 	}
@@ -200,3 +312,4 @@ err:
 		set_default_env(NULL);
 #endif
 }
+#endif /* CONFIG_ENV_OFFSET_REDUND */
-- 
1.7.10.4




More information about the U-Boot mailing list