diff options
| author | Tom Rini <trini@ti.com> | 2013-03-14 05:32:50 +0000 | 
|---|---|---|
| committer | Marek Vasut <marex@denx.de> | 2013-04-10 15:22:22 +0200 | 
| commit | c39d6a0ea57d57b53bd7fb8933874e1640e47888 (patch) | |
| tree | c3e91d95b7fa285301973278ca4cb2b31ab8c621 /common | |
| parent | a24c3155db20f979f9a0aa758d4665f221e470b9 (diff) | |
| download | olio-uboot-2014.01-c39d6a0ea57d57b53bd7fb8933874e1640e47888.tar.xz olio-uboot-2014.01-c39d6a0ea57d57b53bd7fb8933874e1640e47888.zip | |
nand: Extend nand_(read|write)_skip_bad with *actual and limit parameters
We make these two functions take a size_t pointer to how much space
was used on NAND to read or write the buffer (when reads/writes happen)
so that bad blocks can be accounted for.  We also make them take an
loff_t limit on how much data can be read or written.  This means that
we can now catch the case of when writing to a partition would exceed
the partition size due to bad blocks.  To do this we also need to make
check_skip_len count not just complete blocks used but partial ones as
well.  All callers of nand_(read|write)_skip_bad are adjusted to call
these with the most sensible limits available.
The changes were started by Pantelis and finished by Tom.
Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
Signed-off-by: Tom Rini <trini@ti.com>
Diffstat (limited to 'common')
| -rw-r--r-- | common/cmd_nand.c | 53 | ||||
| -rw-r--r-- | common/env_nand.c | 3 | 
2 files changed, 33 insertions, 23 deletions
| diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 32348f377..110c78c18 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -137,7 +137,8 @@ static inline int str2long(const char *p, ulong *num)  	return *p != '\0' && *endptr == '\0';  } -static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) +static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size, +		loff_t *maxsize)  {  #ifdef CONFIG_CMD_MTDPARTS  	struct mtd_device *dev; @@ -160,6 +161,7 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)  	*off = part->offset;  	*size = part->size; +	*maxsize = part->size;  	*idx = dev->id->num;  	ret = set_dev(*idx); @@ -173,10 +175,11 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)  #endif  } -static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) +static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size, +		loff_t *maxsize)  {  	if (!str2off(arg, off)) -		return get_part(arg, idx, off, maxsize); +		return get_part(arg, idx, off, size, maxsize);  	if (*off >= nand_info[*idx].size) {  		puts("Offset exceeds device limit\n"); @@ -184,36 +187,35 @@ static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize)  	}  	*maxsize = nand_info[*idx].size - *off; +	*size = *maxsize;  	return 0;  }  static int arg_off_size(int argc, char *const argv[], int *idx, -			loff_t *off, loff_t *size) +			loff_t *off, loff_t *size, loff_t *maxsize)  {  	int ret; -	loff_t maxsize = 0;  	if (argc == 0) {  		*off = 0;  		*size = nand_info[*idx].size; +		*maxsize = *size;  		goto print;  	} -	ret = arg_off(argv[0], idx, off, &maxsize); +	ret = arg_off(argv[0], idx, off, size, maxsize);  	if (ret)  		return ret; -	if (argc == 1) { -		*size = maxsize; +	if (argc == 1)  		goto print; -	}  	if (!str2off(argv[1], size)) {  		printf("'%s' is not a number\n", argv[1]);  		return -1;  	} -	if (*size > maxsize) { +	if (*size > *maxsize) {  		puts("Size exceeds partition or device limit\n");  		return -1;  	} @@ -307,7 +309,8 @@ int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[])  		if (argc < 3)  			goto usage; -		if (arg_off(argv[2], &idx, &addr, &maxsize)) { +		/* We don't care about size, or maxsize. */ +		if (arg_off(argv[2], &idx, &addr, &maxsize, &maxsize)) {  			puts("Offset or partition name expected\n");  			return 1;  		} @@ -426,7 +429,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  {  	int i, ret = 0;  	ulong addr; -	loff_t off, size; +	loff_t off, size, maxsize;  	char *cmd, *s;  	nand_info_t *nand;  #ifdef CONFIG_SYS_NAND_QUIET @@ -551,7 +554,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		printf("\nNAND %s: ", cmd);  		/* skip first two or three arguments, look for offset and size */ -		if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0) +		if (arg_off_size(argc - o, argv + o, &dev, &off, &size, +				 &maxsize) != 0)  			return 1;  		nand = &nand_info[dev]; @@ -619,7 +623,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		if (s && !strcmp(s, ".raw")) {  			raw = 1; -			if (arg_off(argv[3], &dev, &off, &size)) +			if (arg_off(argv[3], &dev, &off, &size, &maxsize))  				return 1;  			if (argc > 4 && !str2long(argv[4], &pagecount)) { @@ -635,7 +639,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  			rwsize = pagecount * (nand->writesize + nand->oobsize);  		} else {  			if (arg_off_size(argc - 3, argv + 3, &dev, -						&off, &size) != 0) +						&off, &size, &maxsize) != 0)  				return 1;  			rwsize = size; @@ -645,9 +649,11 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		    !strcmp(s, ".e") || !strcmp(s, ".i")) {  			if (read)  				ret = nand_read_skip_bad(nand, off, &rwsize, +							 NULL, maxsize,  							 (u_char *)addr);  			else  				ret = nand_write_skip_bad(nand, off, &rwsize, +							  NULL, maxsize,  							  (u_char *)addr, 0);  #ifdef CONFIG_CMD_NAND_TRIMFFS  		} else if (!strcmp(s, ".trimffs")) { @@ -655,8 +661,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  				printf("Unknown nand command suffix '%s'\n", s);  				return 1;  			} -			ret = nand_write_skip_bad(nand, off, &rwsize, -						(u_char *)addr, +			ret = nand_write_skip_bad(nand, off, &rwsize, NULL, +						maxsize, (u_char *)addr,  						WITH_DROP_FFS);  #endif  #ifdef CONFIG_CMD_NAND_YAFFS @@ -665,8 +671,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  				printf("Unknown nand command suffix '%s'.\n", s);  				return 1;  			} -			ret = nand_write_skip_bad(nand, off, &rwsize, -						(u_char *)addr, +			ret = nand_write_skip_bad(nand, off, &rwsize, NULL, +						maxsize, (u_char *)addr,  						WITH_INLINE_OOB);  #endif  		} else if (!strcmp(s, ".oob")) { @@ -775,7 +781,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  		if (s && !strcmp(s, ".allexcept"))  			allexcept = 1; -		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0) +		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size, +				 &maxsize) < 0)  			return 1;  		if (!nand_unlock(&nand_info[dev], off, size, allexcept)) { @@ -873,7 +880,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,  	printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset);  	cnt = nand->writesize; -	r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); +	r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, +			(u_char *)addr);  	if (r) {  		puts("** Read error\n");  		bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ); @@ -905,7 +913,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,  	}  	bootstage_mark(BOOTSTAGE_ID_NAND_TYPE); -	r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); +	r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, +			(u_char *)addr);  	if (r) {  		puts("** Read error\n");  		bootstage_error(BOOTSTAGE_ID_NAND_READ); diff --git a/common/env_nand.c b/common/env_nand.c index 5b69889c0..b745822be 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -281,7 +281,8 @@ int readenv(size_t offset, u_char *buf)  		} else {  			char_ptr = &buf[amount_loaded];  			if (nand_read_skip_bad(&nand_info[0], offset, -					       &len, char_ptr)) +					       &len, NULL, +					       nand_info[0].size, char_ptr))  				return 1;  			offset += blocksize; |