[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