FPGA 管理器

概述

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

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

编程映像的详细信息在结构 (struct fpga_image_info) 中给出。此结构包含指向 FPGA 映像的指针以及特定于映像的详细信息,例如映像是为完整还是部分重新配置而构建的。

如何支持新的 FPGA 设备

要添加另一个 FPGA 管理器,请编写一个实现一组操作的驱动程序。探测函数调用 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;
}

或者,探测函数可以调用资源管理的注册函数之一,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

包含操作的模块

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

布尔标志,用于告知 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

包含操作的所有者模块。

描述

此函数的调用者负责调用 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

包含操作的所有者模块。

描述

此函数的调用者负责调用 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

包含操作的所有者模块。

返回

成功时返回 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

包含操作的所有者模块。

返回

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

描述

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

void fpga_mgr_unregister(struct fpga_manager *mgr)

注销一个 FPGA 管理器。

参数

struct fpga_manager *mgr

fpga 管理器结构。

描述

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