This will become more important with NAND support, in which case the minimum erase region is a block, which consists of several pages and can be 256KiB large.
Signed-off-by: Guennadi Liakhovetski <[EMAIL PROTECTED]> --- tools/env/fw_env.c | 125 +++++++++++++++++++++++++++++++-------------------- 1 files changed, 76 insertions(+), 49 deletions(-) diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index 556aa85..931e647 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -413,11 +413,37 @@ int fw_setenv (int argc, char *argv[]) return 0; } +static int flash_read_buf (int dev, int fd, void *buf, size_t count, + off_t offset) +{ + int rc; + + rc = lseek (fd, offset, SEEK_SET); + if (rc == -1) { + fprintf (stderr, + "seek error on %s: %s\n", + DEVNAME (dev), strerror (errno)); + return rc; + } + + rc = read (fd, buf, count); + if (rc != count) { + fprintf (stderr, + "Read error on %s: %s\n", + DEVNAME (dev), strerror (errno)); + return -1; + } + + return rc; +} + static int flash_write (void) { - int fd_current, fd_target, rc, dev_target, resid; + int fd_current, fd_target, rc, dev_target; erase_info_t erase_current = {}, erase_target; char *data = NULL; + off_t erase_offset; + struct mtd_info_user mtdinfo_target; /* dev_current: fd_current, erase_current */ if ((fd_current = open (DEVNAME (dev_current), O_RDWR)) < 0) { @@ -442,6 +468,45 @@ static int flash_write (void) dev_target = dev_current; fd_target = fd_current; } + + /* + * Support environment anywhere within erase sectors: read out the + * complete area to be erased, replace the environment image, write + * the whole block back again. + */ + if (DEVESIZE (dev_target) > CFG_ENV_SIZE) { + data = malloc (DEVESIZE (dev_target)); + if (!data) { + fprintf (stderr, + "Cannot malloc %lu bytes: %s\n", + DEVESIZE (dev_target), + strerror (errno)); + return -1; + } + + rc = ioctl (fd_target, MEMGETINFO, &mtdinfo_target); + if (rc < 0) { + perror ("Cannot get MTD information"); + return -1; + } + + /* Erase sector size is always a power of 2 */ + erase_offset = DEVOFFSET (dev_target) & + ~(mtdinfo_target.erasesize - 1); + + rc = flash_read_buf (dev_target, fd_target, data, + DEVESIZE (dev_target), erase_offset); + if (rc < 0) + return rc; + + /* Overwrite the old environment */ + memcpy(DEVOFFSET (dev_target) - erase_offset + data, + environment.image, CFG_ENV_SIZE); + } else { + data = (char *)environment.image; + erase_offset = DEVOFFSET (dev_target); + } + printf ("Unlocking flash...\n"); erase_target.length = DEVESIZE (dev_target); erase_target.start = DEVOFFSET (dev_target); @@ -455,30 +520,6 @@ static int flash_write (void) } printf ("Done\n"); - resid = DEVESIZE (dev_target) - CFG_ENV_SIZE; - if (resid) { - if ((data = malloc (resid)) == NULL) { - fprintf (stderr, - "Cannot malloc %d bytes: %s\n", - resid, - strerror (errno)); - return -1; - } - if (lseek (fd_target, DEVOFFSET (dev_target) + CFG_ENV_SIZE, - SEEK_SET) == -1) { - fprintf (stderr, "seek error on %s: %s\n", - DEVNAME (dev_target), - strerror (errno)); - return -1; - } - if ((rc = read (fd_target, data, resid)) != resid) { - fprintf (stderr, - "read error on %s: %s\n", - DEVNAME (dev_target), - strerror (errno)); - return -1; - } - } printf ("Erasing old environment...\n"); @@ -492,30 +533,24 @@ static int flash_write (void) printf ("Done\n"); printf ("Writing environment to %s...\n", DEVNAME (dev_target)); - if (lseek (fd_target, DEVOFFSET (dev_target), SEEK_SET) == -1) { + if (lseek (fd_target, erase_offset, SEEK_SET) == -1) { fprintf (stderr, "seek error on %s: %s\n", DEVNAME (dev_target), strerror (errno)); return -1; } - if (write (fd_target, environment.image, CFG_ENV_SIZE) != - CFG_ENV_SIZE) { + if (write (fd_target, data, DEVESIZE (dev_target)) != + DEVESIZE (dev_target)) { fprintf (stderr, "Write error on %s: %s\n", DEVNAME (dev_target), strerror (errno)); return -1; } - if (resid) { - if (write (fd_target, data, resid) != resid) { - fprintf (stderr, - "write error on %s: %s\n", - DEVNAME (dev_current), strerror (errno)); - return -1; - } + if (DEVESIZE (dev_target) > CFG_ENV_SIZE) free (data); - } + if (HaveRedundEnv) { /* change flag on current active env partition */ if (lseek (fd_current, DEVOFFSET (dev_current) + sizeof (ulong), @@ -560,7 +595,7 @@ static int flash_write (void) static int flash_read (void) { - int fd; + int fd, rc; if ((fd = open (DEVNAME (dev_current), O_RDONLY)) < 0) { fprintf (stderr, @@ -569,18 +604,10 @@ static int flash_read (void) return -1; } - if (lseek (fd, DEVOFFSET (dev_current), SEEK_SET) == -1) { - fprintf (stderr, - "seek error on %s: %s\n", - DEVNAME (dev_current), strerror (errno)); - return -1; - } - if (read (fd, environment.image, CFG_ENV_SIZE) != CFG_ENV_SIZE) { - fprintf (stderr, - "Read error on %s: %s\n", - DEVNAME (dev_current), strerror (errno)); - return -1; - } + rc = flash_read_buf (dev_current, fd, environment.image, CFG_ENV_SIZE, + DEVOFFSET (dev_current)); + if (rc < 0) + return rc; if (close (fd)) { fprintf (stderr, -- 1.5.4 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot