固件上传 API

向固件加载器注册的设备驱动程序将公开持久性 sysfs 节点,使用户能够启动该设备的固件更新。设备驱动程序和/或设备本身负责对接收到的数据执行任何验证。固件上传使用固件回退文档中描述的相同loadingdata sysfs 文件。它还添加了额外的 sysfs 文件,以提供固件映像传输到设备的状态。

注册固件上传

设备驱动程序通过调用 firmware_upload_register() 来注册固件上传。参数列表中有一个名称,用于标识 /sys/class/firmware 下的设备。用户可以通过将 1 回显到目标设备的 loading sysfs 文件来启动固件上传。接下来,用户将固件映像写入 data sysfs 文件。写入固件数据后,用户将 0 回显到 loading sysfs 文件以表示完成。将 0 回显到 loading 还会触发在内核工作线程的上下文中将固件传输到较低级别的设备驱动程序。

要使用固件上传 API,请编写一个实现一组操作的驱动程序。probe 函数调用 firmware_upload_register(),而 remove 函数调用 firmware_upload_unregister(),例如

static const struct fw_upload_ops m10bmc_ops = {
        .prepare = m10bmc_sec_prepare,
        .write = m10bmc_sec_write,
        .poll_complete = m10bmc_sec_poll_complete,
        .cancel = m10bmc_sec_cancel,
        .cleanup = m10bmc_sec_cleanup,
};

static int m10bmc_sec_probe(struct platform_device *pdev)
{
        const char *fw_name, *truncate;
        struct m10bmc_sec *sec;
        struct fw_upload *fwl;
        unsigned int len;

        sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);
        if (!sec)
                return -ENOMEM;

        sec->dev = &pdev->dev;
        sec->m10bmc = dev_get_drvdata(pdev->dev.parent);
        dev_set_drvdata(&pdev->dev, sec);

        fw_name = dev_name(sec->dev);
        truncate = strstr(fw_name, ".auto");
        len = (truncate) ? truncate - fw_name : strlen(fw_name);
        sec->fw_name = kmemdup_nul(fw_name, len, GFP_KERNEL);

        fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name,
                                       &m10bmc_ops, sec);
        if (IS_ERR(fwl)) {
                dev_err(sec->dev, "Firmware Upload driver failed to start\n");
                kfree(sec->fw_name);
                return PTR_ERR(fwl);
        }

        sec->fwl = fwl;
        return 0;
}

static int m10bmc_sec_remove(struct platform_device *pdev)
{
        struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);

        firmware_upload_unregister(sec->fwl);
        kfree(sec->fw_name);
        return 0;
}

firmware_upload_register

struct fw_upload *firmware_upload_register(struct module *module, struct device *parent, const char *name, const struct fw_upload_ops *ops, void *dd_handle)

注册固件上传 sysfs API

参数

struct module *module

此设备的内核模块

struct device *parent

实例化固件上传的父设备

const char *name

要与此设备关联的固件名称

const struct fw_upload_ops *ops

指向固件上传操作结构的指针

void *dd_handle

指向父驱动程序私有数据的指针

name 在固件上传的所有用户中必须是唯一的。此设备的固件 sysfs 文件将在 /sys/class/firmware/name 中找到。

返回

struct fw_upload 指针或 ERR_PTR()

firmware_upload_unregister

void firmware_upload_unregister(struct fw_upload *fw_upload)

取消注册固件上传接口

参数

struct fw_upload *fw_upload

指向 struct fw_upload 的指针

固件上传操作

struct fw_upload_ops

支持固件上传的设备特定操作

定义:

struct fw_upload_ops {
    enum fw_upload_err (*prepare)(struct fw_upload *fw_upload, const u8 *data, u32 size);
    enum fw_upload_err (*write)(struct fw_upload *fw_upload,const u8 *data, u32 offset, u32 size, u32 *written);
    enum fw_upload_err (*poll_complete)(struct fw_upload *fw_upload);
    void (*cancel)(struct fw_upload *fw_upload);
    void (*cleanup)(struct fw_upload *fw_upload);
};

成员

prepare

必需:准备安全更新

write

必需:write() 操作接收要写入的剩余大小,并且必须返回实际写入的大小或负错误代码。将重复调用 write() 操作,直到写入所有数据。

poll_complete

必需:检查硬件身份验证/编程过程是否完成。

cancel

必需:请求取消更新。此操作是从不同的内核线程的上下文中调用的,因此需要考虑竞争条件。

cleanup

可选:补充 prepare() 函数,并在更新成功或失败时在 prepare 函数成功后调用。

固件上传进度代码

以下进度代码由固件加载器在内部使用。相应的字符串通过下面描述的 status sysfs 节点报告,并在 ABI 文档中记录。

enum fw_upload_prog

固件上传进度代码

常量

FW_UPLOAD_PROG_IDLE

没有正在进行的固件上传

FW_UPLOAD_PROG_RECEIVING

工作线程正在接收固件数据

FW_UPLOAD_PROG_PREPARING

目标设备正在准备固件上传

FW_UPLOAD_PROG_TRANSFERRING

数据正在复制到设备

FW_UPLOAD_PROG_PROGRAMMING

设备正在执行固件更新

FW_UPLOAD_PROG_MAX

最大进度代码标记

固件上传错误代码

如果失败,驱动程序操作可能会返回以下错误代码

enum fw_upload_err

固件上传错误代码

常量

FW_UPLOAD_ERR_NONE

返回以表示成功

FW_UPLOAD_ERR_HW_ERROR

硬件发出的错误信号,请参阅内核日志

FW_UPLOAD_ERR_TIMEOUT

SW 在与硬件/固件握手时超时

FW_UPLOAD_ERR_CANCELED

上传被用户取消

FW_UPLOAD_ERR_BUSY

已有上传操作正在进行中

FW_UPLOAD_ERR_INVALID_SIZE

无效的固件映像大小

FW_UPLOAD_ERR_RW_ERROR

读取或写入硬件失败,请参阅内核日志

FW_UPLOAD_ERR_WEAROUT

FLASH 设备正在接近耗损,请等待并重试

FW_UPLOAD_ERR_FW_INVALID

无效的固件文件

FW_UPLOAD_ERR_MAX

最大错误代码标记

Sysfs 属性

除了 loadingdata sysfs 文件之外,还有其他 sysfs 文件来监视数据传输到目标设备的状态,并确定传输的最终通过/失败状态。根据设备和固件映像的大小,固件更新可能需要几毫秒到几分钟。

其他 sysfs 文件是

  • status - 提供固件更新进度的指示

  • error - 提供失败固件更新的错误信息

  • remaining_size - 跟踪更新的数据传输部分

  • cancel - 将 1 回显到此文件以取消更新