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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox