[Skiboot] [PATCH 6/7] libflash/blocklevel: add a smart write function which wraps up eraseing and writing
Alistair Popple
alistair at popple.id.au
Fri Jun 12 12:53:08 AEST 2015
Looks good to me.
Reviewed-by: Alistair Popple <alistair at popple.id.au>
On Fri, 5 Jun 2015 14:11:30 Cyril Bur wrote:
> For consumers who can't do better or who aren't to phased about
> performance, having to book keep erasing in order to be able to write data
> can be painful. Blocklevel can do it, possibly naively but its a convenience
> function
>
> Signed-off-by: Cyril Bur <cyril.bur at au1.ibm.com>
> ---
> libflash/blocklevel.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++
> libflash/blocklevel.h | 3 +++
> 2 files changed, 71 insertions(+)
>
> diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
> index c3ca95e..6482587 100644
> --- a/libflash/blocklevel.c
> +++ b/libflash/blocklevel.c
> @@ -156,6 +156,74 @@ int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint32_
> return rc;
> }
>
> +int blocklevel_smart_write(struct blocklevel_device *bl, uint32_t pos, const void *buf, uint32_t len)
> +{
> + uint32_t erase_size;
> + const void *write_buf = buf;
> + void *write_buf_start = NULL;
> + void *erase_buf;
> + int rc = 0;
> +
> + if (!write_buf || !bl)
> + return -EINVAL;
> +
> + if (!(bl->flags & WRITE_NEED_ERASE))
> + return blocklevel_write(bl, pos, buf, len);
> +
> + if (read_protected(bl, pos, len) || write_protected(bl, pos, len))
> + return -EACCES;
> +
> + rc = blocklevel_get_info(bl, NULL, NULL, &erase_size);
> + if (rc)
> + return rc;
> +
> + if (ecc_protected(bl, pos, len)) {
> + len = ecc_buffer_size(len);
> +
> + write_buf_start = malloc(len);
> + if (!write_buf_start)
> + return -ENOMEM;
> +
> + if (memcpy_to_ecc(write_buf_start, buf, ecc_buffer_size_minus_ecc(len))) {
> + free(write_buf_start);
> + return -EBADF;
> + }
> + write_buf = write_buf_start;
> + }
> +
> + erase_buf = malloc(erase_size);
> + if (!erase_buf) {
> + rc = -ENOMEM;
> + goto out;
> + }
> +
> + while (len > 0) {
> + uint32_t erase_block = pos & ~(erase_size - 1);
> + uint32_t block_offset = pos & (erase_size - 1);
> + uint32_t size = erase_size > len ? len : erase_size;
> +
> + rc = bl->read(bl, erase_block, erase_buf, erase_size);
> + if (rc)
> + goto out;
> +
> + if (memcmp(erase_buf + block_offset, write_buf, size) != 0) {
> + memcpy(erase_buf + block_offset, write_buf, size);
> + rc = bl->write(bl, erase_block, erase_buf + block_offset, size);
> + if (rc)
> + goto out;
> + }
> +
> + len -= size;
> + pos += size;
> + write_buf += size;
> + }
> +
> +out:
> + free(write_buf_start);
> + free(erase_buf);
> + return rc;
> +}
> +
> static int insert_bl_prot_range(struct bl_prot_range **ranges, int *n_ranges,
> struct bl_prot_range range)
> {
> diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
> index d2995ce..dfbe973 100644
> --- a/libflash/blocklevel.h
> +++ b/libflash/blocklevel.h
> @@ -62,6 +62,9 @@ int blocklevel_erase(struct blocklevel_device *bl, uint32_t pos, uint32_t len);
> int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint32_t *total_size,
> uint32_t *erase_granule);
>
> +/* Convienience functions */
> +int blocklevel_smart_write(struct blocklevel_device *bl, uint32_t pos, const void *buf, uint32_t len);
> +
> /* Implemented in software at this level */
> int blocklevel_ecc_protect(struct blocklevel_device *bl, uint32_t start, uint32_t len);
> int blocklevel_read_protect(struct blocklevel_device *bl, uint32_t start, uint32_t len);
>
More information about the Skiboot
mailing list