blocklevel_info: Refactor the passing of output data

Message ID 20170829041922.4193-1-wak@google.com
State New
Headers show
Series
  • blocklevel_info: Refactor the passing of output data
Related show

Commit Message

William Kennington Aug. 29, 2017, 4:19 a.m.
This changes refactors all of the output variables from flash_get_info
into a new output struct. Callers now supply the info struct, and always
get all of the info with each call. There are never any allocations done
by this function so it shouldn't be much slower to always populate all
of the information.

Signed-off-by: William A. Kennington III <wak@google.com>
---
 core/flash.c                           | 15 +++++------
 external/common/arch_flash_arm.c       |  6 ++---
 external/common/arch_flash_common.c    |  6 ++---
 external/gard/gard.c                   | 10 +++----
 external/opal-prd/pnor.c               | 12 ++++-----
 external/opal-prd/pnor.h               |  3 +--
 external/opal-prd/test/test_pnor_ops.c |  7 +++--
 external/pflash/pflash.c               | 46 ++++++++++++++++----------------
 libflash/blocklevel.c                  | 35 ++++++++++++-------------
 libflash/blocklevel.h                  | 16 +++++++++---
 libflash/file.c                        | 48 ++++++++++++++--------------------
 libflash/libffs.c                      |  8 +++---
 libflash/libflash.c                    | 15 +++++------
 libflash/mbox-flash.c                  | 19 ++++----------
 libflash/test/test-flash.c             |  6 ++---
 platforms/mambo/mambo.c                | 15 ++++-------
 16 files changed, 125 insertions(+), 142 deletions(-)

Comments

Cyril Bur Aug. 29, 2017, 5:37 a.m. | #1
On Mon, 2017-08-28 at 21:19 -0700, William A. Kennington III wrote:
> This changes refactors all of the output variables from flash_get_info
> into a new output struct. Callers now supply the info struct, and always
> get all of the info with each call. There are never any allocations done
> by this function so it shouldn't be much slower to always populate all
> of the information.
> 

Hi William,

As nice as this refactor is (thanks for the effort!), unfortunately
we're a bit stuck with the interface as is, both openbmc and petitboot
projects link against a dynamic libflash.

Ironically I'm about to send a series which which does rework the
libffs api a bit - although I'm quite sure only external/ffspart
actually uses what I've changed. blocklevel_get_info() though is pretty
core and changing that won't work.

Perhaps you've prompted a discussion that now might be a good time to
do a significant rewrite of libflash/libffs which are now being used
for a completely different purpose for which they were first written,
hopefully Stewart will weigh in.


Cyril

