FPGA 管理器

概述

FPGA 管理器核心导出了一组用于使用映像编程 FPGA 的函数。该 API 与制造商无关。 所有制造商的特殊性都隐藏在底层驱动程序中,该驱动程序向核心注册一组操作。 FPGA 映像数据本身非常特定于制造商,但就我们的目的而言,它只是二进制数据。 FPGA 管理器核心不会解析它。

要编程的 FPGA 映像可以在散布/聚集列表中、单个连续缓冲区中或固件文件中。 因为应避免为缓冲区分配连续的内核内存,因此建议用户尽可能改用散布/聚集列表。

编程映像的详细信息显示在一个结构体 (struct fpga_image_info) 中。 此结构体包含诸如指向 FPGA 映像的指针以及映像特定的详细信息(例如映像是为完全还是部分重新配置而构建的)之类的参数。

如何支持新的 FPGA 设备

要添加另一个 FPGA 管理器,请编写一个实现一组操作的驱动程序。 probe 函数调用 fpga_mgr_register()fpga_mgr_register_full(),例如

static const struct fpga_manager_ops socfpga_fpga_ops = {
        .write_init = socfpga_fpga_ops_configure_init,
        .write = socfpga_fpga_ops_configure_write,
        .write_complete = socfpga_fpga_ops_configure_complete,
        .state = socfpga_fpga_ops_state,
};

static int socfpga_fpga_probe(struct platform_device *pdev)
{
        struct device *dev = &pdev->dev;
        struct socfpga_fpga_priv *priv;
        struct fpga_manager *mgr;
        int ret;

        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;

        /*
         * do ioremaps, get interrupts, etc. and save
         * them in priv
         */

        mgr = fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
                                &socfpga_fpga_ops, priv);
        if (IS_ERR(mgr))
                return PTR_ERR(mgr);

        platform_set_drvdata(pdev, mgr);

        return 0;
}

static int socfpga_fpga_remove(struct platform_device *pdev)
{
        struct fpga_manager *mgr = platform_get_drvdata(pdev);

        fpga_mgr_unregister(mgr);

        return 0;
}

或者,probe 函数可以调用资源管理的注册函数之一 devm_fpga_mgr_register()devm_fpga_mgr_register_full()。 使用这些函数时,参数语法相同,但应删除对 fpga_mgr_unregister() 的调用。 在上面的示例中,不需要 socfpga_fpga_remove() 函数。

这些操作将实现所需的任何设备特定寄存器写入,以执行此特定 FPGA 的编程序列。 这些操作成功时返回 0,否则返回负错误代码。

编程序列为:
  1. .parse_header(可选,可以调用一次或多次)

  2. .write_init

  3. .write 或 .write_sg(可以调用一次或多次)

  4. .write_complete

.parse_header 函数会将 header_size 和 data_size 设置为 struct fpga_image_info。 在 parse_header 调用之前,header_size 会使用 initial_header_size 初始化。 如果 fpga_manager_ops 的标志 skip_header 为 true,则 .write 函数将获取从头 header_size 偏移量开始的映像缓冲区。 如果设置了 data_size,则 .write 函数将获取映像缓冲区的 data_size 个字节,否则 .write 将获取数据直到映像缓冲区的末尾。 这不会影响 .write_sg,.write_sg 仍将以 sg_table 形式获取整个映像。 如果 FPGA 映像已映射为单个连续缓冲区,则整个缓冲区将传递到 .parse_header。 如果映像采用散布-聚集形式,则核心代码将在第一次调用 .parse_header 之前缓冲至少 .initial_header_size,如果这不够,则 .parse_header 应将所需大小设置为 info->header_size 并返回 -EAGAIN,然后将再次使用输入端上的较大映像缓冲区调用它。

.write_init 函数将准备 FPGA 以接收映像数据。 传递到 .write_init 的缓冲区将至少为 info->header_size 字节长;如果整个比特流不可立即使用,则核心代码将在启动之前缓冲至少这么多。

.write 函数将缓冲区写入 FPGA。 该缓冲区可能包含整个 FPGA 映像,也可能包含 FPGA 映像的较小块。 在后一种情况下,会为连续块多次调用此函数。 此接口适用于使用 PIO 的驱动程序。

