On 3/7/2026 12:35 AM, Christian Marangi wrote:
> It might be useful to get the firmware size before reading it to allocate the
> correct size. This is needed for case where the firmware size change across
> different firmware version and is not always the same. In such case the only 
> way
> to handle this scenario is to allocate a big-enough buffer to read the 
> firmware.
> 
> To better handle this, introduce the request_firmware_size() OP to get the
> firmware size before reading it. This way proper buffer can be allocated and
> dynamic firmware size can be better supported.
> 
> Both FS and FIP lodaer are updated to handle the new .get_size() handler.
> 
> Signed-off-by: Christian Marangi <[email protected]>
> ---
>  drivers/misc/fw_loader/fip_loader.c | 35 +++++++++++++++
>  drivers/misc/fw_loader/fs_loader.c  | 70 ++++++++++++++++++++++++-----
>  drivers/misc/fw_loader/fw_loader.c  | 20 +++++++++
>  drivers/misc/fw_loader/internal.h   |  1 +
>  include/fw_loader.h                 |  9 ++++
>  5 files changed, 124 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/misc/fw_loader/fip_loader.c 
> b/drivers/misc/fw_loader/fip_loader.c
> index 376e1d2a59d8..a285f785db37 100644
> --- a/drivers/misc/fw_loader/fip_loader.c
> +++ b/drivers/misc/fw_loader/fip_loader.c
> @@ -523,6 +523,40 @@ out:
>       return ret;
>  }
>  
> +/**
> + * fw_get_fip_firmware_size - get firmware size.
> + * @dev: An instance of a driver.
> + *
> + * Return: Size of firmware, negative value when error.
> + */
> +static int fw_get_fip_firmware_size(struct udevice *dev)
> +{
> +     struct fip_toc_entry ent;
> +     struct fip_storage_info info = { };
> +     int ret;
> +
> +     ret = fw_parse_storage_info(dev, &info);
> +     if (ret)
> +             goto out;
> +
> +     struct firmware *firmwarep = dev_get_priv(dev);
> +
> +     if (!firmwarep) {
> +             ret = -EINVAL;
> +             goto out;
> +     }
> +
> +     ret = parse_fip_firmware(firmwarep, &info, &ent);
> +     if (ret)
> +             goto out;
> +
> +     ret = ent.size;
> +
> +out:
> +     fw_storage_info_release(dev, &info);
> +     return ret;
> +}
> +
>  static int fip_loader_probe(struct udevice *dev)
>  {
>       struct device_plat *plat = dev_get_plat(dev);
> @@ -533,6 +567,7 @@ static int fip_loader_probe(struct udevice *dev)
>               return ret;
>  
>       plat->get_firmware = fw_get_fip_firmware;
> +     plat->get_size = fw_get_fip_firmware_size;
>  
>       return 0;
>  };
> diff --git a/drivers/misc/fw_loader/fs_loader.c 
> b/drivers/misc/fw_loader/fs_loader.c
> index 4ae01b9c8f0d..d6b9f4998815 100644
> --- a/drivers/misc/fw_loader/fs_loader.c
> +++ b/drivers/misc/fw_loader/fs_loader.c
> @@ -93,15 +93,8 @@ static int select_fs_dev(struct device_plat *plat)
>       return ret;
>  }
>  
> -/**
> - * fw_get_filesystem_firmware - load firmware into an allocated buffer.
> - * @dev: An instance of a driver.
> - *
> - * Return: Size of total read, negative value when error.
> - */
> -static int fw_get_filesystem_firmware(struct udevice *dev)
> +static int __fw_get_filesystem_firmware_prepare(struct udevice *dev)
>  {
> -     loff_t actread = 0;
>       char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
>       int ret;
>  
> @@ -126,6 +119,28 @@ static int fw_get_filesystem_firmware(struct udevice 
> *dev)
>               ret = select_fs_dev(dev_get_plat(dev));
>       }
>  
> +     return ret;
> +}
> +
> +static void __fw_get_filesystem_firmware_release(struct udevice *dev)
> +{
> +#ifdef CONFIG_CMD_UBIFS
> +     umount_ubifs();
> +#endif
> +}
> +
> +/**
> + * fw_get_filesystem_firmware - load firmware into an allocated buffer.
> + * @dev: An instance of a driver.
> + *
> + * Return: Size of total read, negative value when error.
> + */
> +static int fw_get_filesystem_firmware(struct udevice *dev)
> +{
> +     loff_t actread = 0;
> +     int ret;
> +
> +     ret = __fw_get_filesystem_firmware_prepare(dev);
>       if (ret)
>               goto out;
>  
> @@ -147,9 +162,41 @@ static int fw_get_filesystem_firmware(struct udevice 
> *dev)
>       }
>  
>  out:
> -#ifdef CONFIG_CMD_UBIFS
> -     umount_ubifs();
> -#endif
> +     __fw_get_filesystem_firmware_release(dev);
> +     return ret;
> +}
> +
> +/**
> + * fw_get_filesystem_firmware_size - get firmware size.
> + * @dev: An instance of a driver.
> + *
> + * Return: Size of firmware, negative value when error.
> + */
> +static int fw_get_filesystem_firmware_size(struct udevice *dev)
> +{
> +     loff_t size = 0;
> +     int ret;
> +
> +     ret = __fw_get_filesystem_firmware_prepare(dev);
> +     if (ret)
> +             goto out;
> +
> +     struct firmware *firmwarep = dev_get_priv(dev);
> +
> +     if (!firmwarep)
> +             return -ENOMEM;

goto out?

> +
> +     ret = fs_size(firmwarep->name, &size);
> +
> +     if (ret) {
> +             debug("Error: %d Failed to get size for %s.\n",
> +                   ret, firmwarep->name);
> +     } else {
> +             ret = size;
> +     }
> +
> +out:
> +     __fw_get_filesystem_firmware_release(dev);
>       return ret;
>  }
>  
> @@ -163,6 +210,7 @@ static int fs_loader_probe(struct udevice *dev)
>               return ret;
>  
>       plat->get_firmware = fw_get_filesystem_firmware;
> +     plat->get_size = fw_get_filesystem_firmware_size;
>  
>       return 0;
>  };
> diff --git a/drivers/misc/fw_loader/fw_loader.c 
> b/drivers/misc/fw_loader/fw_loader.c
> index d2446fdc07da..d5973fce4b9c 100644
> --- a/drivers/misc/fw_loader/fw_loader.c
> +++ b/drivers/misc/fw_loader/fw_loader.c
> @@ -162,3 +162,23 @@ int request_firmware_into_buf(struct udevice *dev,
>  
>       return plat->get_firmware(dev);
>  }
> +
> +int request_firmware_size(struct udevice *dev, const char *name)
> +{
> +     struct device_plat *plat;
> +     int ret;
> +
> +     if (!dev)
> +             return -EINVAL;
> +
> +     ret = _request_firmware_prepare(dev, name, NULL, 0, 0);
> +     if (ret < 0) /* error */
> +             return ret;
> +
> +     plat = dev_get_plat(dev);
> +
> +     if (!plat->get_size)
> +             return -EOPNOTSUPP;
> +
> +     return plat->get_size(dev);
> +}
> diff --git a/drivers/misc/fw_loader/internal.h 
> b/drivers/misc/fw_loader/internal.h
> index 5513e043925f..4701b494bf3f 100644
> --- a/drivers/misc/fw_loader/internal.h
> +++ b/drivers/misc/fw_loader/internal.h
> @@ -36,6 +36,7 @@ struct device_plat {
>       char *ubivol;
>  
>       int (*get_firmware)(struct udevice *dev);
> +     int (*get_size)(struct udevice *dev);
>  };
>  
>  /**
> diff --git a/include/fw_loader.h b/include/fw_loader.h
> index 7053c7bc6f05..1af3db385161 100644
> --- a/include/fw_loader.h
> +++ b/include/fw_loader.h
> @@ -39,6 +39,15 @@ int request_firmware_into_buf(struct udevice *dev,
>                             const char *name,
>                             void *buf, size_t size, u32 offset);
>  
> +/**
> + * request_firmware_size - Get firmware size.
> + * @dev: An instance of a driver.
> + * @name: Name of firmware file.
> + *
> + * Return: Size of firmware, negative value when error.
> + */
> +int request_firmware_size(struct udevice *dev, const char *name);
> +
>  /**
>   * request_firmware_into_buf_via_script() -
>   * Load firmware using a U-Boot script and copy to buffer

Thanks for this series. I think this starts to pave the way for us to move away
from using vendor specific drivers scattered around (like
arch/arm/mach-k3/r5/sysfw-loader.c) and eventually come into fw_loader.

-- 
Thanking You
Neha Malcom Francis

Reply via email to