[Skiboot] [PATCH V2 6/7] libflash/blocklevel: add a smart write function which wraps up eraseing and writing
Alistair Popple
alistair at popple.id.au
Mon Jun 22 19:27:48 AEST 2015
Again, looks similar to the previous version so:
Reviewed-By: Alistair Popple <alistair at popple.id.au>
On Tue, 16 Jun 2015 19:01:09 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 | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++
> libflash/blocklevel.h | 3 +++
> 2 files changed, 74 insertions(+)
>
> diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
> index 8df9c3d..68106ca 100644
> --- a/libflash/blocklevel.c
> +++ b/libflash/blocklevel.c
> @@ -156,6 +156,77 @@ 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) {
> + errno = EINVAL;
> + return FLASH_ERR_PARM_ERROR;
> + }
> +
> + if (!(bl->flags & WRITE_NEED_ERASE))
> + return blocklevel_write(bl, pos, buf, len);
> +
> + 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) {
> + errno = ENOMEM;
> + return FLASH_ERR_MALLOC_FAILED;
> + }
> +
> + if (memcpy_to_ecc(write_buf_start, buf, ecc_buffer_size_minus_ecc(len))) {
> + free(write_buf_start);
> + errno = EBADF;
> + return FLASH_ERR_ECC_INVALID;
> + }
> + write_buf = write_buf_start;
> + }
> +
> + erase_buf = malloc(erase_size);
> + if (!erase_buf) {
> + errno = ENOMEM;
> + rc = FLASH_ERR_MALLOC_FAILED;
> + 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,
> int *total_n_ranges, struct bl_prot_range range)
> {
> diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
> index 2185ca7..e335df2 100644
> --- a/libflash/blocklevel.h
> +++ b/libflash/blocklevel.h
> @@ -56,6 +56,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);
>
>
More information about the Skiboot
mailing list