.write_sg 版本的行为与 .write 相同,只是输入是 sg_table 散布列表。 此接口适用于使用 DMA 的驱动程序。

.write_complete 函数在所有映像都已写入后调用,以使 FPGA 进入运行模式。

这些操作包括一个 .state 函数,该函数将确定 FPGA 所处的状态,并返回 enum fpga_mgr_states 类型的代码。 它不会导致状态更改。

用于实现新的 FPGA 管理器驱动程序的 API

辅助宏 fpga_mgr_register_full()fpga_mgr_register()devm_fpga_mgr_register_full()devm_fpga_mgr_register() 可用于简化注册。

enum fpga_mgr_states

fpga 框架状态

常量

FPGA_MGR_STATE_UNKNOWN

无法确定状态

FPGA_MGR_STATE_POWER_OFF

FPGA 电源已关闭

FPGA_MGR_STATE_POWER_UP

FPGA 报告电源已开启

FPGA_MGR_STATE_RESET

FPGA 处于复位状态

FPGA_MGR_STATE_FIRMWARE_REQ

固件请求正在进行中

FPGA_MGR_STATE_FIRMWARE_REQ_ERR

固件请求失败

FPGA_MGR_STATE_PARSE_HEADER

解析 FPGA 映像标头

FPGA_MGR_STATE_PARSE_HEADER_ERR

PARSE_HEADER 阶段期间出错

FPGA_MGR_STATE_WRITE_INIT

准备 FPGA 进行编程

FPGA_MGR_STATE_WRITE_INIT_ERR

WRITE_INIT 阶段期间出错

FPGA_MGR_STATE_WRITE

将映像写入 FPGA

FPGA_MGR_STATE_WRITE_ERR

写入 FPGA 时出错

FPGA_MGR_STATE_WRITE_COMPLETE

执行编程后步骤

FPGA_MGR_STATE_WRITE_COMPLETE_ERR

WRITE_COMPLETE 期间出错

FPGA_MGR_STATE_OPERATING

FPGA 已编程并正在运行

struct fpga_manager

fpga 管理器结构体

定义:

struct fpga_manager {
    const char *name;
    struct device dev;
    struct mutex ref_mutex;
    enum fpga_mgr_states state;
    struct fpga_compat_id *compat_id;
    const struct fpga_manager_ops *mops;
    struct module *mops_owner;
    void *priv;
};

成员

name

底层 fpga 管理器的名称

dev

fpga 管理器设备

ref_mutex

仅允许对 fpga 管理器的一个引用

state

fpga 管理器的状态

compat_id

用于兼容性检查的 FPGA 管理器 ID。

mops

指向 fpga 管理器操作结构体的指针

mops_owner

包含 mops 的模块

priv

底层驱动程序私有日期

struct fpga_manager_ops

底层 fpga 管理器驱动程序的操作

定义:

struct fpga_manager_ops {
    size_t initial_header_size;
    bool skip_header;
    enum fpga_mgr_states (*state)(struct fpga_manager *mgr);
    u64 (*status)(struct fpga_manager *mgr);
    int (*parse_header)(struct fpga_manager *mgr,struct fpga_image_info *info, const char *buf, size_t count);
    int (*write_init)(struct fpga_manager *mgr,struct fpga_image_info *info, const char *buf, size_t count);
    int (*write)(struct fpga_manager *mgr, const char *buf, size_t count);
    int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt);
    int (*write_complete)(struct fpga_manager *mgr, struct fpga_image_info *info);
    void (*fpga_remove)(struct fpga_manager *mgr);
    const struct attribute_group **groups;
};

成员

initial_header_size

应传递到 parse_header 和 write_init 的最小字节数。

skip_header

bool 标志,用于告诉 fpga-mgr 核心在调用写入回调时是否应跳过映像开头的 info->header_size 部分。

state

返回 FPGA 状态的枚举值

status

返回 FPGA 的状态,包括重新配置错误代码

parse_header

