env_mmc: add support for redundant environment
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@heimpold.de>
This commit is contained in:
		
							parent
							
								
									d2eae43ba8
								
							
						
					
					
						commit
						d196bd8803
					
				|  | @ -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; | ||||
|  |  | |||
							
								
								
									
										132
									
								
								common/env_mmc.c
								
								
								
								
							
							
						
						
									
										132
									
								
								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 | ||||
|  | @ -46,9 +51,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; | ||||
| } | ||||
| 
 | ||||
|  | @ -110,6 +119,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) | ||||
| { | ||||
| 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); | ||||
|  | @ -117,16 +130,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,7 +144,21 @@ int saveenv(void) | |||
| 	} | ||||
| 
 | ||||
| 	env_new->crc = crc32(0, &env_new->data[0], 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; | ||||
|  | @ -146,6 +168,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; | ||||
|  | @ -166,6 +192,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) | ||||
|  | @ -179,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; | ||||
| 	} | ||||
|  | @ -199,3 +312,4 @@ err: | |||
| 		set_default_env(NULL); | ||||
| #endif | ||||
| } | ||||
| #endif /* CONFIG_ENV_OFFSET_REDUND */ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue