[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