解析 FPGA 映像标头以设置 info->header_size 和 info->data_size。 如果输入缓冲区不够大,请将所需大小设置为 info->header_size 并返回 -EAGAIN。

write_init

准备 FPGA 以接收配置数据

write

将 count 个字节的配置数据写入 FPGA

write_sg

将配置数据的散布列表写入 FPGA

write_complete

写入完成后,将 FPGA 设置为运行状态

fpga_remove

可选:在驱动程序移除期间将 FPGA 设置为特定状态

groups

可选的属性组。

描述

fpga_manager_ops 是由特定的 fpga 管理器驱动程序实现的底层函数。 可选的函数在调用之前会测试是否为 NULL,因此省略它们是可以的。

struct fpga_manager_info

FPGA 管理器的参数集合

定义:

struct fpga_manager_info {
    const char *name;
    struct fpga_compat_id *compat_id;
    const struct fpga_manager_ops *mops;
    void *priv;
};

成员

name

fpga 管理器名称

compat_id

用于兼容性检查的 FPGA 管理器 ID。

mops

指向 fpga 管理器操作结构体的指针

priv

fpga 管理器私有数据

描述

fpga_manager_info 包含 register_full 函数的参数。 这些参数被分成一个 info 结构体,因为它们中的一些是可选的,而其他的可能会在将来被添加。 info 结构体有助于维护稳定的 API。

struct fpga_manager *__fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, struct module *owner)

创建并注册 FPGA 管理器设备

参数

struct device *parent

来自 pdev 的 fpga 管理器设备

const struct fpga_manager_info *info

fpga 管理器的参数

struct module *owner

包含操作的 owner 模块

描述

此函数的调用者负责调用 fpga_mgr_unregister()。 建议改用 devm_fpga_mgr_register_full()。

返回

指向 struct fpga_manager 指针的指针,或者 ERR_PTR()

struct fpga_manager *__fpga_mgr_register(struct device *parent, const char *name, const struct fpga_manager_ops *mops, void *priv, struct module *owner)

创建并注册 FPGA 管理器设备

参数

struct device *parent

来自 pdev 的 fpga 管理器设备

const char *name

fpga 管理器名称

const struct fpga_manager_ops *mops

指向 fpga 管理器操作结构体的指针

void *priv

fpga 管理器私有数据

struct module *owner

包含操作的 owner 模块

描述

此函数的调用者负责调用 fpga_mgr_unregister()。 建议改用 devm_fpga_mgr_register()。 此简单版本的注册函数应足以满足大多数用户的需求。 fpga_mgr_register_full() 函数可用于需要传递其他可选参数的用户。

返回

指向 struct fpga_manager 指针的指针,或者 ERR_PTR()

struct fpga_manager *__devm_fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info, struct module *owner)

fpga_mgr_register() 的资源管理变体

参数

struct device *parent

来自 pdev 的 fpga 管理器设备

const struct fpga_manager_info *info

fpga 管理器的参数

struct module *owner

包含操作的 owner 模块

返回

成功时返回 FPGA 管理器指针,否则返回负的错误代码。

描述

这是 fpga_mgr_register_full() 的 devres 变体,当管理设备分离时,将自动调用注销函数。

struct fpga_manager *__devm_fpga_mgr_register(struct device *parent, const char *name, const struct fpga_manager_ops *mops, void *priv, struct module *owner)

fpga_mgr_register() 的资源管理变体

参数

struct device *parent

来自 pdev 的 fpga 管理器设备

const char *name

fpga 管理器名称

const struct fpga_manager_ops *mops

指向 fpga 管理器操作结构体的指针

void *priv

fpga 管理器私有数据

struct module *owner

包含操作的 owner 模块

返回

成功时返回 FPGA 管理器指针,否则返回负的错误代码。

描述

这是 fpga_mgr_register() 的 devres 变体,当管理设备分离时,将自动调用注销函数。

void fpga_mgr_unregister(struct fpga_manager *mgr)

注销一个 FPGA 管理器

参数

struct fpga_manager *mgr

FPGA 管理器结构体

描述

此函数旨在用于 FPGA 管理器驱动程序的 remove 函数中。