> Signed-off-by: William A. Kennington III <wak@google.com>
> ---
>  core/flash.c                           | 15 +++++------
>  external/common/arch_flash_arm.c       |  6 ++---
>  external/common/arch_flash_common.c    |  6 ++---
>  external/gard/gard.c                   | 10 +++----
>  external/opal-prd/pnor.c               | 12 ++++-----
>  external/opal-prd/pnor.h               |  3 +--
>  external/opal-prd/test/test_pnor_ops.c |  7 +++--
>  external/pflash/pflash.c               | 46 ++++++++++++++++----------------
>  libflash/blocklevel.c                  | 35 ++++++++++++-------------
>  libflash/blocklevel.h                  | 16 +++++++++---
>  libflash/file.c                        | 48 ++++++++++++++--------------------
>  libflash/libffs.c                      |  8 +++---
>  libflash/libflash.c                    | 15 +++++------
>  libflash/mbox-flash.c                  | 19 ++++----------
>  libflash/test/test-flash.c             |  6 ++---
>  platforms/mambo/mambo.c                | 15 ++++-------
>  16 files changed, 125 insertions(+), 142 deletions(-)
> 
> diff --git a/core/flash.c b/core/flash.c
> index 53e6eba08..35a0c4c32 100644
> --- a/core/flash.c
> +++ b/core/flash.c
> @@ -254,21 +254,20 @@ static int num_flashes(void)
>  
>  int flash_register(struct blocklevel_device *bl)
>  {
> -	uint64_t size;
> -	uint32_t block_size;
> +	struct blocklevel_info bl_info;
>  	struct ffs_handle *ffs;
>  	struct dt_node *node;
>  	struct flash *flash;
> -	const char *name;
>  	int rc;
>  
> -	rc = blocklevel_get_info(bl, &name, &size, &block_size);
> +	rc = blocklevel_get_info(bl, &bl_info);
>  	if (rc)
>  		return rc;
>  
>  	prlog(PR_INFO, "FLASH: registering flash device %s "
>  			"(size 0x%llx, blocksize 0x%x)\n",
> -			name ?: "(unnamed)", size, block_size);
> +			bl_info.name ? bl_info.name : "(unnamed)", bl_info.size,
> +			bl_info.erase_granule);
>  
>  	lock(&flash_lock);
>  
> @@ -281,8 +280,8 @@ int flash_register(struct blocklevel_device *bl)
>  
>  	flash->busy = false;
>  	flash->bl = bl;
> -	flash->size = size;
> -	flash->block_size = block_size;
> +	flash->size = bl_info.size;
> +	flash->block_size = bl_info.erase_granule;
>  	flash->id = num_flashes();
>  
>  	list_add(&flashes, &flash->list);
> @@ -302,7 +301,7 @@ int flash_register(struct blocklevel_device *bl)
>  
>  	node = flash_add_dt_node(flash, flash->id);
>  
> -	setup_system_flash(flash, node, name, ffs);
> +	setup_system_flash(flash, node, bl_info.name, ffs);
>  
>  	if (ffs)
>  		ffs_close(ffs);
> diff --git a/external/common/arch_flash_arm.c b/external/common/arch_flash_arm.c
> index 3cdd41ded..ac43de0c4 100644
> --- a/external/common/arch_flash_arm.c
> +++ b/external/common/arch_flash_arm.c
> @@ -303,13 +303,13 @@ int arch_flash_erase_chip(struct blocklevel_device *bl)
>  	if (!arch_data.flash_chip) {
>  		/* Just assume its a regular erase */
>  		int rc;
> -		uint64_t total_size;
> +		struct blocklevel_info bl_info;
>  
> -		rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
> +		rc = blocklevel_get_info(bl, &bl_info);
>  		if (rc)
>  			return rc;
>  
> -		return blocklevel_erase(bl, 0, total_size);
> +		return blocklevel_erase(bl, 0, bl_info.size);
>  	}
>  
>  	return flash_erase_chip(arch_data.flash_chip);
> diff --git a/external/common/arch_flash_common.c b/external/common/arch_flash_common.c
> index 6bce7e1ba..41239662a 100644
> --- a/external/common/arch_flash_common.c
> +++ b/external/common/arch_flash_common.c
> @@ -31,13 +31,13 @@
>  int __attribute__((weak)) arch_flash_erase_chip(struct blocklevel_device *bl)
>  {
>  	int rc;
> -	uint64_t total_size;
> +	struct blocklevel_info bl_info;
>  
> -	rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
> +	rc = blocklevel_get_info(bl, &bl_info);
>  	if (rc)
>  		return rc;
>  
> -	return blocklevel_erase(bl, 0, total_size);
> +	return blocklevel_erase(bl, 0, bl_info.size);
>  }
>  
>  int __attribute__((weak,const)) arch_flash_4b_mode(struct blocklevel_device *bl, int set_4b)
> diff --git a/external/gard/gard.c b/external/gard/gard.c
> index c5cb93b88..3946cad6f 100644
> --- a/external/gard/gard.c
> +++ b/external/gard/gard.c
> @@ -596,7 +596,7 @@ int main(int argc, char **argv)
>  	const char *action, *progname;
>  	char *filename = NULL;
>  	struct gard_ctx _ctx, *ctx;
> -	uint64_t bl_size;
> +	struct blocklevel_info bl_info;
>  	int rc, i = 0;
>  	bool part = 0;
>  	bool ecc = 0;
> @@ -665,17 +665,17 @@ int main(int argc, char **argv)
>  		goto out_free;
>  	}
>  
> -	rc = blocklevel_get_info(ctx->bl, NULL, &bl_size, NULL);
> +	rc = blocklevel_get_info(ctx->bl, &bl_info);
>  	if (rc)
>  		goto out;
>  
> -	if (bl_size > UINT_MAX) {
> +	if (bl_info.size > UINT_MAX) {
>  		fprintf(stderr, "MTD device bigger than %i: size: %" PRIu64 "\n",
> -			UINT_MAX, bl_size);
> +			UINT_MAX, bl_info.size);
>  		rc = EXIT_FAILURE;
>  		goto out;
>  	}
> -	ctx->f_size = bl_size;
> +	ctx->f_size = bl_info.size;
>  
>  	if (!part) {
>  		rc = ffs_init(0, ctx->f_size, ctx->bl, &ctx->ffs, 1);
> diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c
> index c032421d1..afb6ccd1f 100644
> --- a/external/opal-prd/pnor.c
> +++ b/external/opal-prd/pnor.c
> @@ -64,13 +64,13 @@ int pnor_init(struct pnor *pnor)
>  		return -1;
>  	}
>  
> -	rc = blocklevel_get_info(pnor->bl, NULL, &(pnor->size), &(pnor->erasesize));
> +	rc = blocklevel_get_info(pnor->bl, &pnor->bl_info);
>  	if (rc) {
>  		pr_log(LOG_ERR, "PNOR: blocklevel_get_info() failed. Can't use PNOR");
>  		goto out;
>  	}
>  
> -	rc = ffs_init(0, pnor->size, pnor->bl, &pnor->ffsh, 0);
> +	rc = ffs_init(0, pnor->bl_info.size, pnor->bl, &pnor->ffsh, 0);
>  	if (rc) {
>  		pr_log(LOG_ERR, "PNOR: Failed to open pnor partition table");
>  		goto out;
> @@ -121,8 +121,8 @@ static int mtd_write(struct pnor *pnor, void *data, uint64_t offset,
>  {
>  	int rc;
>  
> -	if (len > pnor->size || offset > pnor->size ||
> -	    len + offset > pnor->size)
> +	if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
> +	    len + offset > pnor->bl_info.size)
>  		return -ERANGE;
>  
>  	rc = blocklevel_smart_write(pnor->bl, offset, data, len);
> @@ -137,8 +137,8 @@ static int mtd_read(struct pnor *pnor, void *data, uint64_t offset,
>  {
>  	int rc;
>  
> -	if (len > pnor->size || offset > pnor->size ||
> -	    len + offset > pnor->size)
> +	if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
> +	    len + offset > pnor->bl_info.size)
>  		return -ERANGE;
>  
>  	rc = blocklevel_read(pnor->bl, offset, data, len);
> diff --git a/external/opal-prd/pnor.h b/external/opal-prd/pnor.h
> index 28571af64..1ee033659 100644
> --- a/external/opal-prd/pnor.h
> +++ b/external/opal-prd/pnor.h
> @@ -7,8 +7,7 @@
>  struct pnor {
>  	char			*path;
>  	struct ffs_handle	*ffsh;
> -	uint64_t		size;
> -	uint32_t		erasesize;
> +	struct blocklevel_info bl_info;
>  	struct blocklevel_device *bl;
>  };
>  
> diff --git a/external/opal-prd/test/test_pnor_ops.c b/external/opal-prd/test/test_pnor_ops.c
> index fd5e2c22a..3743362e1 100644
> --- a/external/opal-prd/test/test_pnor_ops.c
> +++ b/external/opal-prd/test/test_pnor_ops.c
> @@ -130,11 +130,14 @@ int main(int argc, char **argv)
>  	for (i = 0; i < 2; i++)
>  		write(fd, data, 16);
>  
> +	/* Unused */
> +	pnor.bl_info.name = NULL;
> +
>  	/* Adjust this if making the file smaller */
> -	pnor.size = 32;
> +	pnor.bl_info.size = 32;
>  
>  	/* This is fake. Make it smaller than the size */
> -	pnor.erasesize = 4;
> +	pnor.bl_info.erase_granule = 4;
>  
>  	printf("Write: ");
>  	memset(data, 'A', sizeof(data));
> diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c
> index bfc975fe5..3f501e583 100644
> --- a/external/pflash/pflash.c
> +++ b/external/pflash/pflash.c
> @@ -43,11 +43,9 @@
>  
>  struct flash_details {
>  	struct blocklevel_device *bl;
> +	struct blocklevel_info bl_info;
>  	int need_relock;
> -	const char *name;
>  	uint64_t toc;
> -	uint64_t total_size;
> -	uint32_t erase_granule;
>  };
>  
>  /* Full pflash version number (possibly includes gitid). */
> @@ -144,7 +142,7 @@ static struct ffs_handle *open_ffs(struct flash_details *flash)
>  	struct ffs_handle *ffsh;
>  	int rc;
>  
> -	rc = ffs_init(flash->toc, flash->total_size,
> +	rc = ffs_init(flash->toc, flash->bl_info.size,
>  			flash->bl, &ffsh, 0);
>  	if (rc) {
>  		fprintf(stderr, "Error %d opening ffs !\n", rc);
> @@ -166,11 +164,11 @@ static void print_flash_info(struct flash_details *flash)
>  
>  	printf("Flash info:\n");
>  	printf("-----------\n");
> -	printf("Name          = %s\n", flash->name);
> +	printf("Name          = %s\n", flash->bl_info.name);
>  	printf("Total size    = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED, R:READONLY\n",
> -			flash->total_size >> 20);
> +			flash->bl_info.size >> 20);
>  	printf("Erase granule = %2d%-13sB:BACKUP, F:REPROVISION\n",
> -			flash->erase_granule >> 10, "KB");
> +			flash->bl_info.erase_granule >> 10, "KB");
>  
>  	if (bmc_flash)
>  		return;
> @@ -282,9 +280,11 @@ static int erase_chip(struct flash_details *flash)
>  	 * likes the progress bars.
>  	 * Lets do an erase block at a time erase then...
>  	 */
> -	progress_init(flash->total_size);
> -	for (pos = 0; pos < flash->total_size; pos += flash->erase_granule) {
> -		rc = blocklevel_erase(flash->bl, pos, flash->erase_granule);
> +	progress_init(flash->bl_info.size);
> +	for (pos = 0; pos < flash->bl_info.size;
> +			pos += flash->bl_info.erase_granule) {
> +		rc = blocklevel_erase(flash->bl, pos,
> +				flash->bl_info.erase_granule);
>  		if (rc)
>  			break;
>  		progress_tick(pos);
> @@ -303,7 +303,7 @@ static int erase_range(struct flash_details *flash,
>  		uint32_t start, uint32_t size, bool will_program,
>  		struct ffs_handle *ffsh, int ffs_index)
>  {
> -	uint32_t done = 0, erase_mask = flash->erase_granule - 1;
> +	uint32_t done = 0, erase_mask = flash->bl_info.erase_granule - 1;
>  	bool confirm;
>  	int rc;
>  
> @@ -326,25 +326,26 @@ static int erase_range(struct flash_details *flash,
>  	if (start & erase_mask) {
>  		/* Align to next erase block */
>  		rc = blocklevel_smart_erase(flash->bl, start,
> -				flash->erase_granule - (start & erase_mask));
> +				flash->bl_info.erase_granule - (start & erase_mask));
>  		if (rc) {
>  			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
>  			return 1;
>  		}
> -		start += flash->erase_granule - (start & erase_mask);
> -		size -= flash->erase_granule - (start & erase_mask);
> -		done = flash->erase_granule - (start & erase_mask);
> +		start += flash->bl_info.erase_granule - (start & erase_mask);
> +		size -= flash->bl_info.erase_granule - (start & erase_mask);
> +		done = flash->bl_info.erase_granule - (start & erase_mask);
>  	}
>  	progress_tick(done);
>  	while (size & ~(erase_mask)) {
> -		rc = blocklevel_smart_erase(flash->bl, start, flash->erase_granule);
> +		rc = blocklevel_smart_erase(flash->bl, start,
> +				flash->bl_info.erase_granule);
>  		if (rc) {
>  			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
>  			return 1;
>  		}
> -		start += flash->erase_granule;
> -		size -= flash->erase_granule;
> -		done += flash->erase_granule;
> +		start += flash->bl_info.erase_granule;
> +		size -= flash->bl_info.erase_granule;
> +		done += flash->bl_info.erase_granule;
>  		progress_tick(done);
>  	}
>  	if (size) {
> @@ -1003,8 +1004,7 @@ int main(int argc, char *argv[])
>  		goto out;
>  	}
>  
> -	rc = blocklevel_get_info(flash.bl, &flash.name,
> -			    &flash.total_size, &flash.erase_granule);
> +	rc = blocklevel_get_info(flash.bl, &flash.bl_info);
>  	if (rc) {
>  		fprintf(stderr, "Error %d getting flash info\n", rc);
>  		rc = 1;
> @@ -1025,7 +1025,7 @@ int main(int argc, char *argv[])
>  
>  	/* If read specified and no read_size, use flash size */
>  	if (do_read && !read_size && !part_name)
> -		read_size = flash.total_size;
> +		read_size = flash.bl_info.size;
>  
>  	/* We have a partition, adjust read/write size if needed */
>  	if (part_name || print_detail) {
> @@ -1087,7 +1087,7 @@ int main(int argc, char *argv[])
>  		/* Set address */
>  		address = pstart;
>  	} else if (erase) {
> -		if ((address | write_size) & (flash.erase_granule - 1)) {
> +		if ((address | write_size) & (flash.bl_info.erase_granule - 1)) {
>  			if (must_confirm) {
>  				printf("ERROR: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
>  						address, write_size);
> diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
> index 33d5c5d2f..3955be823 100644
> --- a/libflash/blocklevel.c
> +++ b/libflash/blocklevel.c
> @@ -229,12 +229,11 @@ int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len)
>  	return rc;
>  }
>  
> -int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
> -		uint32_t *erase_granule)
> +int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info)
>  {
>  	int rc;
>  
> -	if (!bl || !bl->get_info) {
> +	if (!bl || !bl->get_info || !bl_info) {
>  		errno = EINVAL;
>  		return FLASH_ERR_PARM_ERROR;
>  	}
> @@ -243,12 +242,12 @@ int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_
>  	if (rc)
>  		return rc;
>  
> -	rc = bl->get_info(bl, name, total_size, erase_granule);
> +	rc = bl->get_info(bl, bl_info);
>  
>  	/* Check the validity of what we are being told */
> -	if (erase_granule && *erase_granule != bl->erase_mask + 1)
> +	if (bl_info->erase_granule != bl->erase_mask + 1)
>  		FL_ERR("blocklevel_get_info: WARNING: erase_granule (0x%08x) and erase_mask"
> -				" (0x%08x) don't match\n", *erase_granule, bl->erase_mask + 1);
> +				" (0x%08x) don't match\n", bl_info->erase_granule, bl->erase_mask + 1);
>  
>  	release(bl);
>  
> @@ -417,7 +416,7 @@ out:
>  
>  int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len)
>  {
> -	uint32_t erase_size;
> +	struct blocklevel_info bl_info;
>  	const void *write_buf = buf;
>  	void *write_buf_start = NULL;
>  	void *erase_buf;
> @@ -435,7 +434,7 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
>  		return blocklevel_write(bl, pos, buf, len);
>  	}
>  
> -	rc = blocklevel_get_info(bl, NULL, NULL, &erase_size);
> +	rc = blocklevel_get_info(bl, &bl_info);
>  	if (rc)
>  		return rc;
>  
> @@ -458,7 +457,7 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
>  		write_buf = write_buf_start;
>  	}
>  
> -	erase_buf = malloc(erase_size);
> +	erase_buf = malloc(bl_info.erase_granule);
>  	if (!erase_buf) {
>  		errno = ENOMEM;
>  		rc = FLASH_ERR_MALLOC_FAILED;
> @@ -470,32 +469,32 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
>  		goto out_free;
>  
>  	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;
> +		uint32_t erase_block = pos & ~(bl_info.erase_granule - 1);
> +		uint32_t block_offset = pos & (bl_info.erase_granule - 1);
> +		uint32_t size = bl_info.erase_granule > len ? len : bl_info.erase_granule;
>  		int cmp;
>  
>  		/* Write crosses an erase boundary, shrink the write to the boundary */
> -		if (erase_size < block_offset + size) {
> -			size = erase_size - block_offset;
> +		if (bl_info.erase_granule < block_offset + size) {
> +			size = bl_info.erase_granule - block_offset;
>  		}
>  
> -		rc = bl->read(bl, erase_block, erase_buf, erase_size);
> +		rc = bl->read(bl, erase_block, erase_buf, bl_info.erase_granule);
>  		if (rc)
>  			goto out;
>  
>  		cmp = blocklevel_flashcmp(erase_buf + block_offset, write_buf, size);
>  		FL_DBG("%s: region 0x%08x..0x%08x ", __func__,
> -				erase_block, erase_size);
> +				erase_block, bl_info.erase_granule);
>  		if (cmp != 0) {
>  			FL_DBG("needs ");
>  			if (cmp == -1) {
>  				FL_DBG("erase and ");
> -				bl->erase(bl, erase_block, erase_size);
> +				bl->erase(bl, erase_block, bl_info.erase_granule);
>  			}
>  			FL_DBG("write\n");
>  			memcpy(erase_buf + block_offset, write_buf, size);
> -			rc = bl->write(bl, erase_block, erase_buf, erase_size);
> +			rc = bl->write(bl, erase_block, erase_buf, bl_info.erase_granule);
>  			if (rc)
>  				goto out;
>  		}
> diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
> index ba42c83d0..d2d269054 100644
> --- a/libflash/blocklevel.h
> +++ b/libflash/blocklevel.h
> @@ -34,6 +34,15 @@ enum blocklevel_flags {
>  	WRITE_NEED_ERASE = 1,
>  };
>  
> +struct blocklevel_info {
> +	/* name is not owned by this struct and must persist for the
> +	 * liftime of blocklevel_info
> +	 */
> +	const char *name;
> +	uint64_t size;
> +	uint32_t erase_granule;
> +};
> +
>  /*
>   * libffs may be used with different backends, all should provide these for
>   * libflash to get the information it needs
> @@ -45,8 +54,7 @@ struct blocklevel_device {
>  	int (*read)(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len);
>  	int (*write)(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
>  	int (*erase)(struct blocklevel_device *bl, uint64_t pos, uint64_t len);
> -	int (*get_info)(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
> -			uint32_t *erase_granule);
> +	int (*get_info)(struct blocklevel_device *bl, struct blocklevel_info *bl_info);
>  
>  	/*
>  	 * Keep the erase mask so that blocklevel_erase() can do sanity checking
> @@ -62,8 +70,8 @@ int blocklevel_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint6
>  int blocklevel_raw_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
>  int blocklevel_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
>  int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len);
> -int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
> -		uint32_t *erase_granule);
> +
> +int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info);
>  
>  /*
>   * blocklevel_smart_write() performs reads on the data to see if it
> diff --git a/libflash/file.c b/libflash/file.c
> index 7065eb4fa..b87679cd1 100644
> --- a/libflash/file.c
> +++ b/libflash/file.c
> @@ -212,6 +212,7 @@ static int get_info_name(struct file_data *file_data, char **name)
>  	}
>  	lpath[len] = '\0';
>  
> +	free(*name);
>  	*name = lpath;
>  
>  	free(path);
> @@ -219,8 +220,8 @@ static int get_info_name(struct file_data *file_data, char **name)
>  }
>  
>  
> -static int mtd_get_info(struct blocklevel_device *bl, const char **name,
> -		uint64_t *total_size, uint32_t *erase_granule)
> +static int mtd_get_info(struct blocklevel_device *bl,
> +		struct blocklevel_info *bl_info)
>  {
>  	struct file_data *file_data = container_of(bl, struct file_data, bl);
>  	struct mtd_info_user mtd_info;
> @@ -230,24 +231,19 @@ static int mtd_get_info(struct blocklevel_device *bl, const char **name,
>  	if (rc == -1)
>  		return FLASH_ERR_BAD_READ;
>  
> -	if (total_size)
> -		*total_size = mtd_info.size;
> -
> -	if (erase_granule)
> -		*erase_granule = mtd_info.erasesize;
> +	rc = get_info_name(file_data, &(file_data->name));
> +	if (rc)
> +		return rc;
>  
> -	if (name) {
> -		rc = get_info_name(file_data, &(file_data->name));
> -		if (rc)
> -			return rc;
> -		*name = file_data->name;
> -	}
> +	bl_info->name = file_data->name;
> +	bl_info->size = mtd_info.size;
> +	bl_info->erase_granule = mtd_info.erasesize;
>  
>  	return 0;
>  }
>  
> -static int file_get_info(struct blocklevel_device *bl, const char **name,
> -		uint64_t *total_size, uint32_t *erase_granule)
> +static int file_get_info(struct blocklevel_device *bl,
> +		struct blocklevel_info *bl_info)
>  {
>  	struct file_data *file_data = container_of(bl, struct file_data, bl);
>  	struct stat st;
> @@ -256,18 +252,13 @@ static int file_get_info(struct blocklevel_device *bl, const char **name,
>  	if (fstat(file_data->fd, &st))
>  		return FLASH_ERR_PARM_ERROR;
>  
> -	if (total_size)
> -		*total_size = st.st_size;
> -
> -	if (erase_granule)
> -		*erase_granule = 1;
> +	rc = get_info_name(file_data, &(file_data->name));
> +	if (rc)
> +		return rc;
>  
> -	if (name) {
> -		rc = get_info_name(file_data, &(file_data->name));
> -		if (rc)
> -			return rc;
> -		*name = file_data->name;
> -	}
> +	bl_info->name = file_data->name;
> +	bl_info->size = st.st_size;
> +	bl_info->erase_granule = 1;
>  
>  	return 0;
>  }
> @@ -315,8 +306,9 @@ int file_init(int fd, struct blocklevel_device **bl)
>  		file_data->bl.erase = &mtd_erase;
>  		file_data->bl.get_info = &mtd_get_info;
>  		file_data->bl.flags = WRITE_NEED_ERASE;
> -		mtd_get_info(&file_data->bl, NULL, NULL, &(file_data->bl.erase_mask));
> -		file_data->bl.erase_mask--;
> +		struct blocklevel_info bl_info;
> +		mtd_get_info(&file_data->bl, &bl_info);
> +		file_data->bl.erase_mask = bl_info.erase_granule - 1;
>  	} else if (!S_ISREG(sbuf.st_mode)) {
>  		/* If not a char device or a regular file something went wrong */
>  		goto out;
> diff --git a/libflash/libffs.c b/libflash/libffs.c
> index 038f59425..6fc23eee9 100644
> --- a/libflash/libffs.c
> +++ b/libflash/libffs.c
> @@ -216,25 +216,25 @@ int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
>  {
>  	struct __ffs_hdr blank_hdr;
>  	struct __ffs_hdr raw_hdr;
> +	struct blocklevel_info bl_info;
>  	struct ffs_handle *f;
> -	uint64_t total_size;
>  	int rc, i;
>  
>  	if (!ffs || !bl)
>  		return FLASH_ERR_PARM_ERROR;
>  	*ffs = NULL;
>  
> -	rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
> +	rc = blocklevel_get_info(bl, &bl_info);
>  	if (rc) {
>  		FL_ERR("FFS: Error %d retrieving flash info\n", rc);
>  		return rc;
>  	}
> -	if (total_size > UINT_MAX)
> +	if (bl_info.size > UINT_MAX)
>  		return FLASH_ERR_VERIFY_FAILURE;
>  	if ((offset + max_size) < offset)
>  		return FLASH_ERR_PARM_ERROR;
>  
> -	if ((max_size > total_size))
> +	if ((max_size > bl_info.size))
>  		return FLASH_ERR_PARM_ERROR;
>  
>  	/* Read flash header */
> diff --git a/libflash/libflash.c b/libflash/libflash.c
> index 38f87b86e..82a2baecc 100644
> --- a/libflash/libflash.c
> +++ b/libflash/libflash.c
> @@ -792,16 +792,15 @@ static int flash_configure(struct flash_chip *c)
>  	return 0;
>  }
>  
> -static int flash_get_info(struct blocklevel_device *bl, const char **name,
> -		   uint64_t *total_size, uint32_t *erase_granule)
> +static int flash_get_info(struct blocklevel_device *bl,
> +		struct blocklevel_info *bl_info)
>  {
>  	struct flash_chip *c = container_of(bl, struct flash_chip, bl);
> -	if (name)
> -		*name = c->info.name;
> -	if (total_size)
> -		*total_size = c->tsize;
> -	if (erase_granule)
> -		*erase_granule = c->min_erase_mask + 1;
> +
> +	bl_info->name = c->info.name;
> +	bl_info->size = c->tsize;
> +	bl_info->erase_granule = c->min_erase_mask + 1;
> +
>  	return 0;
>  }
>  
> diff --git a/libflash/mbox-flash.c b/libflash/mbox-flash.c
> index 950e24f05..d4200ce53 100644
> --- a/libflash/mbox-flash.c
> +++ b/libflash/mbox-flash.c
> @@ -745,8 +745,8 @@ static int mbox_flash_read(struct blocklevel_device *bl, uint64_t pos,
>  	return rc;
>  }
>  
> -static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
> -		uint64_t *total_size, uint32_t *erase_granule)
> +static int mbox_flash_get_info(struct blocklevel_device *bl,
> +		struct blocklevel_info *bl_info)
>  {
>  	struct mbox_flash_data *mbox_flash;
>  	struct bmc_mbox_msg *msg;
> @@ -761,14 +761,7 @@ static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
>  	if (!msg)
>  		return FLASH_ERR_MALLOC_FAILED;
>  
> -	/*
> -	 * We want to avoid runtime mallocs in skiboot. The expected
> -	 * behavour to uses of libflash is that one can free() the memory
> -	 * returned.
> -	 * NULL will do for now.
> -	 */
> -	if (name)
> -		*name = NULL;
> +	bl_info->name = "pnor_mbox";
>  
>  	mbox_flash->busy = true;
>  	rc = msg_send(mbox_flash, msg);
> @@ -784,10 +777,8 @@ static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
>  
>  	mbox_flash->bl.erase_mask = mbox_flash->erase_granule - 1;
>  
> -	if (total_size)
> -		*total_size = mbox_flash->total_size;
> -	if (erase_granule)
> -		*erase_granule = mbox_flash->erase_granule;
> +	bl_info->size = mbox_flash->total_size;
> +	bl_info->erase_granule = mbox_flash->erase_granule;
>  
>  out:
>  	msg_free_memory(msg);
> diff --git a/libflash/test/test-flash.c b/libflash/test/test-flash.c
> index 3f77d6f3e..1ca467bb0 100644
> --- a/libflash/test/test-flash.c
> +++ b/libflash/test/test-flash.c
> @@ -367,9 +367,7 @@ struct spi_flash_ctrl sim_ctrl = {
>  int main(void)
>  {
>  	struct blocklevel_device *bl;
> -	uint64_t total_size;
> -	uint32_t erase_granule;
> -	const char *name;
> +	struct blocklevel_info bl_info;
>  	uint16_t *test;
>  	struct ecc64 *ecc_test;
>  	uint64_t *test64;
> @@ -384,7 +382,7 @@ int main(void)
>  		ERR("flash_init failed with err %d\n", rc);
>  		exit(1);
>  	}
> -	rc = flash_get_info(bl, &name, &total_size, &erase_granule);
> +	rc = flash_get_info(bl, &bl_info);
>  	if (rc) {
>  		ERR("flash_get_info failed with err %d\n", rc);
>  		exit(1);
> diff --git a/platforms/mambo/mambo.c b/platforms/mambo/mambo.c
> index cb6e103cc..dd7872a8e 100644
> --- a/platforms/mambo/mambo.c
> +++ b/platforms/mambo/mambo.c
> @@ -125,19 +125,14 @@ static int bogus_disk_erase(struct blocklevel_device *bl __unused,
>  	return 0; /* NOP */
>  }
>  
> -static int bogus_disk_get_info(struct blocklevel_device *bl, const char **name,
> -			      uint64_t *total_size, uint32_t *erase_granule)
> +static int bogus_disk_get_info(struct blocklevel_device *bl,
> +			struct blocklevel_info *bl_info)
>  {
>  	struct bogus_disk_info *bdi = bl->priv;
>  
> -	if (total_size)
> -		*total_size = bdi->size;
> -
> -	if (erase_granule)
> -		*erase_granule = BD_SECT_SZ;
> -
> -	if (name)
> -		*name = "mambobogus";
> +	bl_info->name = "mambobogus";
> +	bl_info->size = bdi->size;
> +	bl_info->erase_granule = BD_SECT_SZ;
>  
>  	return 0;
>  }
William Kennington Aug. 29, 2017, 6:34 a.m. | #2
Cyril,

Sounds good. I actually wrote this up a couple of months back, but I'd like
to upstream as many of our changes as possible. It just occurred to me that
we may not actually need this change at all to support one of the flash
changes we made. It would be nice to clean up these interfaces though.

On Mon, Aug 28, 2017 at 10:38 PM Cyril Bur <cyrilbur@gmail.com> wrote:

> On Mon, 2017-08-28 at 21:19 -0700, William A. Kennington III wrote:
> > This changes refactors all of the output variables from flash_get_info
> > into a new output struct. Callers now supply the info struct, and always
> > get all of the info with each call. There are never any allocations done
> > by this function so it shouldn't be much slower to always populate all
> > of the information.
> >
>
> Hi William,
>
> As nice as this refactor is (thanks for the effort!), unfortunately
> we're a bit stuck with the interface as is, both openbmc and petitboot
> projects link against a dynamic libflash.
>
> Ironically I'm about to send a series which which does rework the
> libffs api a bit - although I'm quite sure only external/ffspart
> actually uses what I've changed. blocklevel_get_info() though is pretty
> core and changing that won't work.
>
> Perhaps you've prompted a discussion that now might be a good time to
> do a significant rewrite of libflash/libffs which are now being used
> for a completely different purpose for which they were first written,
> hopefully Stewart will weigh in.
>
>
> Cyril
>
> > Signed-off-by: William A. Kennington III <wak@google.com>
> > ---
> >  core/flash.c                           | 15 +++++------
> >  external/common/arch_flash_arm.c       |  6 ++---
> >  external/common/arch_flash_common.c    |  6 ++---
> >  external/gard/gard.c                   | 10 +++----
> >  external/opal-prd/pnor.c               | 12 ++++-----
> >  external/opal-prd/pnor.h               |  3 +--
> >  external/opal-prd/test/test_pnor_ops.c |  7 +++--
> >  external/pflash/pflash.c               | 46
> ++++++++++++++++----------------
> >  libflash/blocklevel.c                  | 35 ++++++++++++-------------
> >  libflash/blocklevel.h                  | 16 +++++++++---
> >  libflash/file.c                        | 48
> ++++++++++++++--------------------
> >  libflash/libffs.c                      |  8 +++---
> >  libflash/libflash.c                    | 15 +++++------
> >  libflash/mbox-flash.c                  | 19 ++++----------
> >  libflash/test/test-flash.c             |  6 ++---
> >  platforms/mambo/mambo.c                | 15 ++++-------
> >  16 files changed, 125 insertions(+), 142 deletions(-)
> >
> > diff --git a/core/flash.c b/core/flash.c
> > index 53e6eba08..35a0c4c32 100644
> > --- a/core/flash.c
> > +++ b/core/flash.c
> > @@ -254,21 +254,20 @@ static int num_flashes(void)
> >
> >  int flash_register(struct blocklevel_device *bl)
> >  {
> > -     uint64_t size;
> > -     uint32_t block_size;
> > +     struct blocklevel_info bl_info;
> >       struct ffs_handle *ffs;
> >       struct dt_node *node;
> >       struct flash *flash;
> > -     const char *name;
> >       int rc;
> >
> > -     rc = blocklevel_get_info(bl, &name, &size, &block_size);
> > +     rc = blocklevel_get_info(bl, &bl_info);
> >       if (rc)
> >               return rc;
> >
> >       prlog(PR_INFO, "FLASH: registering flash device %s "
> >                       "(size 0x%llx, blocksize 0x%x)\n",
> > -                     name ?: "(unnamed)", size, block_size);
> > +                     bl_info.name ? bl_info.name : "(unnamed)",
> bl_info.size,
> > +                     bl_info.erase_granule);
> >
> >       lock(&flash_lock);
> >
> > @@ -281,8 +280,8 @@ int flash_register(struct blocklevel_device *bl)
> >
> >       flash->busy = false;
> >       flash->bl = bl;
> > -     flash->size = size;
> > -     flash->block_size = block_size;
> > +     flash->size = bl_info.size;
> > +     flash->block_size = bl_info.erase_granule;
> >       flash->id = num_flashes();
> >
> >       list_add(&flashes, &flash->list);
> > @@ -302,7 +301,7 @@ int flash_register(struct blocklevel_device *bl)
> >
> >       node = flash_add_dt_node(flash, flash->id);
> >
> > -     setup_system_flash(flash, node, name, ffs);
> > +     setup_system_flash(flash, node, bl_info.name, ffs);
> >
> >       if (ffs)
> >               ffs_close(ffs);
> > diff --git a/external/common/arch_flash_arm.c
> b/external/common/arch_flash_arm.c
> > index 3cdd41ded..ac43de0c4 100644
> > --- a/external/common/arch_flash_arm.c
> > +++ b/external/common/arch_flash_arm.c
> > @@ -303,13 +303,13 @@ int arch_flash_erase_chip(struct blocklevel_device
> *bl)
> >       if (!arch_data.flash_chip) {
> >               /* Just assume its a regular erase */
> >               int rc;
> > -             uint64_t total_size;
> > +             struct blocklevel_info bl_info;
> >
> > -             rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
> > +             rc = blocklevel_get_info(bl, &bl_info);
> >               if (rc)
> >                       return rc;
> >
> > -             return blocklevel_erase(bl, 0, total_size);
> > +             return blocklevel_erase(bl, 0, bl_info.size);
> >       }
> >
> >       return flash_erase_chip(arch_data.flash_chip);
> > diff --git a/external/common/arch_flash_common.c
> b/external/common/arch_flash_common.c
> > index 6bce7e1ba..41239662a 100644
> > --- a/external/common/arch_flash_common.c
> > +++ b/external/common/arch_flash_common.c
> > @@ -31,13 +31,13 @@
> >  int __attribute__((weak)) arch_flash_erase_chip(struct
> blocklevel_device *bl)
> >  {
> >       int rc;
> > -     uint64_t total_size;
> > +     struct blocklevel_info bl_info;
> >
> > -     rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
> > +     rc = blocklevel_get_info(bl, &bl_info);
> >       if (rc)
> >               return rc;
> >
> > -     return blocklevel_erase(bl, 0, total_size);
> > +     return blocklevel_erase(bl, 0, bl_info.size);
> >  }
> >
> >  int __attribute__((weak,const)) arch_flash_4b_mode(struct
> blocklevel_device *bl, int set_4b)
> > diff --git a/external/gard/gard.c b/external/gard/gard.c
> > index c5cb93b88..3946cad6f 100644
> > --- a/external/gard/gard.c
> > +++ b/external/gard/gard.c
> > @@ -596,7 +596,7 @@ int main(int argc, char **argv)
> >       const char *action, *progname;
> >       char *filename = NULL;
> >       struct gard_ctx _ctx, *ctx;
> > -     uint64_t bl_size;
> > +     struct blocklevel_info bl_info;
> >       int rc, i = 0;
> >       bool part = 0;
> >       bool ecc = 0;
> > @@ -665,17 +665,17 @@ int main(int argc, char **argv)
> >               goto out_free;
> >       }
> >
> > -     rc = blocklevel_get_info(ctx->bl, NULL, &bl_size, NULL);
> > +     rc = blocklevel_get_info(ctx->bl, &bl_info);
> >       if (rc)
> >               goto out;
> >
> > -     if (bl_size > UINT_MAX) {
> > +     if (bl_info.size > UINT_MAX) {
> >               fprintf(stderr, "MTD device bigger than %i: size: %"
> PRIu64 "\n",
> > -                     UINT_MAX, bl_size);
> > +                     UINT_MAX, bl_info.size);
> >               rc = EXIT_FAILURE;
> >               goto out;
> >       }
> > -     ctx->f_size = bl_size;
> > +     ctx->f_size = bl_info.size;
> >
> >       if (!part) {
> >               rc = ffs_init(0, ctx->f_size, ctx->bl, &ctx->ffs, 1);
> > diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c
> > index c032421d1..afb6ccd1f 100644
> > --- a/external/opal-prd/pnor.c
> > +++ b/external/opal-prd/pnor.c
> > @@ -64,13 +64,13 @@ int pnor_init(struct pnor *pnor)
> >               return -1;
> >       }
> >
> > -     rc = blocklevel_get_info(pnor->bl, NULL, &(pnor->size),
> &(pnor->erasesize));
> > +     rc = blocklevel_get_info(pnor->bl, &pnor->bl_info);
> >       if (rc) {
> >               pr_log(LOG_ERR, "PNOR: blocklevel_get_info() failed. Can't
> use PNOR");
> >               goto out;
> >       }
> >
> > -     rc = ffs_init(0, pnor->size, pnor->bl, &pnor->ffsh, 0);
> > +     rc = ffs_init(0, pnor->bl_info.size, pnor->bl, &pnor->ffsh, 0);
> >       if (rc) {
> >               pr_log(LOG_ERR, "PNOR: Failed to open pnor partition
> table");
> >               goto out;
> > @@ -121,8 +121,8 @@ static int mtd_write(struct pnor *pnor, void *data,
> uint64_t offset,
> >  {
> >       int rc;
> >
> > -     if (len > pnor->size || offset > pnor->size ||
> > -         len + offset > pnor->size)
> > +     if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
> > +         len + offset > pnor->bl_info.size)
> >               return -ERANGE;
> >
> >       rc = blocklevel_smart_write(pnor->bl, offset, data, len);
> > @@ -137,8 +137,8 @@ static int mtd_read(struct pnor *pnor, void *data,
> uint64_t offset,
> >  {
> >       int rc;
> >
> > -     if (len > pnor->size || offset > pnor->size ||
> > -         len + offset > pnor->size)
> > +     if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
> > +         len + offset > pnor->bl_info.size)
> >               return -ERANGE;
> >
> >       rc = blocklevel_read(pnor->bl, offset, data, len);
> > diff --git a/external/opal-prd/pnor.h b/external/opal-prd/pnor.h
> > index 28571af64..1ee033659 100644
> > --- a/external/opal-prd/pnor.h
> > +++ b/external/opal-prd/pnor.h
> > @@ -7,8 +7,7 @@
> >  struct pnor {
> >       char                    *path;
> >       struct ffs_handle       *ffsh;
> > -     uint64_t                size;
> > -     uint32_t                erasesize;
> > +     struct blocklevel_info bl_info;
> >       struct blocklevel_device *bl;
> >  };
> >
> > diff --git a/external/opal-prd/test/test_pnor_ops.c
> b/external/opal-prd/test/test_pnor_ops.c
> > index fd5e2c22a..3743362e1 100644
> > --- a/external/opal-prd/test/test_pnor_ops.c
> > +++ b/external/opal-prd/test/test_pnor_ops.c
> > @@ -130,11 +130,14 @@ int main(int argc, char **argv)
> >       for (i = 0; i < 2; i++)
> >               write(fd, data, 16);
> >
> > +     /* Unused */
> > +     pnor.bl_info.name = NULL;
> > +
> >       /* Adjust this if making the file smaller */
> > -     pnor.size = 32;
> > +     pnor.bl_info.size = 32;
> >
> >       /* This is fake. Make it smaller than the size */
> > -     pnor.erasesize = 4;
> > +     pnor.bl_info.erase_granule = 4;
> >
> >       printf("Write: ");
> >       memset(data, 'A', sizeof(data));
> > diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c
> > index bfc975fe5..3f501e583 100644
> > --- a/external/pflash/pflash.c
> > +++ b/external/pflash/pflash.c
> > @@ -43,11 +43,9 @@
> >
> >  struct flash_details {
> >       struct blocklevel_device *bl;
> > +     struct blocklevel_info bl_info;
> >       int need_relock;
> > -     const char *name;
> >       uint64_t toc;
> > -     uint64_t total_size;
> > -     uint32_t erase_granule;
> >  };
> >
> >  /* Full pflash version number (possibly includes gitid). */
> > @@ -144,7 +142,7 @@ static struct ffs_handle *open_ffs(struct
> flash_details *flash)
> >       struct ffs_handle *ffsh;
> >       int rc;
> >
> > -     rc = ffs_init(flash->toc, flash->total_size,
> > +     rc = ffs_init(flash->toc, flash->bl_info.size,
> >                       flash->bl, &ffsh, 0);
> >       if (rc) {
> >               fprintf(stderr, "Error %d opening ffs !\n", rc);
> > @@ -166,11 +164,11 @@ static void print_flash_info(struct flash_details
> *flash)
> >
> >       printf("Flash info:\n");
> >       printf("-----------\n");
> > -     printf("Name          = %s\n", flash->name);
> > +     printf("Name          = %s\n", flash->bl_info.name);
> >       printf("Total size    = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED,
> R:READONLY\n",
> > -                     flash->total_size >> 20);
> > +                     flash->bl_info.size >> 20);
> >       printf("Erase granule = %2d%-13sB:BACKUP, F:REPROVISION\n",
> > -                     flash->erase_granule >> 10, "KB");
> > +                     flash->bl_info.erase_granule >> 10, "KB");
> >
> >       if (bmc_flash)
> >               return;
> > @@ -282,9 +280,11 @@ static int erase_chip(struct flash_details *flash)
> >        * likes the progress bars.
> >        * Lets do an erase block at a time erase then...
> >        */
> > -     progress_init(flash->total_size);
> > -     for (pos = 0; pos < flash->total_size; pos +=
> flash->erase_granule) {
> > -             rc = blocklevel_erase(flash->bl, pos,
> flash->erase_granule);
> > +     progress_init(flash->bl_info.size);
> > +     for (pos = 0; pos < flash->bl_info.size;
> > +                     pos += flash->bl_info.erase_granule) {
> > +             rc = blocklevel_erase(flash->bl, pos,
> > +                             flash->bl_info.erase_granule);
> >               if (rc)
> >                       break;
> >               progress_tick(pos);
> > @@ -303,7 +303,7 @@ static int erase_range(struct flash_details *flash,
> >               uint32_t start, uint32_t size, bool will_program,
> >               struct ffs_handle *ffsh, int ffs_index)
> >  {
> > -     uint32_t done = 0, erase_mask = flash->erase_granule - 1;
> > +     uint32_t done = 0, erase_mask = flash->bl_info.erase_granule - 1;
> >       bool confirm;
> >       int rc;
> >
> > @@ -326,25 +326,26 @@ static int erase_range(struct flash_details *flash,
> >       if (start & erase_mask) {
> >               /* Align to next erase block */
> >               rc = blocklevel_smart_erase(flash->bl, start,
> > -                             flash->erase_granule - (start &
> erase_mask));
> > +                             flash->bl_info.erase_granule - (start &
> erase_mask));
> >               if (rc) {
> >                       fprintf(stderr, "Failed to
> blocklevel_smart_erase(): %d\n", rc);
> >                       return 1;
> >               }
> > -             start += flash->erase_granule - (start & erase_mask);
> > -             size -= flash->erase_granule - (start & erase_mask);
> > -             done = flash->erase_granule - (start & erase_mask);
> > +             start += flash->bl_info.erase_granule - (start &
> erase_mask);
> > +             size -= flash->bl_info.erase_granule - (start &
> erase_mask);
> > +             done = flash->bl_info.erase_granule - (start & erase_mask);
> >       }
> >       progress_tick(done);
> >       while (size & ~(erase_mask)) {
> > -             rc = blocklevel_smart_erase(flash->bl, start,
> flash->erase_granule);
> > +             rc = blocklevel_smart_erase(flash->bl, start,
> > +                             flash->bl_info.erase_granule);
> >               if (rc) {
> >                       fprintf(stderr, "Failed to
> blocklevel_smart_erase(): %d\n", rc);
> >                       return 1;
> >               }
> > -             start += flash->erase_granule;
> > -             size -= flash->erase_granule;
> > -             done += flash->erase_granule;
> > +             start += flash->bl_info.erase_granule;
> > +             size -= flash->bl_info.erase_granule;
> > +             done += flash->bl_info.erase_granule;
> >               progress_tick(done);
> >       }
> >       if (size) {
> > @@ -1003,8 +1004,7 @@ int main(int argc, char *argv[])
> >               goto out;
> >       }
> >
> > -     rc = blocklevel_get_info(flash.bl, &flash.name,
> > -                         &flash.total_size, &flash.erase_granule);
> > +     rc = blocklevel_get_info(flash.bl, &flash.bl_info);
> >       if (rc) {
> >               fprintf(stderr, "Error %d getting flash info\n", rc);
> >               rc = 1;
> > @@ -1025,7 +1025,7 @@ int main(int argc, char *argv[])
> >
> >       /* If read specified and no read_size, use flash size */
> >       if (do_read && !read_size && !part_name)
> > -             read_size = flash.total_size;
> > +             read_size = flash.bl_info.size;
> >
> >       /* We have a partition, adjust read/write size if needed */
> >       if (part_name || print_detail) {
> > @@ -1087,7 +1087,7 @@ int main(int argc, char *argv[])
> >               /* Set address */
> >               address = pstart;
> >       } else if (erase) {
> > -             if ((address | write_size) & (flash.erase_granule - 1)) {
> > +             if ((address | write_size) & (flash.bl_info.erase_granule
> - 1)) {
> >                       if (must_confirm) {
> >                               printf("ERROR: Erase at 0x%08x for 0x%08x
> isn't erase block aligned\n",
> >                                               address, write_size);
> > diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
> > index 33d5c5d2f..3955be823 100644
> > --- a/libflash/blocklevel.c
> > +++ b/libflash/blocklevel.c
> > @@ -229,12 +229,11 @@ int blocklevel_erase(struct blocklevel_device *bl,
> uint64_t pos, uint64_t len)
> >       return rc;
> >  }
> >
> > -int blocklevel_get_info(struct blocklevel_device *bl, const char
> **name, uint64_t *total_size,
> > -             uint32_t *erase_granule)
> > +int blocklevel_get_info(struct blocklevel_device *bl, struct
> blocklevel_info *bl_info)
> >  {
> >       int rc;
> >
> > -     if (!bl || !bl->get_info) {
> > +     if (!bl || !bl->get_info || !bl_info) {
> >               errno = EINVAL;
> >               return FLASH_ERR_PARM_ERROR;
> >       }
> > @@ -243,12 +242,12 @@ int blocklevel_get_info(struct blocklevel_device
> *bl, const char **name, uint64_
> >       if (rc)
> >               return rc;
> >
> > -     rc = bl->get_info(bl, name, total_size, erase_granule);
> > +     rc = bl->get_info(bl, bl_info);
> >
> >       /* Check the validity of what we are being told */
> > -     if (erase_granule && *erase_granule != bl->erase_mask + 1)
> > +     if (bl_info->erase_granule != bl->erase_mask + 1)
> >               FL_ERR("blocklevel_get_info: WARNING: erase_granule
> (0x%08x) and erase_mask"
> > -                             " (0x%08x) don't match\n", *erase_granule,
> bl->erase_mask + 1);
> > +                             " (0x%08x) don't match\n",
> bl_info->erase_granule, bl->erase_mask + 1);
> >
> >       release(bl);
> >
> > @@ -417,7 +416,7 @@ out:
> >
> >  int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos,
> const void *buf, uint64_t len)
> >  {
> > -     uint32_t erase_size;
> > +     struct blocklevel_info bl_info;
> >       const void *write_buf = buf;
> >       void *write_buf_start = NULL;
> >       void *erase_buf;
> > @@ -435,7 +434,7 @@ int blocklevel_smart_write(struct blocklevel_device
> *bl, uint64_t pos, const voi
> >               return blocklevel_write(bl, pos, buf, len);
> >       }
> >
> > -     rc = blocklevel_get_info(bl, NULL, NULL, &erase_size);
> > +     rc = blocklevel_get_info(bl, &bl_info);
> >       if (rc)
> >               return rc;
> >
> > @@ -458,7 +457,7 @@ int blocklevel_smart_write(struct blocklevel_device
> *bl, uint64_t pos, const voi
> >               write_buf = write_buf_start;
> >       }
> >
> > -     erase_buf = malloc(erase_size);
> > +     erase_buf = malloc(bl_info.erase_granule);
> >       if (!erase_buf) {
> >               errno = ENOMEM;
> >               rc = FLASH_ERR_MALLOC_FAILED;
> > @@ -470,32 +469,32 @@ int blocklevel_smart_write(struct
> blocklevel_device *bl, uint64_t pos, const voi
> >               goto out_free;
> >
> >       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;
> > +             uint32_t erase_block = pos & ~(bl_info.erase_granule - 1);
> > +             uint32_t block_offset = pos & (bl_info.erase_granule - 1);
> > +             uint32_t size = bl_info.erase_granule > len ? len :
> bl_info.erase_granule;
> >               int cmp;
> >
> >               /* Write crosses an erase boundary, shrink the write to
> the boundary */
> > -             if (erase_size < block_offset + size) {
> > -                     size = erase_size - block_offset;
> > +             if (bl_info.erase_granule < block_offset + size) {
> > +                     size = bl_info.erase_granule - block_offset;
> >               }
> >
> > -             rc = bl->read(bl, erase_block, erase_buf, erase_size);
> > +             rc = bl->read(bl, erase_block, erase_buf,
> bl_info.erase_granule);
> >               if (rc)
> >                       goto out;
> >
> >               cmp = blocklevel_flashcmp(erase_buf + block_offset,
> write_buf, size);
> >               FL_DBG("%s: region 0x%08x..0x%08x ", __func__,
> > -                             erase_block, erase_size);
> > +                             erase_block, bl_info.erase_granule);
> >               if (cmp != 0) {
> >                       FL_DBG("needs ");
> >                       if (cmp == -1) {
> >                               FL_DBG("erase and ");
> > -                             bl->erase(bl, erase_block, erase_size);
> > +                             bl->erase(bl, erase_block,
> bl_info.erase_granule);
> >                       }
> >                       FL_DBG("write\n");
> >                       memcpy(erase_buf + block_offset, write_buf, size);
> > -                     rc = bl->write(bl, erase_block, erase_buf,
> erase_size);
> > +                     rc = bl->write(bl, erase_block, erase_buf,
> bl_info.erase_granule);
> >                       if (rc)
> >                               goto out;
> >               }
> > diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
> > index ba42c83d0..d2d269054 100644
> > --- a/libflash/blocklevel.h
> > +++ b/libflash/blocklevel.h
> > @@ -34,6 +34,15 @@ enum blocklevel_flags {
> >       WRITE_NEED_ERASE = 1,
> >  };
> >
> > +struct blocklevel_info {
> > +     /* name is not owned by this struct and must persist for the
> > +      * liftime of blocklevel_info
> > +      */
> > +     const char *name;
> > +     uint64_t size;
> > +     uint32_t erase_granule;
> > +};
> > +
> >  /*
> >   * libffs may be used with different backends, all should provide these
> for
> >   * libflash to get the information it needs
> > @@ -45,8 +54,7 @@ struct blocklevel_device {
> >       int (*read)(struct blocklevel_device *bl, uint64_t pos, void *buf,
> uint64_t len);
> >       int (*write)(struct blocklevel_device *bl, uint64_t pos, const
> void *buf, uint64_t len);
> >       int (*erase)(struct blocklevel_device *bl, uint64_t pos, uint64_t
> len);
> > -     int (*get_info)(struct blocklevel_device *bl, const char **name,
> uint64_t *total_size,
> > -                     uint32_t *erase_granule);
> > +     int (*get_info)(struct blocklevel_device *bl, struct
> blocklevel_info *bl_info);
> >
> >       /*
> >        * Keep the erase mask so that blocklevel_erase() can do sanity
> checking
> > @@ -62,8 +70,8 @@ int blocklevel_read(struct blocklevel_device *bl,
> uint64_t pos, void *buf, uint6
> >  int blocklevel_raw_write(struct blocklevel_device *bl, uint64_t pos,
> const void *buf, uint64_t len);
> >  int blocklevel_write(struct blocklevel_device *bl, uint64_t pos, const
> void *buf, uint64_t len);
> >  int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos,
> uint64_t len);
> > -int blocklevel_get_info(struct blocklevel_device *bl, const char
> **name, uint64_t *total_size,
> > -             uint32_t *erase_granule);
> > +
> > +int blocklevel_get_info(struct blocklevel_device *bl, struct
> blocklevel_info *bl_info);
> >
> >  /*
> >   * blocklevel_smart_write() performs reads on the data to see if it
> > diff --git a/libflash/file.c b/libflash/file.c
> > index 7065eb4fa..b87679cd1 100644
> > --- a/libflash/file.c
> > +++ b/libflash/file.c
> > @@ -212,6 +212,7 @@ static int get_info_name(struct file_data
> *file_data, char **name)
> >       }
> >       lpath[len] = '\0';
> >
> > +     free(*name);
> >       *name = lpath;
> >
> >       free(path);
> > @@ -219,8 +220,8 @@ static int get_info_name(struct file_data
> *file_data, char **name)
> >  }
> >
> >
> > -static int mtd_get_info(struct blocklevel_device *bl, const char **name,
> > -             uint64_t *total_size, uint32_t *erase_granule)
> > +static int mtd_get_info(struct blocklevel_device *bl,
> > +             struct blocklevel_info *bl_info)
> >  {
> >       struct file_data *file_data = container_of(bl, struct file_data,
> bl);
> >       struct mtd_info_user mtd_info;
> > @@ -230,24 +231,19 @@ static int mtd_get_info(struct blocklevel_device
> *bl, const char **name,
> >       if (rc == -1)
> >               return FLASH_ERR_BAD_READ;
> >
> > -     if (total_size)
> > -             *total_size = mtd_info.size;
> > -
> > -     if (erase_granule)
> > -             *erase_granule = mtd_info.erasesize;
> > +     rc = get_info_name(file_data, &(file_data->name));
> > +     if (rc)
> > +             return rc;
> >
> > -     if (name) {
> > -             rc = get_info_name(file_data, &(file_data->name));
> > -             if (rc)
> > -                     return rc;
> > -             *name = file_data->name;
> > -     }
> > +     bl_info->name = file_data->name;
> > +     bl_info->size = mtd_info.size;
> > +     bl_info->erase_granule = mtd_info.erasesize;
> >
> >       return 0;
> >  }
> >
> > -static int file_get_info(struct blocklevel_device *bl, const char
> **name,
> > -             uint64_t *total_size, uint32_t *erase_granule)
> > +static int file_get_info(struct blocklevel_device *bl,
> > +             struct blocklevel_info *bl_info)
> >  {
> >       struct file_data *file_data = container_of(bl, struct file_data,
> bl);
> >       struct stat st;
> > @@ -256,18 +252,13 @@ static int file_get_info(struct blocklevel_device
> *bl, const char **name,
> >       if (fstat(file_data->fd, &st))
> >               return FLASH_ERR_PARM_ERROR;
> >
> > -     if (total_size)
> > -             *total_size = st.st_size;
> > -
> > -     if (erase_granule)
> > -             *erase_granule = 1;
> > +     rc = get_info_name(file_data, &(file_data->name));
> > +     if (rc)
> > +             return rc;
> >
> > -     if (name) {
> > -             rc = get_info_name(file_data, &(file_data->name));
> > -             if (rc)
> > -                     return rc;
> > -             *name = file_data->name;
> > -     }
> > +     bl_info->name = file_data->name;
> > +     bl_info->size = st.st_size;
> > +     bl_info->erase_granule = 1;
> >
> >       return 0;
> >  }
> > @@ -315,8 +306,9 @@ int file_init(int fd, struct blocklevel_device **bl)
> >               file_data->bl.erase = &mtd_erase;
> >               file_data->bl.get_info = &mtd_get_info;
> >               file_data->bl.flags = WRITE_NEED_ERASE;
> > -             mtd_get_info(&file_data->bl, NULL, NULL,
> &(file_data->bl.erase_mask));
> > -             file_data->bl.erase_mask--;
> > +             struct blocklevel_info bl_info;
> > +             mtd_get_info(&file_data->bl, &bl_info);
> > +             file_data->bl.erase_mask = bl_info.erase_granule - 1;
> >       } else if (!S_ISREG(sbuf.st_mode)) {
> >               /* If not a char device or a regular file something went
> wrong */
> >               goto out;
> > diff --git a/libflash/libffs.c b/libflash/libffs.c
> > index 038f59425..6fc23eee9 100644
> > --- a/libflash/libffs.c
> > +++ b/libflash/libffs.c
> > @@ -216,25 +216,25 @@ int ffs_init(uint32_t offset, uint32_t max_size,
> struct blocklevel_device *bl,
> >  {
> >       struct __ffs_hdr blank_hdr;
> >       struct __ffs_hdr raw_hdr;
> > +     struct blocklevel_info bl_info;
> >       struct ffs_handle *f;
> > -     uint64_t total_size;
> >       int rc, i;
> >
> >       if (!ffs || !bl)
> >               return FLASH_ERR_PARM_ERROR;
> >       *ffs = NULL;
> >
> > -     rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
> > +     rc = blocklevel_get_info(bl, &bl_info);
> >       if (rc) {
> >               FL_ERR("FFS: Error %d retrieving flash info\n", rc);
> >               return rc;
> >       }
> > -     if (total_size > UINT_MAX)
> > +     if (bl_info.size > UINT_MAX)
> >               return FLASH_ERR_VERIFY_FAILURE;
> >       if ((offset + max_size) < offset)
> >               return FLASH_ERR_PARM_ERROR;
> >
> > -     if ((max_size > total_size))
> > +     if ((max_size > bl_info.size))
> >               return FLASH_ERR_PARM_ERROR;
> >
> >       /* Read flash header */
> > diff --git a/libflash/libflash.c b/libflash/libflash.c
> > index 38f87b86e..82a2baecc 100644
> > --- a/libflash/libflash.c
> > +++ b/libflash/libflash.c
> > @@ -792,16 +792,15 @@ static int flash_configure(struct flash_chip *c)
> >       return 0;
> >  }
> >
> > -static int flash_get_info(struct blocklevel_device *bl, const char
> **name,
> > -                uint64_t *total_size, uint32_t *erase_granule)
> > +static int flash_get_info(struct blocklevel_device *bl,
> > +             struct blocklevel_info *bl_info)
> >  {
> >       struct flash_chip *c = container_of(bl, struct flash_chip, bl);
> > -     if (name)
> > -             *name = c->info.name;
> > -     if (total_size)
> > -             *total_size = c->tsize;
> > -     if (erase_granule)
> > -             *erase_granule = c->min_erase_mask + 1;
> > +
> > +     bl_info->name = c->info.name;
> > +     bl_info->size = c->tsize;
> > +     bl_info->erase_granule = c->min_erase_mask + 1;
> > +
> >       return 0;
> >  }
> >
> > diff --git a/libflash/mbox-flash.c b/libflash/mbox-flash.c
> > index 950e24f05..d4200ce53 100644
> > --- a/libflash/mbox-flash.c
> > +++ b/libflash/mbox-flash.c
> > @@ -745,8 +745,8 @@ static int mbox_flash_read(struct blocklevel_device
> *bl, uint64_t pos,
> >       return rc;
> >  }
> >
> > -static int mbox_flash_get_info(struct blocklevel_device *bl, const char
> **name,
> > -             uint64_t *total_size, uint32_t *erase_granule)
> > +static int mbox_flash_get_info(struct blocklevel_device *bl,
> > +             struct blocklevel_info *bl_info)
> >  {
> >       struct mbox_flash_data *mbox_flash;
> >       struct bmc_mbox_msg *msg;
> > @@ -761,14 +761,7 @@ static int mbox_flash_get_info(struct
> blocklevel_device *bl, const char **name,
> >       if (!msg)
> >               return FLASH_ERR_MALLOC_FAILED;
> >
> > -     /*
> > -      * We want to avoid runtime mallocs in skiboot. The expected
> > -      * behavour to uses of libflash is that one can free() the memory
> > -      * returned.
> > -      * NULL will do for now.
> > -      */
> > -     if (name)
> > -             *name = NULL;
> > +     bl_info->name = "pnor_mbox";
> >
> >       mbox_flash->busy = true;
> >       rc = msg_send(mbox_flash, msg);
> > @@ -784,10 +777,8 @@ static int mbox_flash_get_info(struct
> blocklevel_device *bl, const char **name,
> >
> >       mbox_flash->bl.erase_mask = mbox_flash->erase_granule - 1;
> >
> > -     if (total_size)
> > -             *total_size = mbox_flash->total_size;
> > -     if (erase_granule)
> > -             *erase_granule = mbox_flash->erase_granule;
> > +     bl_info->size = mbox_flash->total_size;
> > +     bl_info->erase_granule = mbox_flash->erase_granule;
> >
> >  out:
> >       msg_free_memory(msg);
> > diff --git a/libflash/test/test-flash.c b/libflash/test/test-flash.c
> > index 3f77d6f3e..1ca467bb0 100644
> > --- a/libflash/test/test-flash.c
> > +++ b/libflash/test/test-flash.c
> > @@ -367,9 +367,7 @@ struct spi_flash_ctrl sim_ctrl = {
> >  int main(void)
> >  {
> >       struct blocklevel_device *bl;
> > -     uint64_t total_size;
> > -     uint32_t erase_granule;
> > -     const char *name;
> > +     struct blocklevel_info bl_info;
> >       uint16_t *test;
> >       struct ecc64 *ecc_test;
> >       uint64_t *test64;
> > @@ -384,7 +382,7 @@ int main(void)
> >               ERR("flash_init failed with err %d\n", rc);
> >               exit(1);
> >       }
> > -     rc = flash_get_info(bl, &name, &total_size, &erase_granule);
> > +     rc = flash_get_info(bl, &bl_info);
> >       if (rc) {
> >               ERR("flash_get_info failed with err %d\n", rc);
> >               exit(1);
> > diff --git a/platforms/mambo/mambo.c b/platforms/mambo/mambo.c
> > index cb6e103cc..dd7872a8e 100644
> > --- a/platforms/mambo/mambo.c
> > +++ b/platforms/mambo/mambo.c
> > @@ -125,19 +125,14 @@ static int bogus_disk_erase(struct
> blocklevel_device *bl __unused,
> >       return 0; /* NOP */
> >  }
> >
> > -static int bogus_disk_get_info(struct blocklevel_device *bl, const char
> **name,
> > -                           uint64_t *total_size, uint32_t
> *erase_granule)
> > +static int bogus_disk_get_info(struct blocklevel_device *bl,
> > +                     struct blocklevel_info *bl_info)
> >  {
> >       struct bogus_disk_info *bdi = bl->priv;
> >
> > -     if (total_size)
> > -             *total_size = bdi->size;
> > -
> > -     if (erase_granule)
> > -             *erase_granule = BD_SECT_SZ;
> > -
> > -     if (name)
> > -             *name = "mambobogus";
> > +     bl_info->name = "mambobogus";
> > +     bl_info->size = bdi->size;
> > +     bl_info->erase_granule = BD_SECT_SZ;
> >
> >       return 0;
> >  }
>
<div dir="ltr">Cyril,<div><br></div><div>Sounds good. I actually wrote this up a couple of months back, but I&#39;d like to upstream as many of our changes as possible. It just occurred to me that we may not actually need this change at all to support one of the flash changes we made. It would be nice to clean up these interfaces though.</div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Aug 28, 2017 at 10:38 PM Cyril Bur &lt;<a href="mailto:cyrilbur@gmail.com">cyrilbur@gmail.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Mon, 2017-08-28 at 21:19 -0700, William A. Kennington III wrote:<br>
&gt; This changes refactors all of the output variables from flash_get_info<br>
&gt; into a new output struct. Callers now supply the info struct, and always<br>
&gt; get all of the info with each call. There are never any allocations done<br>
&gt; by this function so it shouldn&#39;t be much slower to always populate all<br>
&gt; of the information.<br>
&gt;<br>
<br>
Hi William,<br>
<br>
As nice as this refactor is (thanks for the effort!), unfortunately<br>
we&#39;re a bit stuck with the interface as is, both openbmc and petitboot<br>
projects link against a dynamic libflash.<br>
<br>
Ironically I&#39;m about to send a series which which does rework the<br>
libffs api a bit - although I&#39;m quite sure only external/ffspart<br>
actually uses what I&#39;ve changed. blocklevel_get_info() though is pretty<br>
core and changing that won&#39;t work.<br>
<br>
Perhaps you&#39;ve prompted a discussion that now might be a good time to<br>
do a significant rewrite of libflash/libffs which are now being used<br>
for a completely different purpose for which they were first written,<br>
hopefully Stewart will weigh in.<br>
<br>
<br>
Cyril<br>
<br>
&gt; Signed-off-by: William A. Kennington III &lt;<a href="mailto:wak@google.com" target="_blank">wak@google.com</a>&gt;<br>
&gt; ---<br>
&gt;  core/flash.c                           | 15 +++++------<br>
&gt;  external/common/arch_flash_arm.c       |  6 ++---<br>
&gt;  external/common/arch_flash_common.c    |  6 ++---<br>
&gt;  external/gard/gard.c                   | 10 +++----<br>
&gt;  external/opal-prd/pnor.c               | 12 ++++-----<br>
&gt;  external/opal-prd/pnor.h               |  3 +--<br>
&gt;  external/opal-prd/test/test_pnor_ops.c |  7 +++--<br>
&gt;  external/pflash/pflash.c               | 46 ++++++++++++++++----------------<br>
&gt;  libflash/blocklevel.c                  | 35 ++++++++++++-------------<br>
&gt;  libflash/blocklevel.h                  | 16 +++++++++---<br>
&gt;  libflash/file.c                        | 48 ++++++++++++++--------------------<br>
&gt;  libflash/libffs.c                      |  8 +++---<br>
&gt;  libflash/libflash.c                    | 15 +++++------<br>
&gt;  libflash/mbox-flash.c                  | 19 ++++----------<br>
&gt;  libflash/test/test-flash.c             |  6 ++---<br>
&gt;  platforms/mambo/mambo.c                | 15 ++++-------<br>
&gt;  16 files changed, 125 insertions(+), 142 deletions(-)<br>
&gt;<br>
&gt; diff --git a/core/flash.c b/core/flash.c<br>
&gt; index 53e6eba08..35a0c4c32 100644<br>
&gt; --- a/core/flash.c<br>
&gt; +++ b/core/flash.c<br>
&gt; @@ -254,21 +254,20 @@ static int num_flashes(void)<br>
&gt;<br>
&gt;  int flash_register(struct blocklevel_device *bl)<br>
&gt;  {<br>
&gt; -     uint64_t size;<br>
&gt; -     uint32_t block_size;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;       struct ffs_handle *ffs;<br>
&gt;       struct dt_node *node;<br>
&gt;       struct flash *flash;<br>
&gt; -     const char *name;<br>
&gt;       int rc;<br>
&gt;<br>
&gt; -     rc = blocklevel_get_info(bl, &amp;name, &amp;size, &amp;block_size);<br>
&gt; +     rc = blocklevel_get_info(bl, &amp;bl_info);<br>
&gt;       if (rc)<br>
&gt;               return rc;<br>
&gt;<br>
&gt;       prlog(PR_INFO, &quot;FLASH: registering flash device %s &quot;<br>
&gt;                       &quot;(size 0x%llx, blocksize 0x%x)\n&quot;,<br>
&gt; -                     name ?: &quot;(unnamed)&quot;, size, block_size);<br>
&gt; +                     <a href="http://bl_info.name" rel="noreferrer" target="_blank">bl_info.name</a> ? <a href="http://bl_info.name" rel="noreferrer" target="_blank">bl_info.name</a> : &quot;(unnamed)&quot;, bl_info.size,<br>
&gt; +                     bl_info.erase_granule);<br>
&gt;<br>
&gt;       lock(&amp;flash_lock);<br>
&gt;<br>
&gt; @@ -281,8 +280,8 @@ int flash_register(struct blocklevel_device *bl)<br>
&gt;<br>
&gt;       flash-&gt;busy = false;<br>
&gt;       flash-&gt;bl = bl;<br>
&gt; -     flash-&gt;size = size;<br>
&gt; -     flash-&gt;block_size = block_size;<br>
&gt; +     flash-&gt;size = bl_info.size;<br>
&gt; +     flash-&gt;block_size = bl_info.erase_granule;<br>
&gt;       flash-&gt;id = num_flashes();<br>
&gt;<br>
&gt;       list_add(&amp;flashes, &amp;flash-&gt;list);<br>
&gt; @@ -302,7 +301,7 @@ int flash_register(struct blocklevel_device *bl)<br>
&gt;<br>
&gt;       node = flash_add_dt_node(flash, flash-&gt;id);<br>
&gt;<br>
&gt; -     setup_system_flash(flash, node, name, ffs);<br>
&gt; +     setup_system_flash(flash, node, <a href="http://bl_info.name" rel="noreferrer" target="_blank">bl_info.name</a>, ffs);<br>
&gt;<br>
&gt;       if (ffs)<br>
&gt;               ffs_close(ffs);<br>
&gt; diff --git a/external/common/arch_flash_arm.c b/external/common/arch_flash_arm.c<br>
&gt; index 3cdd41ded..ac43de0c4 100644<br>
&gt; --- a/external/common/arch_flash_arm.c<br>
&gt; +++ b/external/common/arch_flash_arm.c<br>
&gt; @@ -303,13 +303,13 @@ int arch_flash_erase_chip(struct blocklevel_device *bl)<br>
&gt;       if (!arch_data.flash_chip) {<br>
&gt;               /* Just assume its a regular erase */<br>
&gt;               int rc;<br>
&gt; -             uint64_t total_size;<br>
&gt; +             struct blocklevel_info bl_info;<br>
&gt;<br>
&gt; -             rc = blocklevel_get_info(bl, NULL, &amp;total_size, NULL);<br>
&gt; +             rc = blocklevel_get_info(bl, &amp;bl_info);<br>
&gt;               if (rc)<br>
&gt;                       return rc;<br>
&gt;<br>
&gt; -             return blocklevel_erase(bl, 0, total_size);<br>
&gt; +             return blocklevel_erase(bl, 0, bl_info.size);<br>
&gt;       }<br>
&gt;<br>
&gt;       return flash_erase_chip(arch_data.flash_chip);<br>
&gt; diff --git a/external/common/arch_flash_common.c b/external/common/arch_flash_common.c<br>
&gt; index 6bce7e1ba..41239662a 100644<br>
&gt; --- a/external/common/arch_flash_common.c<br>
&gt; +++ b/external/common/arch_flash_common.c<br>
&gt; @@ -31,13 +31,13 @@<br>
&gt;  int __attribute__((weak)) arch_flash_erase_chip(struct blocklevel_device *bl)<br>
&gt;  {<br>
&gt;       int rc;<br>
&gt; -     uint64_t total_size;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;<br>
&gt; -     rc = blocklevel_get_info(bl, NULL, &amp;total_size, NULL);<br>
&gt; +     rc = blocklevel_get_info(bl, &amp;bl_info);<br>
&gt;       if (rc)<br>
&gt;               return rc;<br>
&gt;<br>
&gt; -     return blocklevel_erase(bl, 0, total_size);<br>
&gt; +     return blocklevel_erase(bl, 0, bl_info.size);<br>
&gt;  }<br>
&gt;<br>
&gt;  int __attribute__((weak,const)) arch_flash_4b_mode(struct blocklevel_device *bl, int set_4b)<br>
&gt; diff --git a/external/gard/gard.c b/external/gard/gard.c<br>
&gt; index c5cb93b88..3946cad6f 100644<br>
&gt; --- a/external/gard/gard.c<br>
&gt; +++ b/external/gard/gard.c<br>
&gt; @@ -596,7 +596,7 @@ int main(int argc, char **argv)<br>
&gt;       const char *action, *progname;<br>
&gt;       char *filename = NULL;<br>
&gt;       struct gard_ctx _ctx, *ctx;<br>
&gt; -     uint64_t bl_size;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;       int rc, i = 0;<br>
&gt;       bool part = 0;<br>
&gt;       bool ecc = 0;<br>
&gt; @@ -665,17 +665,17 @@ int main(int argc, char **argv)<br>
&gt;               goto out_free;<br>
&gt;       }<br>
&gt;<br>
&gt; -     rc = blocklevel_get_info(ctx-&gt;bl, NULL, &amp;bl_size, NULL);<br>
&gt; +     rc = blocklevel_get_info(ctx-&gt;bl, &amp;bl_info);<br>
&gt;       if (rc)<br>
&gt;               goto out;<br>
&gt;<br>
&gt; -     if (bl_size &gt; UINT_MAX) {<br>
&gt; +     if (bl_info.size &gt; UINT_MAX) {<br>
&gt;               fprintf(stderr, &quot;MTD device bigger than %i: size: %&quot; PRIu64 &quot;\n&quot;,<br>
&gt; -                     UINT_MAX, bl_size);<br>
&gt; +                     UINT_MAX, bl_info.size);<br>
&gt;               rc = EXIT_FAILURE;<br>
&gt;               goto out;<br>
&gt;       }<br>
&gt; -     ctx-&gt;f_size = bl_size;<br>
&gt; +     ctx-&gt;f_size = bl_info.size;<br>
&gt;<br>
&gt;       if (!part) {<br>
&gt;               rc = ffs_init(0, ctx-&gt;f_size, ctx-&gt;bl, &amp;ctx-&gt;ffs, 1);<br>
&gt; diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c<br>
&gt; index c032421d1..afb6ccd1f 100644<br>
&gt; --- a/external/opal-prd/pnor.c<br>
&gt; +++ b/external/opal-prd/pnor.c<br>
&gt; @@ -64,13 +64,13 @@ int pnor_init(struct pnor *pnor)<br>
&gt;               return -1;<br>
&gt;       }<br>
&gt;<br>
&gt; -     rc = blocklevel_get_info(pnor-&gt;bl, NULL, &amp;(pnor-&gt;size), &amp;(pnor-&gt;erasesize));<br>
&gt; +     rc = blocklevel_get_info(pnor-&gt;bl, &amp;pnor-&gt;bl_info);<br>
&gt;       if (rc) {<br>
&gt;               pr_log(LOG_ERR, &quot;PNOR: blocklevel_get_info() failed. Can&#39;t use PNOR&quot;);<br>
&gt;               goto out;<br>
&gt;       }<br>
&gt;<br>
&gt; -     rc = ffs_init(0, pnor-&gt;size, pnor-&gt;bl, &amp;pnor-&gt;ffsh, 0);<br>
&gt; +     rc = ffs_init(0, pnor-&gt;bl_info.size, pnor-&gt;bl, &amp;pnor-&gt;ffsh, 0);<br>
&gt;       if (rc) {<br>
&gt;               pr_log(LOG_ERR, &quot;PNOR: Failed to open pnor partition table&quot;);<br>
&gt;               goto out;<br>
&gt; @@ -121,8 +121,8 @@ static int mtd_write(struct pnor *pnor, void *data, uint64_t offset,<br>
&gt;  {<br>
&gt;       int rc;<br>
&gt;<br>
&gt; -     if (len &gt; pnor-&gt;size || offset &gt; pnor-&gt;size ||<br>
&gt; -         len + offset &gt; pnor-&gt;size)<br>
&gt; +     if (len &gt; pnor-&gt;bl_info.size || offset &gt; pnor-&gt;bl_info.size ||<br>
&gt; +         len + offset &gt; pnor-&gt;bl_info.size)<br>
&gt;               return -ERANGE;<br>
&gt;<br>
&gt;       rc = blocklevel_smart_write(pnor-&gt;bl, offset, data, len);<br>
&gt; @@ -137,8 +137,8 @@ static int mtd_read(struct pnor *pnor, void *data, uint64_t offset,<br>
&gt;  {<br>
&gt;       int rc;<br>
&gt;<br>
&gt; -     if (len &gt; pnor-&gt;size || offset &gt; pnor-&gt;size ||<br>
&gt; -         len + offset &gt; pnor-&gt;size)<br>
&gt; +     if (len &gt; pnor-&gt;bl_info.size || offset &gt; pnor-&gt;bl_info.size ||<br>
&gt; +         len + offset &gt; pnor-&gt;bl_info.size)<br>
&gt;               return -ERANGE;<br>
&gt;<br>
&gt;       rc = blocklevel_read(pnor-&gt;bl, offset, data, len);<br>
&gt; diff --git a/external/opal-prd/pnor.h b/external/opal-prd/pnor.h<br>
&gt; index 28571af64..1ee033659 100644<br>
&gt; --- a/external/opal-prd/pnor.h<br>
&gt; +++ b/external/opal-prd/pnor.h<br>
&gt; @@ -7,8 +7,7 @@<br>
&gt;  struct pnor {<br>
&gt;       char                    *path;<br>
&gt;       struct ffs_handle       *ffsh;<br>
&gt; -     uint64_t                size;<br>
&gt; -     uint32_t                erasesize;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;       struct blocklevel_device *bl;<br>
&gt;  };<br>
&gt;<br>
&gt; diff --git a/external/opal-prd/test/test_pnor_ops.c b/external/opal-prd/test/test_pnor_ops.c<br>
&gt; index fd5e2c22a..3743362e1 100644<br>
&gt; --- a/external/opal-prd/test/test_pnor_ops.c<br>
&gt; +++ b/external/opal-prd/test/test_pnor_ops.c<br>
&gt; @@ -130,11 +130,14 @@ int main(int argc, char **argv)<br>
&gt;       for (i = 0; i &lt; 2; i++)<br>
&gt;               write(fd, data, 16);<br>
&gt;<br>
&gt; +     /* Unused */<br>
&gt; +     <a href="http://pnor.bl_info.name" rel="noreferrer" target="_blank">pnor.bl_info.name</a> = NULL;<br>
&gt; +<br>
&gt;       /* Adjust this if making the file smaller */<br>
&gt; -     pnor.size = 32;<br>
&gt; +     pnor.bl_info.size = 32;<br>
&gt;<br>
&gt;       /* This is fake. Make it smaller than the size */<br>
&gt; -     pnor.erasesize = 4;<br>
&gt; +     pnor.bl_info.erase_granule = 4;<br>
&gt;<br>
&gt;       printf(&quot;Write: &quot;);<br>
&gt;       memset(data, &#39;A&#39;, sizeof(data));<br>
&gt; diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c<br>
&gt; index bfc975fe5..3f501e583 100644<br>
&gt; --- a/external/pflash/pflash.c<br>
&gt; +++ b/external/pflash/pflash.c<br>
&gt; @@ -43,11 +43,9 @@<br>
&gt;<br>
&gt;  struct flash_details {<br>
&gt;       struct blocklevel_device *bl;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;       int need_relock;<br>
&gt; -     const char *name;<br>
&gt;       uint64_t toc;<br>
&gt; -     uint64_t total_size;<br>
&gt; -     uint32_t erase_granule;<br>
&gt;  };<br>
&gt;<br>
&gt;  /* Full pflash version number (possibly includes gitid). */<br>
&gt; @@ -144,7 +142,7 @@ static struct ffs_handle *open_ffs(struct flash_details *flash)<br>
&gt;       struct ffs_handle *ffsh;<br>
&gt;       int rc;<br>
&gt;<br>
&gt; -     rc = ffs_init(flash-&gt;toc, flash-&gt;total_size,<br>
&gt; +     rc = ffs_init(flash-&gt;toc, flash-&gt;bl_info.size,<br>
&gt;                       flash-&gt;bl, &amp;ffsh, 0);<br>
&gt;       if (rc) {<br>
&gt;               fprintf(stderr, &quot;Error %d opening ffs !\n&quot;, rc);<br>
&gt; @@ -166,11 +164,11 @@ static void print_flash_info(struct flash_details *flash)<br>
&gt;<br>
&gt;       printf(&quot;Flash info:\n&quot;);<br>
&gt;       printf(&quot;-----------\n&quot;);<br>
&gt; -     printf(&quot;Name          = %s\n&quot;, flash-&gt;name);<br>
&gt; +     printf(&quot;Name          = %s\n&quot;, flash-&gt;<a href="http://bl_info.name" rel="noreferrer" target="_blank">bl_info.name</a>);<br>
&gt;       printf(&quot;Total size    = %&quot; PRIu64 &quot;MB\t Flags E:ECC, P:PRESERVED, R:READONLY\n&quot;,<br>
&gt; -                     flash-&gt;total_size &gt;&gt; 20);<br>
&gt; +                     flash-&gt;bl_info.size &gt;&gt; 20);<br>
&gt;       printf(&quot;Erase granule = %2d%-13sB:BACKUP, F:REPROVISION\n&quot;,<br>
&gt; -                     flash-&gt;erase_granule &gt;&gt; 10, &quot;KB&quot;);<br>
&gt; +                     flash-&gt;bl_info.erase_granule &gt;&gt; 10, &quot;KB&quot;);<br>
&gt;<br>
&gt;       if (bmc_flash)<br>
&gt;               return;<br>
&gt; @@ -282,9 +280,11 @@ static int erase_chip(struct flash_details *flash)<br>
&gt;        * likes the progress bars.<br>
&gt;        * Lets do an erase block at a time erase then...<br>
&gt;        */<br>
&gt; -     progress_init(flash-&gt;total_size);<br>
&gt; -     for (pos = 0; pos &lt; flash-&gt;total_size; pos += flash-&gt;erase_granule) {<br>
&gt; -             rc = blocklevel_erase(flash-&gt;bl, pos, flash-&gt;erase_granule);<br>
&gt; +     progress_init(flash-&gt;bl_info.size);<br>
&gt; +     for (pos = 0; pos &lt; flash-&gt;bl_info.size;<br>
&gt; +                     pos += flash-&gt;bl_info.erase_granule) {<br>
&gt; +             rc = blocklevel_erase(flash-&gt;bl, pos,<br>
&gt; +                             flash-&gt;bl_info.erase_granule);<br>
&gt;               if (rc)<br>
&gt;                       break;<br>
&gt;               progress_tick(pos);<br>
&gt; @@ -303,7 +303,7 @@ static int erase_range(struct flash_details *flash,<br>
&gt;               uint32_t start, uint32_t size, bool will_program,<br>
&gt;               struct ffs_handle *ffsh, int ffs_index)<br>
&gt;  {<br>
&gt; -     uint32_t done = 0, erase_mask = flash-&gt;erase_granule - 1;<br>
&gt; +     uint32_t done = 0, erase_mask = flash-&gt;bl_info.erase_granule - 1;<br>
&gt;       bool confirm;<br>
&gt;       int rc;<br>
&gt;<br>
&gt; @@ -326,25 +326,26 @@ static int erase_range(struct flash_details *flash,<br>
&gt;       if (start &amp; erase_mask) {<br>
&gt;               /* Align to next erase block */<br>
&gt;               rc = blocklevel_smart_erase(flash-&gt;bl, start,<br>
&gt; -                             flash-&gt;erase_granule - (start &amp; erase_mask));<br>
&gt; +                             flash-&gt;bl_info.erase_granule - (start &amp; erase_mask));<br>
&gt;               if (rc) {<br>
&gt;                       fprintf(stderr, &quot;Failed to blocklevel_smart_erase(): %d\n&quot;, rc);<br>
&gt;                       return 1;<br>
&gt;               }<br>
&gt; -             start += flash-&gt;erase_granule - (start &amp; erase_mask);<br>
&gt; -             size -= flash-&gt;erase_granule - (start &amp; erase_mask);<br>
&gt; -             done = flash-&gt;erase_granule - (start &amp; erase_mask);<br>
&gt; +             start += flash-&gt;bl_info.erase_granule - (start &amp; erase_mask);<br>
&gt; +             size -= flash-&gt;bl_info.erase_granule - (start &amp; erase_mask);<br>
&gt; +             done = flash-&gt;bl_info.erase_granule - (start &amp; erase_mask);<br>
&gt;       }<br>
&gt;       progress_tick(done);<br>
&gt;       while (size &amp; ~(erase_mask)) {<br>
&gt; -             rc = blocklevel_smart_erase(flash-&gt;bl, start, flash-&gt;erase_granule);<br>
&gt; +             rc = blocklevel_smart_erase(flash-&gt;bl, start,<br>
&gt; +                             flash-&gt;bl_info.erase_granule);<br>
&gt;               if (rc) {<br>
&gt;                       fprintf(stderr, &quot;Failed to blocklevel_smart_erase(): %d\n&quot;, rc);<br>
&gt;                       return 1;<br>
&gt;               }<br>
&gt; -             start += flash-&gt;erase_granule;<br>
&gt; -             size -= flash-&gt;erase_granule;<br>
&gt; -             done += flash-&gt;erase_granule;<br>
&gt; +             start += flash-&gt;bl_info.erase_granule;<br>
&gt; +             size -= flash-&gt;bl_info.erase_granule;<br>
&gt; +             done += flash-&gt;bl_info.erase_granule;<br>
&gt;               progress_tick(done);<br>
&gt;       }<br>
&gt;       if (size) {<br>
&gt; @@ -1003,8 +1004,7 @@ int main(int argc, char *argv[])<br>
&gt;               goto out;<br>
&gt;       }<br>
&gt;<br>
&gt; -     rc = blocklevel_get_info(flash.bl, &amp;<a href="http://flash.name" rel="noreferrer" target="_blank">flash.name</a>,<br>
&gt; -                         &amp;flash.total_size, &amp;flash.erase_granule);<br>
&gt; +     rc = blocklevel_get_info(flash.bl, &amp;flash.bl_info);<br>
&gt;       if (rc) {<br>
&gt;               fprintf(stderr, &quot;Error %d getting flash info\n&quot;, rc);<br>
&gt;               rc = 1;<br>
&gt; @@ -1025,7 +1025,7 @@ int main(int argc, char *argv[])<br>
&gt;<br>
&gt;       /* If read specified and no read_size, use flash size */<br>
&gt;       if (do_read &amp;&amp; !read_size &amp;&amp; !part_name)<br>
&gt; -             read_size = flash.total_size;<br>
&gt; +             read_size = flash.bl_info.size;<br>
&gt;<br>
&gt;       /* We have a partition, adjust read/write size if needed */<br>
&gt;       if (part_name || print_detail) {<br>
&gt; @@ -1087,7 +1087,7 @@ int main(int argc, char *argv[])<br>
&gt;               /* Set address */<br>
&gt;               address = pstart;<br>
&gt;       } else if (erase) {<br>
&gt; -             if ((address | write_size) &amp; (flash.erase_granule - 1)) {<br>
&gt; +             if ((address | write_size) &amp; (flash.bl_info.erase_granule - 1)) {<br>
&gt;                       if (must_confirm) {<br>
&gt;                               printf(&quot;ERROR: Erase at 0x%08x for 0x%08x isn&#39;t erase block aligned\n&quot;,<br>
&gt;                                               address, write_size);<br>
&gt; diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c<br>
&gt; index 33d5c5d2f..3955be823 100644<br>
&gt; --- a/libflash/blocklevel.c<br>
&gt; +++ b/libflash/blocklevel.c<br>
&gt; @@ -229,12 +229,11 @@ int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len)<br>
&gt;       return rc;<br>
&gt;  }<br>
&gt;<br>
&gt; -int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,<br>
&gt; -             uint32_t *erase_granule)<br>
&gt; +int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info)<br>
&gt;  {<br>
&gt;       int rc;<br>
&gt;<br>
&gt; -     if (!bl || !bl-&gt;get_info) {<br>
&gt; +     if (!bl || !bl-&gt;get_info || !bl_info) {<br>
&gt;               errno = EINVAL;<br>
&gt;               return FLASH_ERR_PARM_ERROR;<br>
&gt;       }<br>
&gt; @@ -243,12 +242,12 @@ int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_<br>
&gt;       if (rc)<br>
&gt;               return rc;<br>
&gt;<br>
&gt; -     rc = bl-&gt;get_info(bl, name, total_size, erase_granule);<br>
&gt; +     rc = bl-&gt;get_info(bl, bl_info);<br>
&gt;<br>
&gt;       /* Check the validity of what we are being told */<br>
&gt; -     if (erase_granule &amp;&amp; *erase_granule != bl-&gt;erase_mask + 1)<br>
&gt; +     if (bl_info-&gt;erase_granule != bl-&gt;erase_mask + 1)<br>
&gt;               FL_ERR(&quot;blocklevel_get_info: WARNING: erase_granule (0x%08x) and erase_mask&quot;<br>
&gt; -                             &quot; (0x%08x) don&#39;t match\n&quot;, *erase_granule, bl-&gt;erase_mask + 1);<br>
&gt; +                             &quot; (0x%08x) don&#39;t match\n&quot;, bl_info-&gt;erase_granule, bl-&gt;erase_mask + 1);<br>
&gt;<br>
&gt;       release(bl);<br>
&gt;<br>
&gt; @@ -417,7 +416,7 @@ out:<br>
&gt;<br>
&gt;  int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len)<br>
&gt;  {<br>
&gt; -     uint32_t erase_size;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;       const void *write_buf = buf;<br>
&gt;       void *write_buf_start = NULL;<br>
&gt;       void *erase_buf;<br>
&gt; @@ -435,7 +434,7 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi<br>
&gt;               return blocklevel_write(bl, pos, buf, len);<br>
&gt;       }<br>
&gt;<br>
&gt; -     rc = blocklevel_get_info(bl, NULL, NULL, &amp;erase_size);<br>
&gt; +     rc = blocklevel_get_info(bl, &amp;bl_info);<br>
&gt;       if (rc)<br>
&gt;               return rc;<br>
&gt;<br>
&gt; @@ -458,7 +457,7 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi<br>
&gt;               write_buf = write_buf_start;<br>
&gt;       }<br>
&gt;<br>
&gt; -     erase_buf = malloc(erase_size);<br>
&gt; +     erase_buf = malloc(bl_info.erase_granule);<br>
&gt;       if (!erase_buf) {<br>
&gt;               errno = ENOMEM;<br>
&gt;               rc = FLASH_ERR_MALLOC_FAILED;<br>
&gt; @@ -470,32 +469,32 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi<br>
&gt;               goto out_free;<br>
&gt;<br>
&gt;       while (len &gt; 0) {<br>
&gt; -             uint32_t erase_block = pos &amp; ~(erase_size - 1);<br>
&gt; -             uint32_t block_offset = pos &amp; (erase_size - 1);<br>
&gt; -             uint32_t size = erase_size &gt; len ? len : erase_size;<br>
&gt; +             uint32_t erase_block = pos &amp; ~(bl_info.erase_granule - 1);<br>
&gt; +             uint32_t block_offset = pos &amp; (bl_info.erase_granule - 1);<br>
&gt; +             uint32_t size = bl_info.erase_granule &gt; len ? len : bl_info.erase_granule;<br>
&gt;               int cmp;<br>
&gt;<br>
&gt;               /* Write crosses an erase boundary, shrink the write to the boundary */<br>
&gt; -             if (erase_size &lt; block_offset + size) {<br>
&gt; -                     size = erase_size - block_offset;<br>
&gt; +             if (bl_info.erase_granule &lt; block_offset + size) {<br>
&gt; +                     size = bl_info.erase_granule - block_offset;<br>
&gt;               }<br>
&gt;<br>
&gt; -             rc = bl-&gt;read(bl, erase_block, erase_buf, erase_size);<br>
&gt; +             rc = bl-&gt;read(bl, erase_block, erase_buf, bl_info.erase_granule);<br>
&gt;               if (rc)<br>
&gt;                       goto out;<br>
&gt;<br>
&gt;               cmp = blocklevel_flashcmp(erase_buf + block_offset, write_buf, size);<br>
&gt;               FL_DBG(&quot;%s: region 0x%08x..0x%08x &quot;, __func__,<br>
&gt; -                             erase_block, erase_size);<br>
&gt; +                             erase_block, bl_info.erase_granule);<br>
&gt;               if (cmp != 0) {<br>
&gt;                       FL_DBG(&quot;needs &quot;);<br>
&gt;                       if (cmp == -1) {<br>
&gt;                               FL_DBG(&quot;erase and &quot;);<br>
&gt; -                             bl-&gt;erase(bl, erase_block, erase_size);<br>
&gt; +                             bl-&gt;erase(bl, erase_block, bl_info.erase_granule);<br>
&gt;                       }<br>
&gt;                       FL_DBG(&quot;write\n&quot;);<br>
&gt;                       memcpy(erase_buf + block_offset, write_buf, size);<br>
&gt; -                     rc = bl-&gt;write(bl, erase_block, erase_buf, erase_size);<br>
&gt; +                     rc = bl-&gt;write(bl, erase_block, erase_buf, bl_info.erase_granule);<br>
&gt;                       if (rc)<br>
&gt;                               goto out;<br>
&gt;               }<br>
&gt; diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h<br>
&gt; index ba42c83d0..d2d269054 100644<br>
&gt; --- a/libflash/blocklevel.h<br>
&gt; +++ b/libflash/blocklevel.h<br>
&gt; @@ -34,6 +34,15 @@ enum blocklevel_flags {<br>
&gt;       WRITE_NEED_ERASE = 1,<br>
&gt;  };<br>
&gt;<br>
&gt; +struct blocklevel_info {<br>
&gt; +     /* name is not owned by this struct and must persist for the<br>
&gt; +      * liftime of blocklevel_info<br>
&gt; +      */<br>
&gt; +     const char *name;<br>
&gt; +     uint64_t size;<br>
&gt; +     uint32_t erase_granule;<br>
&gt; +};<br>
&gt; +<br>
&gt;  /*<br>
&gt;   * libffs may be used with different backends, all should provide these for<br>
&gt;   * libflash to get the information it needs<br>
&gt; @@ -45,8 +54,7 @@ struct blocklevel_device {<br>
&gt;       int (*read)(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len);<br>
&gt;       int (*write)(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);<br>
&gt;       int (*erase)(struct blocklevel_device *bl, uint64_t pos, uint64_t len);<br>
&gt; -     int (*get_info)(struct blocklevel_device *bl, const char **name, uint64_t *total_size,<br>
&gt; -                     uint32_t *erase_granule);<br>
&gt; +     int (*get_info)(struct blocklevel_device *bl, struct blocklevel_info *bl_info);<br>
&gt;<br>
&gt;       /*<br>
&gt;        * Keep the erase mask so that blocklevel_erase() can do sanity checking<br>
&gt; @@ -62,8 +70,8 @@ int blocklevel_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint6<br>
&gt;  int blocklevel_raw_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);<br>
&gt;  int blocklevel_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);<br>
&gt;  int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len);<br>
&gt; -int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,<br>
&gt; -             uint32_t *erase_granule);<br>
&gt; +<br>
&gt; +int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info);<br>
&gt;<br>
&gt;  /*<br>
&gt;   * blocklevel_smart_write() performs reads on the data to see if it<br>
&gt; diff --git a/libflash/file.c b/libflash/file.c<br>
&gt; index 7065eb4fa..b87679cd1 100644<br>
&gt; --- a/libflash/file.c<br>
&gt; +++ b/libflash/file.c<br>
&gt; @@ -212,6 +212,7 @@ static int get_info_name(struct file_data *file_data, char **name)<br>
&gt;       }<br>
&gt;       lpath[len] = &#39;\0&#39;;<br>
&gt;<br>
&gt; +     free(*name);<br>
&gt;       *name = lpath;<br>
&gt;<br>
&gt;       free(path);<br>
&gt; @@ -219,8 +220,8 @@ static int get_info_name(struct file_data *file_data, char **name)<br>
&gt;  }<br>
&gt;<br>
&gt;<br>
&gt; -static int mtd_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt; -             uint64_t *total_size, uint32_t *erase_granule)<br>
&gt; +static int mtd_get_info(struct blocklevel_device *bl,<br>
&gt; +             struct blocklevel_info *bl_info)<br>
&gt;  {<br>
&gt;       struct file_data *file_data = container_of(bl, struct file_data, bl);<br>
&gt;       struct mtd_info_user mtd_info;<br>
&gt; @@ -230,24 +231,19 @@ static int mtd_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt;       if (rc == -1)<br>
&gt;               return FLASH_ERR_BAD_READ;<br>
&gt;<br>
&gt; -     if (total_size)<br>
&gt; -             *total_size = mtd_info.size;<br>
&gt; -<br>
&gt; -     if (erase_granule)<br>
&gt; -             *erase_granule = mtd_info.erasesize;<br>
&gt; +     rc = get_info_name(file_data, &amp;(file_data-&gt;name));<br>
&gt; +     if (rc)<br>
&gt; +             return rc;<br>
&gt;<br>
&gt; -     if (name) {<br>
&gt; -             rc = get_info_name(file_data, &amp;(file_data-&gt;name));<br>
&gt; -             if (rc)<br>
&gt; -                     return rc;<br>
&gt; -             *name = file_data-&gt;name;<br>
&gt; -     }<br>
&gt; +     bl_info-&gt;name = file_data-&gt;name;<br>
&gt; +     bl_info-&gt;size = mtd_info.size;<br>
&gt; +     bl_info-&gt;erase_granule = mtd_info.erasesize;<br>
&gt;<br>
&gt;       return 0;<br>
&gt;  }<br>
&gt;<br>
&gt; -static int file_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt; -             uint64_t *total_size, uint32_t *erase_granule)<br>
&gt; +static int file_get_info(struct blocklevel_device *bl,<br>
&gt; +             struct blocklevel_info *bl_info)<br>
&gt;  {<br>
&gt;       struct file_data *file_data = container_of(bl, struct file_data, bl);<br>
&gt;       struct stat st;<br>
&gt; @@ -256,18 +252,13 @@ static int file_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt;       if (fstat(file_data-&gt;fd, &amp;st))<br>
&gt;               return FLASH_ERR_PARM_ERROR;<br>
&gt;<br>
&gt; -     if (total_size)<br>
&gt; -             *total_size = st.st_size;<br>
&gt; -<br>
&gt; -     if (erase_granule)<br>
&gt; -             *erase_granule = 1;<br>
&gt; +     rc = get_info_name(file_data, &amp;(file_data-&gt;name));<br>
&gt; +     if (rc)<br>
&gt; +             return rc;<br>
&gt;<br>
&gt; -     if (name) {<br>
&gt; -             rc = get_info_name(file_data, &amp;(file_data-&gt;name));<br>
&gt; -             if (rc)<br>
&gt; -                     return rc;<br>
&gt; -             *name = file_data-&gt;name;<br>
&gt; -     }<br>
&gt; +     bl_info-&gt;name = file_data-&gt;name;<br>
&gt; +     bl_info-&gt;size = st.st_size;<br>
&gt; +     bl_info-&gt;erase_granule = 1;<br>
&gt;<br>
&gt;       return 0;<br>
&gt;  }<br>
&gt; @@ -315,8 +306,9 @@ int file_init(int fd, struct blocklevel_device **bl)<br>
&gt;               file_data-&gt;bl.erase = &amp;mtd_erase;<br>
&gt;               file_data-&gt;bl.get_info = &amp;mtd_get_info;<br>
&gt;               file_data-&gt;bl.flags = WRITE_NEED_ERASE;<br>
&gt; -             mtd_get_info(&amp;file_data-&gt;bl, NULL, NULL, &amp;(file_data-&gt;bl.erase_mask));<br>
&gt; -             file_data-&gt;bl.erase_mask--;<br>
&gt; +             struct blocklevel_info bl_info;<br>
&gt; +             mtd_get_info(&amp;file_data-&gt;bl, &amp;bl_info);<br>
&gt; +             file_data-&gt;bl.erase_mask = bl_info.erase_granule - 1;<br>
&gt;       } else if (!S_ISREG(sbuf.st_mode)) {<br>
&gt;               /* If not a char device or a regular file something went wrong */<br>
&gt;               goto out;<br>
&gt; diff --git a/libflash/libffs.c b/libflash/libffs.c<br>
&gt; index 038f59425..6fc23eee9 100644<br>
&gt; --- a/libflash/libffs.c<br>
&gt; +++ b/libflash/libffs.c<br>
&gt; @@ -216,25 +216,25 @@ int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,<br>
&gt;  {<br>
&gt;       struct __ffs_hdr blank_hdr;<br>
&gt;       struct __ffs_hdr raw_hdr;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;       struct ffs_handle *f;<br>
&gt; -     uint64_t total_size;<br>
&gt;       int rc, i;<br>
&gt;<br>
&gt;       if (!ffs || !bl)<br>
&gt;               return FLASH_ERR_PARM_ERROR;<br>
&gt;       *ffs = NULL;<br>
&gt;<br>
&gt; -     rc = blocklevel_get_info(bl, NULL, &amp;total_size, NULL);<br>
&gt; +     rc = blocklevel_get_info(bl, &amp;bl_info);<br>
&gt;       if (rc) {<br>
&gt;               FL_ERR(&quot;FFS: Error %d retrieving flash info\n&quot;, rc);<br>
&gt;               return rc;<br>
&gt;       }<br>
&gt; -     if (total_size &gt; UINT_MAX)<br>
&gt; +     if (bl_info.size &gt; UINT_MAX)<br>
&gt;               return FLASH_ERR_VERIFY_FAILURE;<br>
&gt;       if ((offset + max_size) &lt; offset)<br>
&gt;               return FLASH_ERR_PARM_ERROR;<br>
&gt;<br>
&gt; -     if ((max_size &gt; total_size))<br>
&gt; +     if ((max_size &gt; bl_info.size))<br>
&gt;               return FLASH_ERR_PARM_ERROR;<br>
&gt;<br>
&gt;       /* Read flash header */<br>
&gt; diff --git a/libflash/libflash.c b/libflash/libflash.c<br>
&gt; index 38f87b86e..82a2baecc 100644<br>
&gt; --- a/libflash/libflash.c<br>
&gt; +++ b/libflash/libflash.c<br>
&gt; @@ -792,16 +792,15 @@ static int flash_configure(struct flash_chip *c)<br>
&gt;       return 0;<br>
&gt;  }<br>
&gt;<br>
&gt; -static int flash_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt; -                uint64_t *total_size, uint32_t *erase_granule)<br>
&gt; +static int flash_get_info(struct blocklevel_device *bl,<br>
&gt; +             struct blocklevel_info *bl_info)<br>
&gt;  {<br>
&gt;       struct flash_chip *c = container_of(bl, struct flash_chip, bl);<br>
&gt; -     if (name)<br>
&gt; -             *name = c-&gt;<a href="http://info.name" rel="noreferrer" target="_blank">info.name</a>;<br>
&gt; -     if (total_size)<br>
&gt; -             *total_size = c-&gt;tsize;<br>
&gt; -     if (erase_granule)<br>
&gt; -             *erase_granule = c-&gt;min_erase_mask + 1;<br>
&gt; +<br>
&gt; +     bl_info-&gt;name = c-&gt;<a href="http://info.name" rel="noreferrer" target="_blank">info.name</a>;<br>
&gt; +     bl_info-&gt;size = c-&gt;tsize;<br>
&gt; +     bl_info-&gt;erase_granule = c-&gt;min_erase_mask + 1;<br>
&gt; +<br>
&gt;       return 0;<br>
&gt;  }<br>
&gt;<br>
&gt; diff --git a/libflash/mbox-flash.c b/libflash/mbox-flash.c<br>
&gt; index 950e24f05..d4200ce53 100644<br>
&gt; --- a/libflash/mbox-flash.c<br>
&gt; +++ b/libflash/mbox-flash.c<br>
&gt; @@ -745,8 +745,8 @@ static int mbox_flash_read(struct blocklevel_device *bl, uint64_t pos,<br>
&gt;       return rc;<br>
&gt;  }<br>
&gt;<br>
&gt; -static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt; -             uint64_t *total_size, uint32_t *erase_granule)<br>
&gt; +static int mbox_flash_get_info(struct blocklevel_device *bl,<br>
&gt; +             struct blocklevel_info *bl_info)<br>
&gt;  {<br>
&gt;       struct mbox_flash_data *mbox_flash;<br>
&gt;       struct bmc_mbox_msg *msg;<br>
&gt; @@ -761,14 +761,7 @@ static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt;       if (!msg)<br>
&gt;               return FLASH_ERR_MALLOC_FAILED;<br>
&gt;<br>
&gt; -     /*<br>
&gt; -      * We want to avoid runtime mallocs in skiboot. The expected<br>
&gt; -      * behavour to uses of libflash is that one can free() the memory<br>
&gt; -      * returned.<br>
&gt; -      * NULL will do for now.<br>
&gt; -      */<br>
&gt; -     if (name)<br>
&gt; -             *name = NULL;<br>
&gt; +     bl_info-&gt;name = &quot;pnor_mbox&quot;;<br>
&gt;<br>
&gt;       mbox_flash-&gt;busy = true;<br>
&gt;       rc = msg_send(mbox_flash, msg);<br>
&gt; @@ -784,10 +777,8 @@ static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt;<br>
&gt;       mbox_flash-&gt;bl.erase_mask = mbox_flash-&gt;erase_granule - 1;<br>
&gt;<br>
&gt; -     if (total_size)<br>
&gt; -             *total_size = mbox_flash-&gt;total_size;<br>
&gt; -     if (erase_granule)<br>
&gt; -             *erase_granule = mbox_flash-&gt;erase_granule;<br>
&gt; +     bl_info-&gt;size = mbox_flash-&gt;total_size;<br>
&gt; +     bl_info-&gt;erase_granule = mbox_flash-&gt;erase_granule;<br>
&gt;<br>
&gt;  out:<br>
&gt;       msg_free_memory(msg);<br>
&gt; diff --git a/libflash/test/test-flash.c b/libflash/test/test-flash.c<br>
&gt; index 3f77d6f3e..1ca467bb0 100644<br>
&gt; --- a/libflash/test/test-flash.c<br>
&gt; +++ b/libflash/test/test-flash.c<br>
&gt; @@ -367,9 +367,7 @@ struct spi_flash_ctrl sim_ctrl = {<br>
&gt;  int main(void)<br>
&gt;  {<br>
&gt;       struct blocklevel_device *bl;<br>
&gt; -     uint64_t total_size;<br>
&gt; -     uint32_t erase_granule;<br>
&gt; -     const char *name;<br>
&gt; +     struct blocklevel_info bl_info;<br>
&gt;       uint16_t *test;<br>
&gt;       struct ecc64 *ecc_test;<br>
&gt;       uint64_t *test64;<br>
&gt; @@ -384,7 +382,7 @@ int main(void)<br>
&gt;               ERR(&quot;flash_init failed with err %d\n&quot;, rc);<br>
&gt;               exit(1);<br>
&gt;       }<br>
&gt; -     rc = flash_get_info(bl, &amp;name, &amp;total_size, &amp;erase_granule);<br>
&gt; +     rc = flash_get_info(bl, &amp;bl_info);<br>
&gt;       if (rc) {<br>
&gt;               ERR(&quot;flash_get_info failed with err %d\n&quot;, rc);<br>
&gt;               exit(1);<br>
&gt; diff --git a/platforms/mambo/mambo.c b/platforms/mambo/mambo.c<br>
&gt; index cb6e103cc..dd7872a8e 100644<br>
&gt; --- a/platforms/mambo/mambo.c<br>
&gt; +++ b/platforms/mambo/mambo.c<br>
&gt; @@ -125,19 +125,14 @@ static int bogus_disk_erase(struct blocklevel_device *bl __unused,<br>
&gt;       return 0; /* NOP */<br>
&gt;  }<br>
&gt;<br>
&gt; -static int bogus_disk_get_info(struct blocklevel_device *bl, const char **name,<br>
&gt; -                           uint64_t *total_size, uint32_t *erase_granule)<br>
&gt; +static int bogus_disk_get_info(struct blocklevel_device *bl,<br>
&gt; +                     struct blocklevel_info *bl_info)<br>
&gt;  {<br>
&gt;       struct bogus_disk_info *bdi = bl-&gt;priv;<br>
&gt;<br>
&gt; -     if (total_size)<br>
&gt; -             *total_size = bdi-&gt;size;<br>
&gt; -<br>
&gt; -     if (erase_granule)<br>
&gt; -             *erase_granule = BD_SECT_SZ;<br>
&gt; -<br>
&gt; -     if (name)<br>
&gt; -             *name = &quot;mambobogus&quot;;<br>
&gt; +     bl_info-&gt;name = &quot;mambobogus&quot;;<br>
&gt; +     bl_info-&gt;size = bdi-&gt;size;<br>
&gt; +     bl_info-&gt;erase_granule = BD_SECT_SZ;<br>
&gt;<br>
&gt;       return 0;<br>
&gt;  }<br>
</blockquote></div>
Stewart Smith Sept. 21, 2017, 2:23 a.m. | #3
Cyril Bur <cyrilbur@gmail.com> writes:
> On Mon, 2017-08-28 at 21:19 -0700, William A. Kennington III wrote:
>> This changes refactors all of the output variables from flash_get_info
>> into a new output struct. Callers now supply the info struct, and always
>> get all of the info with each call. There are never any allocations done
>> by this function so it shouldn't be much slower to always populate all
>> of the information.
>> 
>
> Hi William,
>
> As nice as this refactor is (thanks for the effort!), unfortunately
> we're a bit stuck with the interface as is, both openbmc and petitboot
> projects link against a dynamic libflash.

We can always bump the .so version and they can update asynchronously.

Patch

diff --git a/core/flash.c b/core/flash.c
index 53e6eba08..35a0c4c32 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -254,21 +254,20 @@  static int num_flashes(void)
 
 int flash_register(struct blocklevel_device *bl)
 {
-	uint64_t size;
-	uint32_t block_size;
+	struct blocklevel_info bl_info;
 	struct ffs_handle *ffs;
 	struct dt_node *node;
 	struct flash *flash;
-	const char *name;
 	int rc;
 
-	rc = blocklevel_get_info(bl, &name, &size, &block_size);
+	rc = blocklevel_get_info(bl, &bl_info);
 	if (rc)
 		return rc;
 
 	prlog(PR_INFO, "FLASH: registering flash device %s "
 			"(size 0x%llx, blocksize 0x%x)\n",
-			name ?: "(unnamed)", size, block_size);
+			bl_info.name ? bl_info.name : "(unnamed)", bl_info.size,
+			bl_info.erase_granule);
 
 	lock(&flash_lock);
 
@@ -281,8 +280,8 @@  int flash_register(struct blocklevel_device *bl)
 
 	flash->busy = false;
 	flash->bl = bl;
-	flash->size = size;
-	flash->block_size = block_size;
+	flash->size = bl_info.size;
+	flash->block_size = bl_info.erase_granule;
 	flash->id = num_flashes();
 
 	list_add(&flashes, &flash->list);
@@ -302,7 +301,7 @@  int flash_register(struct blocklevel_device *bl)
 
 	node = flash_add_dt_node(flash, flash->id);
 
-	setup_system_flash(flash, node, name, ffs);
+	setup_system_flash(flash, node, bl_info.name, ffs);
 
 	if (ffs)
 		ffs_close(ffs);
diff --git a/external/common/arch_flash_arm.c b/external/common/arch_flash_arm.c
index 3cdd41ded..ac43de0c4 100644
--- a/external/common/arch_flash_arm.c
+++ b/external/common/arch_flash_arm.c
@@ -303,13 +303,13 @@  int arch_flash_erase_chip(struct blocklevel_device *bl)
 	if (!arch_data.flash_chip) {
 		/* Just assume its a regular erase */
 		int rc;
-		uint64_t total_size;
+		struct blocklevel_info bl_info;
 
-		rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
+		rc = blocklevel_get_info(bl, &bl_info);
 		if (rc)
 			return rc;
 
-		return blocklevel_erase(bl, 0, total_size);
+		return blocklevel_erase(bl, 0, bl_info.size);
 	}
 
 	return flash_erase_chip(arch_data.flash_chip);
diff --git a/external/common/arch_flash_common.c b/external/common/arch_flash_common.c
index 6bce7e1ba..41239662a 100644
--- a/external/common/arch_flash_common.c
+++ b/external/common/arch_flash_common.c
@@ -31,13 +31,13 @@ 
 int __attribute__((weak)) arch_flash_erase_chip(struct blocklevel_device *bl)
 {
 	int rc;
-	uint64_t total_size;
+	struct blocklevel_info bl_info;
 
-	rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
+	rc = blocklevel_get_info(bl, &bl_info);
 	if (rc)
 		return rc;
 
-	return blocklevel_erase(bl, 0, total_size);
+	return blocklevel_erase(bl, 0, bl_info.size);
 }
 
 int __attribute__((weak,const)) arch_flash_4b_mode(struct blocklevel_device *bl, int set_4b)
diff --git a/external/gard/gard.c b/external/gard/gard.c
index c5cb93b88..3946cad6f 100644
--- a/external/gard/gard.c
+++ b/external/gard/gard.c
@@ -596,7 +596,7 @@  int main(int argc, char **argv)
 	const char *action, *progname;
 	char *filename = NULL;
 	struct gard_ctx _ctx, *ctx;
-	uint64_t bl_size;
+	struct blocklevel_info bl_info;
 	int rc, i = 0;
 	bool part = 0;
 	bool ecc = 0;
@@ -665,17 +665,17 @@  int main(int argc, char **argv)
 		goto out_free;
 	}
 
-	rc = blocklevel_get_info(ctx->bl, NULL, &bl_size, NULL);
+	rc = blocklevel_get_info(ctx->bl, &bl_info);
 	if (rc)
 		goto out;
 
-	if (bl_size > UINT_MAX) {
+	if (bl_info.size > UINT_MAX) {
 		fprintf(stderr, "MTD device bigger than %i: size: %" PRIu64 "\n",
-			UINT_MAX, bl_size);
+			UINT_MAX, bl_info.size);
 		rc = EXIT_FAILURE;
 		goto out;
 	}
-	ctx->f_size = bl_size;
+	ctx->f_size = bl_info.size;
 
 	if (!part) {
 		rc = ffs_init(0, ctx->f_size, ctx->bl, &ctx->ffs, 1);
diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c
index c032421d1..afb6ccd1f 100644
--- a/external/opal-prd/pnor.c
+++ b/external/opal-prd/pnor.c
@@ -64,13 +64,13 @@  int pnor_init(struct pnor *pnor)
 		return -1;
 	}
 
-	rc = blocklevel_get_info(pnor->bl, NULL, &(pnor->size), &(pnor->erasesize));
+	rc = blocklevel_get_info(pnor->bl, &pnor->bl_info);
 	if (rc) {
 		pr_log(LOG_ERR, "PNOR: blocklevel_get_info() failed. Can't use PNOR");
 		goto out;
 	}
 
-	rc = ffs_init(0, pnor->size, pnor->bl, &pnor->ffsh, 0);
+	rc = ffs_init(0, pnor->bl_info.size, pnor->bl, &pnor->ffsh, 0);
 	if (rc) {
 		pr_log(LOG_ERR, "PNOR: Failed to open pnor partition table");
 		goto out;
@@ -121,8 +121,8 @@  static int mtd_write(struct pnor *pnor, void *data, uint64_t offset,
 {
 	int rc;
 
-	if (len > pnor->size || offset > pnor->size ||
-	    len + offset > pnor->size)
+	if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
+	    len + offset > pnor->bl_info.size)
 		return -ERANGE;
 
 	rc = blocklevel_smart_write(pnor->bl, offset, data, len);
@@ -137,8 +137,8 @@  static int mtd_read(struct pnor *pnor, void *data, uint64_t offset,
 {
 	int rc;
 
-	if (len > pnor->size || offset > pnor->size ||
-	    len + offset > pnor->size)
+	if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
+	    len + offset > pnor->bl_info.size)
 		return -ERANGE;
 
 	rc = blocklevel_read(pnor->bl, offset, data, len);
diff --git a/external/opal-prd/pnor.h b/external/opal-prd/pnor.h
index 28571af64..1ee033659 100644
--- a/external/opal-prd/pnor.h
+++ b/external/opal-prd/pnor.h
@@ -7,8 +7,7 @@ 
 struct pnor {
 	char			*path;
 	struct ffs_handle	*ffsh;
-	uint64_t		size;
-	uint32_t		erasesize;
+	struct blocklevel_info bl_info;
 	struct blocklevel_device *bl;
 };
 
diff --git a/external/opal-prd/test/test_pnor_ops.c b/external/opal-prd/test/test_pnor_ops.c
index fd5e2c22a..3743362e1 100644
--- a/external/opal-prd/test/test_pnor_ops.c
+++ b/external/opal-prd/test/test_pnor_ops.c
@@ -130,11 +130,14 @@  int main(int argc, char **argv)
 	for (i = 0; i < 2; i++)
 		write(fd, data, 16);
 
+	/* Unused */
+	pnor.bl_info.name = NULL;
+
 	/* Adjust this if making the file smaller */
-	pnor.size = 32;
+	pnor.bl_info.size = 32;
 
 	/* This is fake. Make it smaller than the size */
-	pnor.erasesize = 4;
+	pnor.bl_info.erase_granule = 4;
 
 	printf("Write: ");
 	memset(data, 'A', sizeof(data));
diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c
index bfc975fe5..3f501e583 100644
--- a/external/pflash/pflash.c
+++ b/external/pflash/pflash.c
@@ -43,11 +43,9 @@ 
 
 struct flash_details {
 	struct blocklevel_device *bl;
+	struct blocklevel_info bl_info;
 	int need_relock;
-	const char *name;
 	uint64_t toc;
-	uint64_t total_size;
-	uint32_t erase_granule;
 };
 
 /* Full pflash version number (possibly includes gitid). */
@@ -144,7 +142,7 @@  static struct ffs_handle *open_ffs(struct flash_details *flash)
 	struct ffs_handle *ffsh;
 	int rc;
 
-	rc = ffs_init(flash->toc, flash->total_size,
+	rc = ffs_init(flash->toc, flash->bl_info.size,
 			flash->bl, &ffsh, 0);
 	if (rc) {
 		fprintf(stderr, "Error %d opening ffs !\n", rc);
@@ -166,11 +164,11 @@  static void print_flash_info(struct flash_details *flash)
 
 	printf("Flash info:\n");
 	printf("-----------\n");
-	printf("Name          = %s\n", flash->name);
+	printf("Name          = %s\n", flash->bl_info.name);
 	printf("Total size    = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED, R:READONLY\n",
-			flash->total_size >> 20);
+			flash->bl_info.size >> 20);
 	printf("Erase granule = %2d%-13sB:BACKUP, F:REPROVISION\n",
-			flash->erase_granule >> 10, "KB");
+			flash->bl_info.erase_granule >> 10, "KB");
 
 	if (bmc_flash)
 		return;
@@ -282,9 +280,11 @@  static int erase_chip(struct flash_details *flash)
 	 * likes the progress bars.
 	 * Lets do an erase block at a time erase then...
 	 */
-	progress_init(flash->total_size);
-	for (pos = 0; pos < flash->total_size; pos += flash->erase_granule) {
-		rc = blocklevel_erase(flash->bl, pos, flash->erase_granule);
+	progress_init(flash->bl_info.size);
+	for (pos = 0; pos < flash->bl_info.size;
+			pos += flash->bl_info.erase_granule) {
+		rc = blocklevel_erase(flash->bl, pos,
+				flash->bl_info.erase_granule);
 		if (rc)
 			break;
 		progress_tick(pos);
@@ -303,7 +303,7 @@  static int erase_range(struct flash_details *flash,
 		uint32_t start, uint32_t size, bool will_program,
 		struct ffs_handle *ffsh, int ffs_index)
 {
-	uint32_t done = 0, erase_mask = flash->erase_granule - 1;
+	uint32_t done = 0, erase_mask = flash->bl_info.erase_granule - 1;
 	bool confirm;
 	int rc;
 
@@ -326,25 +326,26 @@  static int erase_range(struct flash_details *flash,
 	if (start & erase_mask) {
 		/* Align to next erase block */
 		rc = blocklevel_smart_erase(flash->bl, start,
-				flash->erase_granule - (start & erase_mask));
+				flash->bl_info.erase_granule - (start & erase_mask));
 		if (rc) {
 			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
 			return 1;
 		}
-		start += flash->erase_granule - (start & erase_mask);
-		size -= flash->erase_granule - (start & erase_mask);
-		done = flash->erase_granule - (start & erase_mask);
+		start += flash->bl_info.erase_granule - (start & erase_mask);
+		size -= flash->bl_info.erase_granule - (start & erase_mask);
+		done = flash->bl_info.erase_granule - (start & erase_mask);
 	}
 	progress_tick(done);
 	while (size & ~(erase_mask)) {
-		rc = blocklevel_smart_erase(flash->bl, start, flash->erase_granule);
+		rc = blocklevel_smart_erase(flash->bl, start,
+				flash->bl_info.erase_granule);
 		if (rc) {
 			fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
 			return 1;
 		}
-		start += flash->erase_granule;
-		size -= flash->erase_granule;
-		done += flash->erase_granule;
+		start += flash->bl_info.erase_granule;
+		size -= flash->bl_info.erase_granule;
+		done += flash->bl_info.erase_granule;
 		progress_tick(done);
 	}
 	if (size) {
@@ -1003,8 +1004,7 @@  int main(int argc, char *argv[])
 		goto out;
 	}
 
-	rc = blocklevel_get_info(flash.bl, &flash.name,
-			    &flash.total_size, &flash.erase_granule);
+	rc = blocklevel_get_info(flash.bl, &flash.bl_info);
 	if (rc) {
 		fprintf(stderr, "Error %d getting flash info\n", rc);
 		rc = 1;
@@ -1025,7 +1025,7 @@  int main(int argc, char *argv[])
 
 	/* If read specified and no read_size, use flash size */
 	if (do_read && !read_size && !part_name)
-		read_size = flash.total_size;
+		read_size = flash.bl_info.size;
 
 	/* We have a partition, adjust read/write size if needed */
 	if (part_name || print_detail) {
@@ -1087,7 +1087,7 @@  int main(int argc, char *argv[])
 		/* Set address */
 		address = pstart;
 	} else if (erase) {
-		if ((address | write_size) & (flash.erase_granule - 1)) {
+		if ((address | write_size) & (flash.bl_info.erase_granule - 1)) {
 			if (must_confirm) {
 				printf("ERROR: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
 						address, write_size);
diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
index 33d5c5d2f..3955be823 100644
--- a/libflash/blocklevel.c
+++ b/libflash/blocklevel.c
@@ -229,12 +229,11 @@  int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len)
 	return rc;
 }
 
-int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
-		uint32_t *erase_granule)
+int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info)
 {
 	int rc;
 
-	if (!bl || !bl->get_info) {
+	if (!bl || !bl->get_info || !bl_info) {
 		errno = EINVAL;
 		return FLASH_ERR_PARM_ERROR;
 	}
@@ -243,12 +242,12 @@  int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_
 	if (rc)
 		return rc;
 
-	rc = bl->get_info(bl, name, total_size, erase_granule);
+	rc = bl->get_info(bl, bl_info);
 
 	/* Check the validity of what we are being told */
-	if (erase_granule && *erase_granule != bl->erase_mask + 1)
+	if (bl_info->erase_granule != bl->erase_mask + 1)
 		FL_ERR("blocklevel_get_info: WARNING: erase_granule (0x%08x) and erase_mask"
-				" (0x%08x) don't match\n", *erase_granule, bl->erase_mask + 1);
+				" (0x%08x) don't match\n", bl_info->erase_granule, bl->erase_mask + 1);
 
 	release(bl);
 
@@ -417,7 +416,7 @@  out:
 
 int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len)
 {
-	uint32_t erase_size;
+	struct blocklevel_info bl_info;
 	const void *write_buf = buf;
 	void *write_buf_start = NULL;
 	void *erase_buf;
@@ -435,7 +434,7 @@  int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
 		return blocklevel_write(bl, pos, buf, len);
 	}
 
-	rc = blocklevel_get_info(bl, NULL, NULL, &erase_size);
+	rc = blocklevel_get_info(bl, &bl_info);
 	if (rc)
 		return rc;
 
@@ -458,7 +457,7 @@  int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
 		write_buf = write_buf_start;
 	}
 
-	erase_buf = malloc(erase_size);
+	erase_buf = malloc(bl_info.erase_granule);
 	if (!erase_buf) {
 		errno = ENOMEM;
 		rc = FLASH_ERR_MALLOC_FAILED;
@@ -470,32 +469,32 @@  int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
 		goto out_free;
 
 	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;
+		uint32_t erase_block = pos & ~(bl_info.erase_granule - 1);
+		uint32_t block_offset = pos & (bl_info.erase_granule - 1);
+		uint32_t size = bl_info.erase_granule > len ? len : bl_info.erase_granule;
 		int cmp;
 
 		/* Write crosses an erase boundary, shrink the write to the boundary */
-		if (erase_size < block_offset + size) {
-			size = erase_size - block_offset;
+		if (bl_info.erase_granule < block_offset + size) {
+			size = bl_info.erase_granule - block_offset;
 		}
 
-		rc = bl->read(bl, erase_block, erase_buf, erase_size);
+		rc = bl->read(bl, erase_block, erase_buf, bl_info.erase_granule);
 		if (rc)
 			goto out;
 
 		cmp = blocklevel_flashcmp(erase_buf + block_offset, write_buf, size);
 		FL_DBG("%s: region 0x%08x..0x%08x ", __func__,
-				erase_block, erase_size);
+				erase_block, bl_info.erase_granule);
 		if (cmp != 0) {
 			FL_DBG("needs ");
 			if (cmp == -1) {
 				FL_DBG("erase and ");
-				bl->erase(bl, erase_block, erase_size);
+				bl->erase(bl, erase_block, bl_info.erase_granule);
 			}
 			FL_DBG("write\n");
 			memcpy(erase_buf + block_offset, write_buf, size);
-			rc = bl->write(bl, erase_block, erase_buf, erase_size);
+			rc = bl->write(bl, erase_block, erase_buf, bl_info.erase_granule);
 			if (rc)
 				goto out;
 		}
diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
index ba42c83d0..d2d269054 100644
--- a/libflash/blocklevel.h
+++ b/libflash/blocklevel.h
@@ -34,6 +34,15 @@  enum blocklevel_flags {
 	WRITE_NEED_ERASE = 1,
 };
 
+struct blocklevel_info {
+	/* name is not owned by this struct and must persist for the
+	 * liftime of blocklevel_info
+	 */
+	const char *name;
+	uint64_t size;
+	uint32_t erase_granule;
+};
+
 /*
  * libffs may be used with different backends, all should provide these for
  * libflash to get the information it needs
@@ -45,8 +54,7 @@  struct blocklevel_device {
 	int (*read)(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len);
 	int (*write)(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
 	int (*erase)(struct blocklevel_device *bl, uint64_t pos, uint64_t len);
-	int (*get_info)(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
-			uint32_t *erase_granule);
+	int (*get_info)(struct blocklevel_device *bl, struct blocklevel_info *bl_info);
 
 	/*
 	 * Keep the erase mask so that blocklevel_erase() can do sanity checking
@@ -62,8 +70,8 @@  int blocklevel_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint6
 int blocklevel_raw_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
 int blocklevel_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
 int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len);
-int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
-		uint32_t *erase_granule);
+
+int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info);
 
 /*
  * blocklevel_smart_write() performs reads on the data to see if it
diff --git a/libflash/file.c b/libflash/file.c
index 7065eb4fa..b87679cd1 100644
--- a/libflash/file.c
+++ b/libflash/file.c
@@ -212,6 +212,7 @@  static int get_info_name(struct file_data *file_data, char **name)
 	}
 	lpath[len] = '\0';
 
+	free(*name);
 	*name = lpath;
 
 	free(path);
@@ -219,8 +220,8 @@  static int get_info_name(struct file_data *file_data, char **name)
 }
 
 
-static int mtd_get_info(struct blocklevel_device *bl, const char **name,
-		uint64_t *total_size, uint32_t *erase_granule)
+static int mtd_get_info(struct blocklevel_device *bl,
+		struct blocklevel_info *bl_info)
 {
 	struct file_data *file_data = container_of(bl, struct file_data, bl);
 	struct mtd_info_user mtd_info;
@@ -230,24 +231,19 @@  static int mtd_get_info(struct blocklevel_device *bl, const char **name,
 	if (rc == -1)
 		return FLASH_ERR_BAD_READ;
 
-	if (total_size)
-		*total_size = mtd_info.size;
-
-	if (erase_granule)
-		*erase_granule = mtd_info.erasesize;
+	rc = get_info_name(file_data, &(file_data->name));
+	if (rc)
+		return rc;
 
-	if (name) {
-		rc = get_info_name(file_data, &(file_data->name));
-		if (rc)
-			return rc;
-		*name = file_data->name;
-	}
+	bl_info->name = file_data->name;
+	bl_info->size = mtd_info.size;
+	bl_info->erase_granule = mtd_info.erasesize;
 
 	return 0;
 }
 
-static int file_get_info(struct blocklevel_device *bl, const char **name,
-		uint64_t *total_size, uint32_t *erase_granule)
+static int file_get_info(struct blocklevel_device *bl,
+		struct blocklevel_info *bl_info)
 {
 	struct file_data *file_data = container_of(bl, struct file_data, bl);
 	struct stat st;
@@ -256,18 +252,13 @@  static int file_get_info(struct blocklevel_device *bl, const char **name,
 	if (fstat(file_data->fd, &st))
 		return FLASH_ERR_PARM_ERROR;
 
-	if (total_size)
-		*total_size = st.st_size;
-
-	if (erase_granule)
-		*erase_granule = 1;
+	rc = get_info_name(file_data, &(file_data->name));
+	if (rc)
+		return rc;
 
-	if (name) {
-		rc = get_info_name(file_data, &(file_data->name));
-		if (rc)
-			return rc;
-		*name = file_data->name;
-	}
+	bl_info->name = file_data->name;
+	bl_info->size = st.st_size;
+	bl_info->erase_granule = 1;
 
 	return 0;
 }
@@ -315,8 +306,9 @@  int file_init(int fd, struct blocklevel_device **bl)
 		file_data->bl.erase = &mtd_erase;
 		file_data->bl.get_info = &mtd_get_info;
 		file_data->bl.flags = WRITE_NEED_ERASE;
-		mtd_get_info(&file_data->bl, NULL, NULL, &(file_data->bl.erase_mask));
-		file_data->bl.erase_mask--;
+		struct blocklevel_info bl_info;
+		mtd_get_info(&file_data->bl, &bl_info);
+		file_data->bl.erase_mask = bl_info.erase_granule - 1;
 	} else if (!S_ISREG(sbuf.st_mode)) {
 		/* If not a char device or a regular file something went wrong */
 		goto out;
diff --git a/libflash/libffs.c b/libflash/libffs.c
index 038f59425..6fc23eee9 100644
--- a/libflash/libffs.c
+++ b/libflash/libffs.c
@@ -216,25 +216,25 @@  int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
 {
 	struct __ffs_hdr blank_hdr;
 	struct __ffs_hdr raw_hdr;
+	struct blocklevel_info bl_info;
 	struct ffs_handle *f;
-	uint64_t total_size;
 	int rc, i;
 
 	if (!ffs || !bl)
 		return FLASH_ERR_PARM_ERROR;
 	*ffs = NULL;
 
-	rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
+	rc = blocklevel_get_info(bl, &bl_info);
 	if (rc) {
 		FL_ERR("FFS: Error %d retrieving flash info\n", rc);
 		return rc;
 	}
-	if (total_size > UINT_MAX)
+	if (bl_info.size > UINT_MAX)
 		return FLASH_ERR_VERIFY_FAILURE;
 	if ((offset + max_size) < offset)
 		return FLASH_ERR_PARM_ERROR;
 
-	if ((max_size > total_size))
+	if ((max_size > bl_info.size))
 		return FLASH_ERR_PARM_ERROR;
 
 	/* Read flash header */
diff --git a/libflash/libflash.c b/libflash/libflash.c
index 38f87b86e..82a2baecc 100644
--- a/libflash/libflash.c
+++ b/libflash/libflash.c
@@ -792,16 +792,15 @@  static int flash_configure(struct flash_chip *c)
 	return 0;
 }
 
-static int flash_get_info(struct blocklevel_device *bl, const char **name,
-		   uint64_t *total_size, uint32_t *erase_granule)
+static int flash_get_info(struct blocklevel_device *bl,
+		struct blocklevel_info *bl_info)
 {
 	struct flash_chip *c = container_of(bl, struct flash_chip, bl);
-	if (name)
-		*name = c->info.name;
-	if (total_size)
-		*total_size = c->tsize;
-	if (erase_granule)
-		*erase_granule = c->min_erase_mask + 1;
+
+	bl_info->name = c->info.name;
+	bl_info->size = c->tsize;
+	bl_info->erase_granule = c->min_erase_mask + 1;
+
 	return 0;
 }
 
diff --git a/libflash/mbox-flash.c b/libflash/mbox-flash.c
index 950e24f05..d4200ce53 100644
--- a/libflash/mbox-flash.c
+++ b/libflash/mbox-flash.c
@@ -745,8 +745,8 @@  static int mbox_flash_read(struct blocklevel_device *bl, uint64_t pos,
 	return rc;
 }
 
-static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
-		uint64_t *total_size, uint32_t *erase_granule)
+static int mbox_flash_get_info(struct blocklevel_device *bl,
+		struct blocklevel_info *bl_info)
 {
 	struct mbox_flash_data *mbox_flash;
 	struct bmc_mbox_msg *msg;
@@ -761,14 +761,7 @@  static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
 	if (!msg)
 		return FLASH_ERR_MALLOC_FAILED;
 
-	/*
-	 * We want to avoid runtime mallocs in skiboot. The expected
-	 * behavour to uses of libflash is that one can free() the memory
-	 * returned.
-	 * NULL will do for now.
-	 */
-	if (name)
-		*name = NULL;
+	bl_info->name = "pnor_mbox";
 
 	mbox_flash->busy = true;
 	rc = msg_send(mbox_flash, msg);
@@ -784,10 +777,8 @@  static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
 
 	mbox_flash->bl.erase_mask = mbox_flash->erase_granule - 1;
 
-	if (total_size)
-		*total_size = mbox_flash->total_size;
-	if (erase_granule)
-		*erase_granule = mbox_flash->erase_granule;
+	bl_info->size = mbox_flash->total_size;
+	bl_info->erase_granule = mbox_flash->erase_granule;
 
 out:
 	msg_free_memory(msg);
diff --git a/libflash/test/test-flash.c b/libflash/test/test-flash.c
index 3f77d6f3e..1ca467bb0 100644
--- a/libflash/test/test-flash.c
+++ b/libflash/test/test-flash.c
@@ -367,9 +367,7 @@  struct spi_flash_ctrl sim_ctrl = {
 int main(void)
 {
 	struct blocklevel_device *bl;
-	uint64_t total_size;
-	uint32_t erase_granule;
-	const char *name;
+	struct blocklevel_info bl_info;
 	uint16_t *test;
 	struct ecc64 *ecc_test;
 	uint64_t *test64;
@@ -384,7 +382,7 @@  int main(void)
 		ERR("flash_init failed with err %d\n", rc);
 		exit(1);
 	}
-	rc = flash_get_info(bl, &name, &total_size, &erase_granule);
+	rc = flash_get_info(bl, &bl_info);
 	if (rc) {
 		ERR("flash_get_info failed with err %d\n", rc);
 		exit(1);
diff --git a/platforms/mambo/mambo.c b/platforms/mambo/mambo.c
index cb6e103cc..dd7872a8e 100644
--- a/platforms/mambo/mambo.c
+++ b/platforms/mambo/mambo.c
@@ -125,19 +125,14 @@  static int bogus_disk_erase(struct blocklevel_device *bl __unused,
 	return 0; /* NOP */
 }
 
-static int bogus_disk_get_info(struct blocklevel_device *bl, const char **name,
-			      uint64_t *total_size, uint32_t *erase_granule)
+static int bogus_disk_get_info(struct blocklevel_device *bl,
+			struct blocklevel_info *bl_info)
 {
 	struct bogus_disk_info *bdi = bl->priv;
 
-	if (total_size)
-		*total_size = bdi->size;
-
-	if (erase_granule)
-		*erase_granule = BD_SECT_SZ;
-
-	if (name)
-		*name = "mambobogus";
+	bl_info->name = "mambobogus";
+	bl_info->size = bdi->size;
+	bl_info->erase_granule = BD_SECT_SZ;
 
 	return 0;
 }