X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=common%2Fenv_nand.c;h=695a9eebb01e68e3f11a7a545d96ac68507eebbc;hb=2475e634758577baad4a54f4585c7fa9a638ae73;hp=4e8307aa3332d67cc43dfd178ef5451e3d711377;hpb=2e6e1772c0e34871769be4aef79748fe3e47d953;p=karo-tx-uboot.git diff --git a/common/env_nand.c b/common/env_nand.c index 4e8307aa33..695a9eebb0 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -11,27 +11,9 @@ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH * Andreas Heppel * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ -#define DEBUG - #include #include #include @@ -44,10 +26,11 @@ #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND) #define CMD_SAVEENV #elif defined(CONFIG_ENV_OFFSET_REDUND) -#error Cannot use CONFIG_ENV_OFFSET_REDUND without CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND +#error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND #endif -#if defined(CONFIG_ENV_SIZE_REDUND) && (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE) +#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 @@ -55,28 +38,18 @@ #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE #endif -/* references to names in env_common.c */ -extern uchar default_environment[]; - char *env_name_spec = "NAND"; - #if defined(ENV_IS_EMBEDDED) -extern uchar environment[]; -env_t *env_ptr = (env_t *)(&environment[0]); +env_t *env_ptr = &environment; #elif defined(CONFIG_NAND_ENV_DST) env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST; #else /* ! ENV_IS_EMBEDDED */ -env_t *env_ptr = 0; +env_t *env_ptr; #endif /* ENV_IS_EMBEDDED */ DECLARE_GLOBAL_DATA_PTR; -uchar env_get_char_spec (int index) -{ - return ( *((uchar *)(gd->env_addr + index)) ); -} - /* * This is called before nand_init() so we can't read NAND to * validate env data. @@ -99,16 +72,14 @@ int env_init(void) env_t *tmp_env2; tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE); - crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc); + crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc; #endif - tmp_env1 = env_ptr; - - crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc); + crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc; if (!crc1_ok && !crc2_ok) { - gd->env_addr = 0; - gd->env_valid = 0; + gd->env_addr = 0; + gd->env_valid = 0; return 0; } else if (crc1_ok && !crc2_ok) { @@ -119,13 +90,13 @@ int env_init(void) gd->env_valid = 2; } else { /* both ok - check serial */ - if(tmp_env1->flags == 255 && tmp_env2->flags == 0) + if (tmp_env1->flags == 255 && tmp_env2->flags == 0) gd->env_valid = 2; - else if(tmp_env2->flags == 255 && tmp_env1->flags == 0) + else if (tmp_env2->flags == 255 && tmp_env1->flags == 0) gd->env_valid = 1; - else if(tmp_env1->flags > tmp_env2->flags) + else if (tmp_env1->flags > tmp_env2->flags) gd->env_valid = 1; - else if(tmp_env2->flags > tmp_env1->flags) + else if (tmp_env2->flags > tmp_env1->flags) gd->env_valid = 2; else /* flags are equal - almost impossible */ gd->env_valid = 1; @@ -141,11 +112,11 @@ int env_init(void) gd->env_addr = (ulong)env_ptr->data; #else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ - gd->env_addr = (ulong)&default_environment[0]; - gd->env_valid = 1; + gd->env_addr = (ulong)&default_environment[0]; + gd->env_valid = 1; #endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ - return (0); + return 0; } #ifdef CMD_SAVEENV @@ -158,7 +129,6 @@ int writeenv(size_t offset, u_char *buf) size_t end = offset + CONFIG_ENV_RANGE; size_t amount_saved = 0; size_t blocksize, len; - u_char *char_ptr; blocksize = nand_info[0].erasesize; @@ -169,9 +139,9 @@ int writeenv(size_t offset, u_char *buf) offset += blocksize; } else { char_ptr = &buf[amount_saved]; - if (nand_write(&nand_info[0], offset, &len, - char_ptr)) + if (nand_write(&nand_info[0], offset, &len, char_ptr)) return 1; + offset += blocksize; amount_saved += len; } @@ -181,115 +151,104 @@ int writeenv(size_t offset, u_char *buf) return 0; } -#ifdef CONFIG_ENV_OFFSET_REDUND -int saveenv(void) -{ - env_t env_new; - ssize_t len; - char *res; - int ret = 0; - nand_erase_options_t nand_erase_options; - nand_erase_options.length = CONFIG_ENV_RANGE; - nand_erase_options.quiet = 0; - nand_erase_options.jffs2 = 0; - nand_erase_options.scrub = 0; +struct env_location { + const char *name; + const nand_erase_options_t erase_opts; +}; - if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) - return 1; +static int erase_and_write_env(const struct env_location *location, + u_char *env_new) +{ + int ret = 0; - res = (char *)&env_new.data; - len = hexport('\0', &res, ENV_SIZE); - if (len < 0) { - error("Cannot export environment: errno = %d\n", errno); - return 1; - } - env_new.crc = crc32(0, env_new.data, ENV_SIZE); - env_new.flags = ACTIVE_FLAG; - - if(gd->env_valid == 1) { - puts("Erasing redundant NAND...\n"); - nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; - if (nand_erase_opts(&nand_info[0], &nand_erase_options)) - return 1; - - puts("Writing to redundant NAND... "); - ret = writeenv(CONFIG_ENV_OFFSET_REDUND, - (u_char *)&env_new); - } else { - puts("Erasing NAND...\n"); - nand_erase_options.offset = CONFIG_ENV_OFFSET; - if (nand_erase_opts(&nand_info[0], &nand_erase_options)) - return 1; - - puts("Writing to NAND... "); - ret = writeenv(CONFIG_ENV_OFFSET, - (u_char *)&env_new); - } - if (ret) { - puts("FAILED!\n"); + printf("Erasing %s...\n", location->name); + if (nand_erase_opts(&nand_info[0], &location->erase_opts)) return 1; - } - puts("done\n"); - - gd->env_valid = (gd->env_valid == 2 ? 1 : 2); + printf("Writing to %s... ", location->name); + ret = writeenv(location->erase_opts.offset, env_new); + puts(ret ? "FAILED!\n" : "OK\n"); return ret; } -#else /* ! CONFIG_ENV_OFFSET_REDUND */ + +#ifdef CONFIG_ENV_OFFSET_REDUND +static unsigned char env_flags; +#endif + int saveenv(void) { - int ret = 0; - env_t env_new; + int ret = 0; + ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); ssize_t len; char *res; - nand_erase_options_t nand_erase_options; + int env_idx = 0; + static const struct env_location location[] = { + { + .name = "NAND", + .erase_opts = { + .length = CONFIG_ENV_RANGE, + .offset = CONFIG_ENV_OFFSET, + }, + }, +#ifdef CONFIG_ENV_OFFSET_REDUND + { + .name = "redundant NAND", + .erase_opts = { + .length = CONFIG_ENV_RANGE, + .offset = CONFIG_ENV_OFFSET_REDUND, + }, + }, +#endif + }; - nand_erase_options.length = CONFIG_ENV_RANGE; - nand_erase_options.quiet = 0; - nand_erase_options.jffs2 = 0; - nand_erase_options.scrub = 0; - nand_erase_options.offset = CONFIG_ENV_OFFSET; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; - res = (char *)&env_new.data; - len = hexport('\0', &res, ENV_SIZE); + res = (char *)&env_new->data; + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; } - env_new.crc = crc32(0, env_new.data, ENV_SIZE); - - puts("Erasing Nand...\n"); - if (nand_erase_opts(&nand_info[0], &nand_erase_options)) - return 1; + env_new->crc = crc32(0, env_new->data, ENV_SIZE); +#ifdef CONFIG_ENV_OFFSET_REDUND + env_new->flags = ++env_flags; /* increase the serial */ + env_idx = (gd->env_valid == 1); +#endif - puts("Writing to Nand... "); - if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) { - puts("FAILED!\n"); - return 1; + ret = erase_and_write_env(&location[env_idx], (u_char *)env_new); +#ifdef CONFIG_ENV_OFFSET_REDUND + if (!ret) { + /* preset other copy for next write */ + gd->env_valid = gd->env_valid == 2 ? 1 : 2; + return ret; } - puts("done\n"); + env_idx = (env_idx + 1) & 1; + ret = erase_and_write_env(&location[env_idx], (u_char *)env_new); + if (!ret) + printf("Warning: primary env write failed," + " redundancy is lost!\n"); +#endif + return ret; } -#endif /* CONFIG_ENV_OFFSET_REDUND */ #endif /* CMD_SAVEENV */ -int readenv(size_t offset, u_char * buf) +int readenv(size_t offset, u_char *buf) { size_t end = offset + CONFIG_ENV_RANGE; size_t amount_loaded = 0; size_t blocksize, len; - u_char *char_ptr; blocksize = nand_info[0].erasesize; if (!blocksize) return 1; + len = min(blocksize, CONFIG_ENV_SIZE); while (amount_loaded < CONFIG_ENV_SIZE && offset < end) { @@ -297,12 +256,16 @@ int readenv(size_t offset, u_char * buf) offset += blocksize; } else { char_ptr = &buf[amount_loaded]; - if (nand_read(&nand_info[0], offset, &len, char_ptr)) + if (nand_read_skip_bad(&nand_info[0], offset, + &len, NULL, + nand_info[0].size, char_ptr)) return 1; + offset += blocksize; amount_loaded += len; } } + if (amount_loaded != CONFIG_ENV_SIZE) return 1; @@ -313,14 +276,14 @@ int readenv(size_t offset, u_char * buf) int get_nand_env_oob(nand_info_t *nand, unsigned long *result) { struct mtd_oob_ops ops; - uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)]; + uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)]; int ret; - ops.datbuf = NULL; - ops.mode = MTD_OOB_AUTO; - ops.ooboffs = 0; - ops.ooblen = ENV_OFFSET_SIZE; - ops.oobbuf = (void *) oob_buf; + ops.datbuf = NULL; + ops.mode = MTD_OOB_AUTO; + ops.ooboffs = 0; + ops.ooblen = ENV_OFFSET_SIZE; + ops.oobbuf = (void *)oob_buf; ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops); if (ret) { @@ -345,34 +308,35 @@ int get_nand_env_oob(nand_info_t *nand, unsigned long *result) void env_relocate_spec(void) { #if !defined(ENV_IS_EMBEDDED) + int read1_fail = 0, read2_fail = 0; int crc1_ok = 0, crc2_ok = 0; env_t *ep, *tmp_env1, *tmp_env2; tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE); tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE); - - if ((tmp_env1 == NULL) || (tmp_env2 == NULL)) { + if (tmp_env1 == NULL || tmp_env2 == NULL) { puts("Can't allocate buffers for environment\n"); - free(tmp_env1); - free(tmp_env2); set_default_env("!malloc() failed"); - return; + goto done; } - if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1)) - puts("No Valid Environment Area found\n"); + read1_fail = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1); + read2_fail = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2); - if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2)) - puts("No Valid Redundant Environment Area found\n"); + 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 = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc); - crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc); + 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) { - free(tmp_env1); - free(tmp_env2); set_default_env("!bad CRC"); - return; + goto done; } else if (crc1_ok && !crc2_ok) { gd->env_valid = 1; } else if (!crc1_ok && crc2_ok) { @@ -389,7 +353,6 @@ void env_relocate_spec(void) gd->env_valid = 2; else /* flags are equal - almost impossible */ gd->env_valid = 1; - } free(env_ptr); @@ -399,8 +362,10 @@ void env_relocate_spec(void) else ep = tmp_env2; + env_flags = ep->flags; env_import((char *)ep, 0); +done: free(tmp_env1); free(tmp_env2); @@ -412,11 +377,11 @@ void env_relocate_spec(void) * device i.e., nand_dev_desc + 0. This is also the behaviour using * the new NAND code. */ -void env_relocate_spec (void) +void env_relocate_spec(void) { #if !defined(ENV_IS_EMBEDDED) int ret; - char buf[CONFIG_ENV_SIZE]; + ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE); #if defined(CONFIG_ENV_OFFSET_OOB) ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);