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,否则返回负错误代码。
- 编程序列为:
.parse_header(可选,可以调用一次或多次)
.write_init
.write 或 .write_sg(可以调用一次或多次)
.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_states
- fpga_manager->state 的值。struct fpga_manager
- FPGA 管理器结构struct fpga_manager_ops
- 底层 FPGA 管理器驱动程序操作struct fpga_manager_info
- fpga_mgr_register_full() 的参数结构__fpga_mgr_register_full()
- 创建并注册一个 FPGA 管理器,使用 fpga_mgr_info 结构来提供完全的选项灵活性__fpga_mgr_register()
- 使用标准参数创建并注册一个 FPGA 管理器__devm_fpga_mgr_register_full()
-__fpga_mgr_register_full()
的资源管理版本fpga_mgr_unregister()
- 注销 FPGA 管理器
可以使用辅助宏 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 管理器驱动程序的移除函数中。