From: Marek Vasut <marek.vasut@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v4] cmd_sf: add "update" subcommand to do smart SPI flash update
Date: Sun, 21 Aug 2011 01:04:11 +0200 [thread overview]
Message-ID: <201108210104.11721.marek.vasut@gmail.com> (raw)
In-Reply-To: <1313879751-1093-1-git-send-email-vapier@gentoo.org>
On Sunday, August 21, 2011 12:35:51 AM Mike Frysinger wrote:
> From: Simon Glass <sjg@chromium.org>
>
> This adds a new SPI flash command which only rewrites blocks if the
> contents need to change. This can speed up SPI flash programming when much
> of the data is unchanged from what is already there.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
> ---
> v4
> - tweak summary
> - fix printf warnings with %d vs %zu
> - fix help string and missing/extra newlines
>
> TODO: it'd be nice if we supported +len like we do with erase ...
>
> common/cmd_sf.c | 84
> +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed,
> 81 insertions(+), 3 deletions(-)
>
> diff --git a/common/cmd_sf.c b/common/cmd_sf.c
> index 11a491d..9b7d61b 100644
> --- a/common/cmd_sf.c
> +++ b/common/cmd_sf.c
> @@ -6,6 +6,7 @@
> */
>
> #include <common.h>
> +#include <malloc.h>
> #include <spi_flash.h>
>
> #include <asm/io.h>
> @@ -109,6 +110,78 @@ static int do_spi_flash_probe(int argc, char * const
> argv[]) return 0;
> }
>
> +/**
> + * Write a block of data to SPI flash, first checking if it is different
> from + * what is already there.
> + *
> + * If the data being written is the same, then *skipped is incremented by
> len. + *
> + * @param flash flash context pointer
> + * @param offset flash offset to write
> + * @param len number of bytes to write
> + * @param buf buffer to write from
> + * @param cmp_buf read buffer to use to compare data
> + * @param skipped Count of skipped data (incremented by this function)
> + * @return NULL if OK, else a string containing the stage which failed
> + */
> +static const char *spi_flash_update_block(struct spi_flash *flash, u32
> offset, + size_t len, const char *buf, char *cmp_buf, size_t *skipped)
Can't you just pass here a structure instead of this wicked pointer alchemy ?
> +{
> + debug("offset=%#x, sector_size=%#x, len=%#x\n",
> + offset, flash->sector_size, len);
> + if (spi_flash_read(flash, offset, len, cmp_buf))
> + return "read";
> + if (memcmp(cmp_buf, buf, len) == 0) {
> + debug("Skip region %x size %x: no change\n",
> + offset, len);
> + *skipped += len;
> + return NULL;
> + }
> + if (spi_flash_erase(flash, offset, len))
> + return "erase";
> + if (spi_flash_write(flash, offset, len, buf))
> + return "write";
Numeric value won't be ok ? You can have these in the calling function instead
of returning a char *.
> + return NULL;
> +}
> +
> +/**
> + * Update an area of SPI flash by erasing and writing any blocks which
> need + * to change. Existing blocks with the correct data are left
> unchanged. + *
> + * @param flash flash context pointer
> + * @param offset flash offset to write
> + * @param len number of bytes to write
> + * @param buf buffer to write from
> + * @return 0 if ok, 1 on error
> + */
> +static int spi_flash_update(struct spi_flash *flash, u32 offset,
> + size_t len, const char *buf)
> +{
> + const char *err_oper = NULL;
> + char *cmp_buf;
> + const char *end = buf + len;
> + size_t todo; /* number of bytes to do in this pass */
> + size_t skipped; /* statistics */
You can allocate a structure holding the internal state of the "update" command,
which I mentioned above, here, on stack.
> +
> + cmp_buf = malloc(flash->sector_size);
> + if (cmp_buf) {
if (!cmp_buf)
goto err;
... rest of code ...
Don't be afraid of goto and failpaths.
> + for (skipped = 0; buf < end; buf += todo, offset += todo) {
> + todo = min(end - buf, flash->sector_size);
> + err_oper = spi_flash_update_block(flash, offset, todo,
> + buf, cmp_buf, &skipped);
> + }
> + } else {
> + err_oper = "malloc";
> + }
> + free(cmp_buf);
> + if (err_oper) {
> + printf("SPI flash failed in %s step\n", err_oper);
> + return 1;
> + }
> + printf("%zu bytes written, %zu bytes skipped\n", len - skipped, skipped);
> + return 0;
> +}
> +
> static int do_spi_flash_read_write(int argc, char * const argv[])
> {
> unsigned long addr;
> @@ -137,7 +210,9 @@ static int do_spi_flash_read_write(int argc, char *
> const argv[]) return 1;
> }
>
> - if (strcmp(argv[0], "read") == 0)
> + if (strcmp(argv[0], "update") == 0)
> + ret = spi_flash_update(flash, offset, len, buf);
> + else if (strcmp(argv[0], "read") == 0)
> ret = spi_flash_read(flash, offset, len, buf);
> else
> ret = spi_flash_write(flash, offset, len, buf);
> @@ -203,7 +278,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int
> argc, char * const argv[ return 1;
> }
>
> - if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0)
> + if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 ||
> + strcmp(cmd, "update") == 0)
> ret = do_spi_flash_read_write(argc, argv);
> else if (strcmp(cmd, "erase") == 0)
> ret = do_spi_flash_erase(argc, argv);
> @@ -228,5 +304,7 @@ U_BOOT_CMD(
> "sf write addr offset len - write `len' bytes from memory\n"
> " at `addr' to flash at `offset'\n"
> "sf erase offset [+]len - erase `len' bytes from `offset'\n"
> - " `+len' round up `len' to block size"
> + " `+len' round up `len' to block size\n"
> + "sf update addr offset len - erase and write `len' bytes from memory\n"
> + " at `addr' to flash at `offset'"
> );
I like this patch!
Cheers
next prev parent reply other threads:[~2011-08-20 23:04 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-19 19:28 [U-Boot] [PATCH v3] Add 'sf update' command to do smart SPI flash update Simon Glass
2011-08-19 21:15 ` Mike Frysinger
2011-08-19 21:25 ` Simon Glass
2011-08-19 22:28 ` Mike Frysinger
2011-08-23 22:01 ` Simon Glass
2011-08-23 22:16 ` Mike Frysinger
2011-08-24 3:41 ` Che-liang Chiou
2011-08-24 4:11 ` Simon Glass
2011-08-20 22:35 ` [U-Boot] [PATCH v4] cmd_sf: add "update" subcommand " Mike Frysinger
2011-08-20 23:04 ` Marek Vasut [this message]
2011-08-21 10:37 ` Simon Glass
2011-08-21 16:35 ` Mike Frysinger
2011-08-22 22:53 ` Simon Glass
2011-08-21 10:27 ` Simon Glass
2011-08-21 16:34 ` Mike Frysinger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201108210104.11721.marek.vasut@gmail.com \
--to=marek.vasut@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.