固件上传 API

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

注册固件上传

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

要使用固件上传 API,请编写一个实现一组 ops 的驱动程序。探针函数调用 firmware_upload_register(),删除函数调用 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

指向固件上传 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 的指针

固件上传 Ops

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() op 接收要写入的剩余大小,并且必须返回实际写入的大小或负错误代码。write() op 将被重复调用,直到写入所有数据。

poll_complete

必需:检查硬件身份验证/编程过程的完成情况。

cancel

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

cleanup

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

固件上传进度代码

以下进度代码由固件加载器内部使用。相应的字符串通过下面描述的状态 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

最大进度代码标记

固件上传错误代码

如果发生故障,驱动程序 ops 可能会返回以下错误代码

enum fw_upload_err

固件上传错误代码

常量

FW_UPLOAD_ERR_NONE

返回以指示成功

FW_UPLOAD_ERR_HW_ERROR

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

FW_UPLOAD_ERR_TIMEOUT

软件与硬件/固件握手超时

FW_UPLOAD_ERR_CANCELED

上传被用户取消

FW_UPLOAD_ERR_BUSY

已经有一个上传操作正在进行中

FW_UPLOAD_ERR_INVALID_SIZE

固件映像大小无效

FW_UPLOAD_ERR_RW_ERROR

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

FW_UPLOAD_ERR_WEAROUT

闪存设备即将耗尽,请等待并重试

FW_UPLOAD_ERR_FW_INVALID

固件文件无效

FW_UPLOAD_ERR_MAX

最大错误代码标记

Sysfs 属性

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

额外的 sysfs 文件是

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

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

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

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