DOCA 文档 v2.10.0

DOCA DevEmu PCI Generic

注意

此库在 alpha 级别提供支持;不保证向后兼容性。

本指南提供有关构建和开发需要模拟通用 PCIe 设备的应用程序的说明。

DOCA DevEmu PCI Generic 是 DOCA 设备模拟子系统的一部分。它提供低级软件 API,允许使用 NVIDIA® BlueField® 的模拟功能创建自定义 PCIe 设备。

例如,它可以通过创建通用模拟设备、配置其功能和 BAR 以符合 NVMe 规范,并在 DPU 中根据需要操作它来模拟 NVMe 设备。

此库遵循 DOCA Core Context 的架构。建议事先阅读以下章节

通用设备模拟是 DOCA PCIe 设备模拟的一部分。建议事先阅读以下指南

DOCA DevEmu PCI Generic 模拟仅在 BlueField 目标上受支持。BlueField 必须满足以下要求

  • DOCA 版本 2.7.0 或更高版本

  • BlueField-3 固件 32.41.1000 或更高版本

信息

库必须以 root 权限运行。

请参阅 DOCA DevEmu PCI 环境,了解更多必要的配置。

DOCA DevEmu PCI Generic 允许创建通用 PCI 类型。PCI 类型是 DOCA DevEmu PCI 库的一部分。它负责配置模拟设备的功能和 bar 布局。

PCI 类型可以被视为创建模拟设备的模板。这样,用户首先配置一种类型,然后他们可以使用它来创建多个具有相同配置的模拟设备。

为了更具体的示例,假设您想模拟 NVMe 设备,那么您将创建一个类型并配置其功能和 BAR 以符合 NVMe 规范,之后您可以使用相同的类型来生成多个 NVMe 模拟设备。

PCIe 配置空间

PCIe 配置空间长 256 字节,并且具有 64 字节长的标头。每个字段都可以称为寄存器(例如,设备 ID)。

每个 PCIe 设备都需要按照 PCIe 规范中定义的方式实现 PCIe 配置空间。

然后,主机可以读取和/或写入 PCIe 配置空间中的寄存器。这允许 PCIe 驱动程序和 BIOS 与设备交互并执行所需的设置。

可以配置 PCIe 配置空间标头中的寄存器,如下图所示

PCI_header-version-1-modificationdate-1725860395143-api-v2.png

信息

0x0 是唯一支持的标头类型(通用设备)。

以下寄存器是只读的,它们用于标识设备

寄存器名称

描述

示例

类代码

定义设备的功能

可以进一步分为 3 个值

{类:子类:程序 IF}

0x020000

类:0x02(网络控制器)

子类:0x00(以太网控制器)

程序 IF:0x00 (N/A)

修订 ID

设备修订的唯一标识符

供应商自行分配 ID

0x01

(修订版 01)

供应商 ID

芯片组供应商的唯一标识符

供应商从 PCI-SIG 分配 ID

0x15b3

英伟达

设备 ID

芯片组的唯一标识符

供应商自行分配 ID

0xa2dc

BlueField-3 集成 ConnectX-7 网络控制器

子系统供应商 ID

卡供应商的唯一标识符

供应商从 PCI-SIG 分配 ID

0x15b3

英伟达

子系统 ID

卡的唯一标识符

供应商自行分配 ID

0x0051


BAR

虽然 PCIe 配置空间可用于与 PCIe 设备交互,但这不足以实现设备的目标功能。相反,它仅与 PCIe 层相关。

为了启用特定于协议的功能,设备配置了额外的内存区域,称为基地址寄存器 (BAR),主机可以使用这些区域与设备交互。与 PCIe 配置空间不同,BAR 由设备定义,并且与它们的交互是设备特定的。例如,PCIe 驱动程序根据 PCIe 规范与 NVMe 设备的 PCIe 配置空间交互,而 NVMe 驱动程序根据 NVMe 规范与 BAR 区域交互。

BAR 上的任何读取/写入请求通常都会路由到硬件,但在模拟设备的情况下,请求会路由到软件。

DOCA DevEmu PCI 类型库提供了 API,允许软件选择用于将请求路由到软件的机制,同时考虑到现有设备中常用的设计模式。

Bar_Overview-version-1-modificationdate-1725860395473-api-v2.png

每个 PCIe 设备最多可以有 6 个具有不同属性的 BAR。在 PCIe 总线枚举过程中,PCIe 设备必须能够通告有关每个 BAR 布局的信息。基于通告的信息,BIOS/OS 然后为每个 BAR 分配一个内存区域,并将地址分配给 PCIe 配置空间标头中的相关 BAR。然后,驱动程序可以使用分配的内存地址对 BAR 执行读取/写入操作。

BAR 布局

PCIe 设备必须能够提供有关每个 BAR 布局的信息。

布局可以分为 2 种类型,每种类型都有自己的属性,如下面的小节中详细介绍。

I/O 映射

根据 PCIe 规范,以下表示 I/O 映射 BAR

io_mapped-version-1-modificationdate-1725860395760-api-v2.png

此外,BAR 寄存器负责在枚举期间通告请求的大小。

信息

大小必须是 2 的幂。

用户可以使用以下 API 将 BAR 设置为 I/O 映射

复制
已复制!
            

doca_devemu_pci_type_set_io_bar_conf(struct doca_devemu_pci_type *pci_type, uint8_t id, uint8_t log_sz) 

  • id – BAR ID

  • log_sz – BAR 大小的对数

内存映射

根据 PCIe 规范,以下表示内存映射 BAR

memory_mapped_-version-1-modificationdate-1725860396090-api-v2.png

此外,BAR 寄存器负责在枚举期间通告请求的大小。

信息

大小必须是 2 的幂。

内存映射 BAR 允许分配 64 位地址。为了实现这一点,用户必须将 bar 内存类型指定为 64 位,然后将下一个 BAR(BAR ID + 1)的大小设置为 0。

设置可预取位表示对 BAR 的读取没有副作用。

用户可以使用以下 API 将 BAR 设置为内存映射

复制
已复制!
            

doca_devemu_pci_type_set_memory_bar_conf(struct doca_devemu_pci_type *pci_type, uint8_t id, uint8_t log_sz, enum doca_devemu_pci_bar_mem_type memory_type, uint8_t prefetchable)

  • id – BAR ID

  • log_sz – BAR 大小的对数。如果设置为 0,则大小被视为 0(而不是 1)。

  • memory_type – 指定 BAR 的内存类型。如果设置为 64 位,则下一个 BAR 必须将 log_sz 设置为 0。

  • prefetchable – 指示 BAR 内存是否可预取(值分别为 1 或 0)

BAR 区域

BAR 区域是指构成 BAR 布局的内存区域。这不是 PCIe 规范的一部分,而是一个 DOCA 概念,允许用户自定义主机与 BAR 交互时的行为。

BAR 区域定义了当主机对 BAR 内的地址执行读取/写入操作时的行为,以便每个地址都落在用户定义的某个内存区域中。

Bar_region_overview-version-1-modificationdate-1725860396423-api-v2.png

通用配置

所有 BAR 区域都具有这些共同的配置

  • id – 区域所属的 BAR ID

  • start_addr – 区域在 BAR 布局内的起始地址,相对于 BAR。0 表示 BAR 布局的开始。

  • size – BAR 区域的大小

目前,有 4 种 BAR 区域类型,定义了不同的行为

  • 有状态

  • 按偏移量 DB

  • 按数据 DB

  • MSIX 表

  • MSIX PBA

通用控制路径(有状态 BAR 区域)

有状态区域可以用作共享内存,以便内容在固件中维护。从驱动程序读取返回最新值,而写入更新值并触发 DPU 上运行的软件的事件。

这对于驱动程序和设备之间的通信非常有用,在控制路径期间(例如,公开功能、初始化)。

信息

某些限制适用,请参阅 限制 部分

驱动程序读取

从驱动程序读取会返回写入到该区域的最新值,无论是由主机还是驱动程序本身写入的。

stateful_region_read-version-1-modificationdate-1725860396727-api-v2.png

驱动程序写入

从驱动程序写入会更新写入地址的值,并通知在 Arm 上运行的软件已发生写入。Arm 上的通知作为异步事件到达(请参阅 doca_devemu_pci_dev_event_bar_stateful_region_driver_write)。

stateful_region_write-version-1-modificationdate-1725860396950-api-v2.png

信息

到达 Arm 软件的事件是异步的,因此它可能在驱动程序完成写入后到达。


DPU 读取

DPU 可以使用 doca_devemu_pci_dev_query_bar_stateful_region_values 读取有状态区域的值。这将返回有状态区域值的最新快照。在“有状态区域驱动程序写入事件”发生后,查找驱动程序写入的内容可能特别有用。

DPU 写入

DPU 可以使用 doca_devemu_pci_dev_modify_bar_stateful_region_values 写入有状态区域的值。这将更新这些值,以便后续从驱动程序或 DPU 读取返回这些值。

默认值

DPU 可以为有状态区域设置默认值。默认值分为 2 层

  • 类型默认值 – 这些值是为具有相同类型的所有设备设置的。只有在当前不存在设备时才能设置此值。

  • 设备默认值 – 这些值是为特定设备设置的,并在下一个 FLR 周期或设备的下一个热插拔时生效

有状态区域的读取遵循以下层次结构

  1. 返回主机或驱动程序写入的最新值(以最后完成的为准)。

  2. 返回设备默认值。

  3. 返回类型默认值。

  4. 返回 0。

stateful_default_values-version-1-modificationdate-1725860397300-api-v2.png

通用数据路径(DB BAR 区域)

门铃 (DB) 区域可用于在驱动程序和 DPU 之间实现消费者-生产者队列,以便从驱动程序写入将通过 DPA 触发 DPU 上的事件,从而允许它获取写入的值。这对于驱动程序和设备之间的通信非常有用,在数据路径期间允许 IO 处理。

虽然 DB 不是 PCIe 规范的一部分,但它是供应商广泛使用的机制(例如,RDMA QP、NVMe SQ、virtio VQ 等)。

DB_region_overview-version-1-modificationdate-1725860397570-api-v2.png

同一个 DB 区域可用于管理多个 DB,以便每个 DB 可用于实现队列。

DPU 软件可以单独利用 DB 资源

  • 每个 DB 资源都有一个唯一的从零开始的索引,称为 DB ID

  • DB 资源可以单独管理(创建/销毁/修改/查询)

  • 每个 DB 资源都有单独的通知机制。也就是说,DPU 上的通知是为每个 DB 单独触发的。

驱动程序写入

DB 通常由一个数值(例如,uint32_t)组成,表示队列的消费者/生产者索引。

当驱动程序写入 DB 区域时,相关的 DB 资源将使用写入的值进行更新,并且会向 DPU 发送通知。

当驱动程序写入 DB BAR 区域时,它必须遵守以下规定

  • 写入的大小必须与 DB 值的大小匹配(例如,uint32_t

  • 区域内的偏移量必须与 DB 步幅大小或 DB 大小对齐

流程如下所示

  • 驱动程序在 DB BAR 区域内的某个偏移量处执行 DB 值的写入

  • DPU 计算写入的目标 DB ID。取决于区域类型

    • 按偏移量 DB – DPU 根据相对于 DB BAR 区域的写入偏移量计算 DB ID

    • 按数据 DB – DPU 解析写入的 DB 值并从中提取 DB ID

  • DPU 使用驱动程序写入的值更新具有匹配 DB ID 的 DB 资源

  • DPU 向 DPA 应用程序发送通知,告知它具有 DB ID 的 DB 的值已由驱动程序更新

驱动程序读取

驱动程序不应尝试从 DB 区域读取。这样做会导致异常行为。

BlueField 写入

BlueField 可以使用 doca_devemu_pci_db_modify_value 单独更新每个 DB 资源的值。这会产生与驱动程序使用写入 DB 区域更新值类似的副作用。

BlueField 读取

BlueField 可以使用以下方法之一单独读取每个 DB 资源的值

  • 使用 doca_devemu_pci_db_query_value 从 BlueField Arm 读取值

  • 使用 doca_dpa_dev_devemu_pci_db_get_value 从 DPA 读取值

第一种选择是耗时的操作,仅建议用于控制路径。在数据路径中,建议仅使用第二种选择。

按偏移量 DB

DB_region_by_offset-version-1-modificationdate-1725860397847-api-v2.png

API doca_devemu_pci_type_set_bar_db_region_by_offset_conf 可用于设置按偏移量 DB 区域。当驱动程序使用此区域写入 DB 值时,DPU 会根据写入偏移量接收相关 DB 资源的通知,以便 DB ID 的计算方式如下:db_id=write_offset/db_stride_size

警告

作为步幅一部分但不是门铃一部分的区域不应用于任何读取/写入操作,这样做将导致未定义的异常。


按数据 DB

DB_region_by_data-version-1-modificationdate-1725860398063-api-v2.png

API doca_devemu_pci_type_set_bar_db_region_by_data_conf 可用于设置按数据 DB 区域。当驱动程序使用此区域写入 DB 值时,DPU 会根据写入的 DB 值接收相关 DB 资源的通知,以便写入偏移量与触发的 DB 之间没有关系。此 DB 区域假定 DB ID 嵌入在驱动程序写入的 DB 值中。设置此区域时,用户必须指定 DB ID 的最高有效字节 (MSB) 和最低有效字节 (LSB) 嵌入在 DB 值中的位置。

DPU 遵循以下步骤从 DB 值中提取 DB ID

  • 驱动程序写入 DB 值

  • BlueField 提取 MSB 和 LSB 之间的字节

  • DPU 将 MSB 索引与 LSB 索引进行比较

    • 如果 MSB 索引大于 LSB 索引:提取的值被解释为小端

    • 如果 LSB 索引大于 MSB 索引:提取的值被解释为大端

示例

DB 大小为 4 字节,LSB 为 1,MSB 为 3。

  • 驱动程序以小端模式将值 0xCCDDEEFF 写入索引 0 处的 DB 区域

    • 该值写入内存,如下所示:[0]=FF [1]=EE [2]=DD [3]=CC

  • 相关字节如下:[1]=EE [2]=DD [3]=CC

  • 由于 MSB (3) 大于 LSB (1),因此该值被解释为小端:db_id = 0xCCDDEE

MSI-X 功能(MSI-X BAR 区域)

消息信号中断扩展 (MSI-X) 通常由 PCIe 设备用于通过 PCIe 总线向主机驱动程序发送中断。DOCA API 允许用户按照 PCIe 规范公开 MSI-X 功能,并在以后使用它向主机驱动程序发送中断。

要配置它,用户必须提供以下内容

  • MSI-X 向量的数量,可以使用 doca_devemu_pci_type_set_num_msix 完成

  • 定义 MSI-X 表

  • 定义 MSI-X PBA

MSI-X 表 BAR 区域

根据 PCIe 规范,为了公开 MSI-X 功能,设备必须在其 BAR 内指定一个内存区域作为 MSI-X 表区域。在 DOCA 中,可以使用 doca_devemu_pci_type_set_bar_msix_table_region_conf 完成此操作。

MSI-X PBA BAR 区域

根据 PCIe 规范,为了公开 MSI-X 功能,设备必须在其 BAR 内指定一个内存区域作为 MSI-X 挂起位数组 (PBA) 区域。在 DOCA 中,可以使用 doca_devemu_pci_type_set_bar_msix_pba_region_conf 完成此操作。

从 DPU 触发 MSI-X

可以为每个向量单独触发 MSI-X。这只能使用 DPA API doca_dpa_dev_devemu_pci_msix_raise 完成。

DMA 内存

某些操作需要访问由主机驱动程序设置的内存。DOCA 的设备模拟 API 允许用户使用 DOCA mmap 访问此类 I/O 内存(请参阅 DOCA Core 内存子系统)。

启动 PCIe 设备后,可以使用 doca_devemu_pci_mmap_create 获取引用主机内存的 mmap。创建此 mmap 后,可以通过提供以下内容来配置它

  • 访问权限

  • 主机内存范围

  • 可以访问内存的 DOCA 设备

然后,mmap 可用于创建引用主机上内存的缓冲区。缓冲区的地址在本地不可访问(即,CPU 无法取消引用地址),相反,地址将是主机驱动程序定义的 I/O 地址。

从 mmap 创建的缓冲区可以与其他 DOCA 库一起使用,并接受 doca_buf 作为输入。这包括

功能级重置

FLR 可以按照 DOCA DevEmu PCI FLR 中所述的方式处理。此外,用户必须确保在停止 PCIe 设备之前销毁以下资源

  • 使用 doca_devemu_pci_db_create_on_dpa 创建的门铃

  • 使用 doca_devemu_pci_msix_create_on_dpa 创建的 MSI-X 向量

  • 使用 doca_devemu_pci_mmap_create 创建的内存映射

限制

根据“驱动程序写入”中的解释,用户可以假设 DOCA DevEmu PCI Generic 支持创建模拟 PCI 设备,但存在限制,即当驱动程序写入寄存器时,该值可以立即用于后续从同一寄存器读取。但是,这种即时可用性并不能确保已完成写入触发的任何必需的内部操作。建议依赖特定的不同寄存器值来确认写入操作的完成。例如,当实现写入清除操作时,例如写入 1 到寄存器 A 以清除寄存器 B,建议轮询寄存器 B,直到它指示所需的状态。这种方法确保写入操作已成功执行。如果设备规范要求在公开写入值以供后续读取之前完成某些操作,则无法使用 DOCA DevEmu PCI 通用框架模拟此类设备。

DOCA PCI 设备模拟需要设备才能运行。有关选择设备的信息,请参阅 DOCA DevEmu PCI 设备支持

某些设备可以允许不同的功能,如下所示

  • 模拟设备的最大数量

  • 不同 PCIe 类型的最大数量

  • BAR 的最大数量

  • BAR 的最大大小

  • 门铃的最大数量

  • MSI-X 向量的最大数量

  • 是否支持将设备添加到与 DOCA devemu PCI 设备关联的 DOCA mmap

  • 对于每种 BAR 区域类型,都有以下功能

    • 是否支持该区域

    • 此类型的区域的最大数量

    • 区域的起始地址对齐

    • 区域的大小对齐

    • 区域的最小/最大大小

提示

由于功能列表可能很长,建议使用 DOCA 功能打印工具 来概览所有可用的功能。

以 root 用户身份运行该工具,如下所示

复制
已复制!
            

$ sudo /opt/mellanox/doca/tools/doca_caps -p <pci-address> -b devemu_pci Example output: PCI: 0000:03:00.0 devemu_pci max_hotplug_devices 15 max_pci_types 2 mmap_add_dev_supported supported        type_log_min_bar_size 12 type_log_max_bar_size 30 type_max_num_msix 11 type_max_num_db 64 type_log_min_db_size 1 type_log_max_db_size 2 type_log_min_db_stride_size 2 type_log_max_db_stride_size 12 type_max_bars 2 bar_max_bar_regions 12 type_max_bar_regions 12 bar_db_region_identify_by_offset supported bar_db_region_identify_by_data supported bar_db_region_block_size 4096 bar_db_region_max_num_region_blocks 16 type_max_bar_db_regions 2 bar_max_bar_db_regions 2 bar_db_region_start_addr_alignment 4096 bar_stateful_region_block_size 64 bar_stateful_region_max_num_region_blocks 4 type_max_bar_stateful_regions 1 bar_max_bar_stateful_regions 1 bar_stateful_region_start_addr_alignment 64 bar_msix_table_region_block_size 4096 bar_msix_table_region_max_num_region_blocks 1 type_max_bar_msix_table_regions 1 bar_max_bar_msix_table_regions 1 bar_msix_table_region_start_addr_alignment 4096 bar_msix_pba_region_block_size 4096 bar_msix_pba_region_max_num_region_blocks 1 type_max_bar_msix_pba_regions 1 bar_max_bar_msix_pba_regions 1 bar_msix_pba_region_start_addr_alignment 4096 bar_is_32_bit_supported unsupported bar_is_1_mb_supported unsupported bar_is_64_bit_supported supported pci_type_hotplug supported pci_type_mgmt supported

配置

本节介绍可以在启动之前提供的 DOCA DevEmu PCI Type 对象的配置。

要查找是否支持某个配置或其最小/最大值是多少,请参阅 设备支持

强制配置

以下是强制配置,必须在启动 PCI 类型之前提供

  • 作为模拟管理器或热插拔管理器的 DOCA 设备。请参阅 设备支持

可选配置

以下配置是可选的

  • PCIe 设备 ID

  • PCIe 供应商 ID

  • PCIe 子系统 ID

  • PCIe 子系统供应商 ID

  • PCIe 修订 ID

  • PCIe 类代码

  • MSI-X 功能的 MSI-X 向量数

  • 一个或多个内存映射 BAR

  • 一个或多个 I/O 映射 BAR

  • 一个或多个 DB 区域

  • MSI-X 表和 PBA 区域

  • 一个或多个有状态区域

信息

如果未设置这些配置,则使用默认值。

配置阶段

本节介绍额外的配置选项,除了 DOCA DevEmu PCI 设备配置阶段 中已描述的选项之外。

配置

可以配置上下文以匹配应用程序的用例。

要查找是否支持某个配置或其最小/最大值是多少,请参阅 设备支持

可选配置

以下配置是可选的

  • 设置有状态区域的默认值 – 如果未设置,则使用类型默认值。有关更多信息,请参阅 有状态区域默认值

执行阶段

本节介绍额外的事件,除了 DOCA DevEmu PCI 设备事件 中已描述的事件之外。

事件

DOCA DevEmu PCI Device 公开异步事件,以根据 DOCA Core 架构通知突然发生的更改。

常见事件在 DOCA Core Event 中描述。

BAR 有状态区域驱动程序写入

有状态区域驱动程序写入事件允许您在主机驱动程序写入有状态 BAR 区域时接收通知。有关更多信息,请参阅“驱动程序写入”部分。

配置

描述

设置配置的 API

查询支持的 API

注册事件

doca_devemu_pci_dev_event_bar_stateful_region_driver_write_register

doca_devemu_pci_cap_type_get_max_bar_stateful_regions

如果同一设备有多个有状态区域,则每个区域单独完成注册。注册时提供的详细信息(即,bar_id 和起始地址)必须与先前为 PCIe 类型配置的区域匹配。

触发条件

每当主机驱动程序写入有状态区域时,都会触发该事件。有关更多信息,请参阅“驱动程序写入”部分。

输出

常见输出如 DOCA Core Event 中所述。

此外,事件回调接收类型为 struct doca_devemu_pci_dev_event_bar_stateful_region_driver_write 的事件对象,该对象可用于检索

  • 表示触发事件的模拟设备的 DOCA DevEmu PCI Device – doca_devemu_pci_dev_event_bar_stateful_region_driver_write_get_pci_dev

  • 包含有状态区域的 BAR 的 ID – doca_devemu_pci_dev_event_bar_stateful_region_driver_write_get_bar_id

  • 有状态区域的起始地址 – doca_devemu_pci_dev_event_bar_stateful_region_driver_write_get_bar_region_start_addr

事件处理

一旦触发事件,就意味着主机驱动程序已写入到区域中的某个位置。

用户必须执行以下任一操作

  • 查询有状态区域的新值 – doca_devemu_pci_dev_query_bar_stateful_region_values

  • 修改有状态区域的值 – doca_devemu_pci_dev_modify_bar_stateful_region_values

也可以两者都做。但是,重要的是,主机写入的内存区域要么被查询,要么被修改操作覆盖。

注意

否则会导致重复事件。例如,如果主机写入了区域的前半部分,但 BlueField Arm 在收到事件后仅查询了区域的后半部分。然后,如果用户未处理该事件,则库会重新触发该事件。

创建 PCIe 设备后,可以使用它来创建 DB 对象。每个 DB 对象代表一个由 DB ID 标识的 DB 资源。请参阅通用数据路径 (DB BAR 区域)

创建 DB 时,必须提供 DB ID。对于按偏移量 DB按数据 DB,DB ID 的含义可能不同。然后,DB 对象可用于在驱动程序写入时获取 DPA 的通知,并使用 DPA 获取最新值。

配置

创建和配置 DB

创建和配置 DB 的流程应如下所示:

  1. 创建 DB 对象

    复制
    已复制!
                

    arm> doca_devemu_pci_db_create_on_dpa

  2. (可选)查询 DB 值

    复制
    已复制!
                

    arm> doca_devemu_pci_db_query_value

  3. (可选)修改 DB 值

    复制
    已复制!
                

    arm> doca_devemu_pci_db_modify_value

  4. 获取 DB DPA 句柄,以便从 DPA 引用 DB

    复制
    已复制!
                

    arm> doca_devemu_pci_db_get_dpa_handle

  5. 使用上一步中的句柄将 DB 绑定到 DB 完成上下文

    复制
    已复制!
                

    dpa> doca_dpa_dev_devemu_pci_db_completion_bind_db

    警告

    在执行下一步之前,务必执行此步骤。否则,DB 完成上下文将开始接收未绑定 DB 的完成。

  6. 启动 DB 以开始接收 DPA 上的完成

    复制
    已复制!
                

    arm> doca_devemu_pci_db_start

    信息

    DB 启动后,会在 DPA 上立即生成完成。

销毁 DB

销毁 DB 的流程如下所示:

  1. 停止 DB 以停止接收完成

    复制
    已复制!
                

    arm> doca_devemu_pci_db_stop

    信息

    此步骤确保不会为此 DB 收到其他完成

  2. 确认与此 DB 相关的所有完成

    复制
    已复制!
                

    dpa> doca_dpa_dev_devemu_pci_db_completion_ack

    信息

    此步骤确保已处理现有完成。

  3. 从 DB 完成上下文中解绑 DB

    复制
    已复制!
                

    dpa> doca_dpa_dev_devemu_pci_db_completion_unbind_db

    警告

    确保此步骤的执行次数不超过一次。

  4. 销毁 DB 对象

    复制
    已复制!
                

    arm> doca_devemu_pci_db_destroy

在 DPA 上获取 DB

要从 DPA 获取 DB,可以使用 DB 完成上下文。DB 完成上下文用于以下目的:

  • 通知 DPA 线程 DB 值已更新(唤醒线程)

  • 提供有关哪个 DB 已更新的信息

以下流程展示了如何使用相同的 DB 完成上下文,以便在任何 DB 更新时收到通知,并查找实际更新了哪些 DB,最后获取 DB 的值

  1. 获取 DB 完成元素

    复制
    已复制!
                

    doca_dpa_dev_devemu_pci_get_db_completion 

  2. 从完成中获取 DB

    复制
    已复制!
                

    doca_dpa_dev_devemu_pci_db_completion_element_get_db_properties

  3. 存储 DB(例如,在数组中)。

  4. 重复步骤 1-3,直到没有更多完成。

  5. 确认收到的完成数量

    复制
    已复制!
                

    doca_dpa_dev_devemu_pci_db_completion_ack 

  6. 请求 DPA 上关于下一个完成的通知

    复制
    已复制!
                

    doca_dpa_dev_devemu_pci_db_completion_request_notification

  7. 遍历步骤 3 中存储的 DB,并针对每个 DB 执行以下操作

    1. 请求在主机驱动程序下次写入此 DB 时发出通知

      复制
      已复制!
                  

      doca_dpa_dev_devemu_pci_db_request_notification

    2. 获取 DB 的最新值

      复制
      已复制!
                  

      doca_dpa_dev_devemu_pci_db_get_value

从 Arm 查询/修改 DB

可以使用 Arm 上的 doca_devemu_pci_db_query_value 查询特定 DB 的 DB 值。同样,可以使用 doca_devemu_pci_db_modify_value 修改 DB 值。修改 DB 值时,此类修改的副作用与主机驱动程序更新 DB 值时的副作用相同。

提示

从 Arm 进行查询和修改操作非常耗时,应仅在控制路径中使用。建议使用在 DPA 上获取 DB 的方法来检索数据路径中的 DB 值。


创建 PCIe 设备后,可以使用它来创建 MSI-X 对象。每个 MSI-X 对象代表一个由向量索引标识的 MSI-X 向量。

MSI-X 对象可用于从 DPA 向主机驱动程序发送通知。

配置

可以使用 doca_devemu_pci_msix_create_on_dpa 创建 MSI-X 对象。创建期间必须提供 MSI-X 向量索引,该值范围为 [0, num_msix),其中 num_msix 是先前使用 doca_devemu_pci_type_set_num_msix 设置的值。

创建 MSI-X 对象后,可以使用 doca_devemu_pci_msix_get_dpa_handle 获取 DPA 句柄,以便在 DPA 中使用。

触发 MSI-X

MSI-X 对象可在 DPA 上用于使用 doca_dpa_dev_devemu_pci_msix_raise 引发 MSI-X 向量。

本节介绍 DOCA DevEmu Generic 示例。

这些示例说明了如何使用 DOCA DevEmu Generic API 执行以下操作:

  • 列出具有相同通用类型的模拟设备的详细信息

  • 创建和热插拔/热移除具有通用类型的模拟设备

  • 使用有状态区域处理主机驱动程序写入

  • 使用 DB 区域处理主机驱动程序写入

  • 向主机驱动程序引发 MSI-X

  • 执行 DMA 操作以在主机驱动程序和 DPU Arm 之间复制内存缓冲区

结构

所有示例都使用相同的通用 PCI 类型。类型的配置位于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h

一些示例的结构如下:

  • /opt/mellanox/doca/samples/doca_devemu/<示例目录>

    1. dpu

      1. host

      2. device

    2. host

遵循此结构的示例将具有两个二进制文件:dpu (1) 和 host (2)。前者应在 BlueField 上运行,表示模拟设备的控制器,而后者应在主机上运行,表示主机驱动程序。

为简单起见,主机 (2) 端基于 VFIO 驱动程序,允许在用户空间中开发驱动程序。

dpu (a) 目录中,有 host (a) 和 device (b) 目录。在这种情况下,host 指的是 BlueField Arm 处理器,而 device 指的是 DPA 处理器。这两个目录都编译成单个二进制文件。

运行示例

  1. 请参阅以下文档:

  2. 要构建给定的示例:

    复制
    已复制!
                

    cd /opt/mellanox/doca/samples/doca_devemu/<sample_name>[/dpu or /host] meson /tmp/build ninja -C /tmp/build

    信息

    二进制文件 doca_<示例名称>[_dpu 或 _host]/tmp/build/ 下创建。

  3. 示例(例如,doca_devemu_pci_device_db)用法

    1. BlueField 端 (doca_devemu_pci_device_db_dpu)

      复制
      已复制!
                  

      Usage: doca_devemu_pci_device_db_dpu [DOCA Flags] [Program Flags]   DOCA Flags: -h, --help Print a help synopsis -v, --version Print program version information -l, --log-level Set the (numeric) log level for the program <10=DISABLE, 20=CRITICAL, 30=ERROR, 40=WARNING, 50=INFO, 60=DEBUG, 70=TRACE> --sdk-log-level Set the SDK (numeric) log level for the program <10=DISABLE, 20=CRITICAL, 30=ERROR, 40=WARNING, 50=INFO, 60=DEBUG, 70=TRACE> -j, --json <path> Parse all command flags from an input json file   Program Flags: -p, --pci-addr The DOCA device PCI address. Format: XXXX:XX:XX.X or XX:XX.X -u, --vuid DOCA Devemu emulated device VUID. Sample will use this device to handle Doorbells from Host -r, --region-index The index of the DB region as defined in devemu_pci_type_config.h. Integer -i, --db-id The DB ID of the DB. Sample will listen on DBs related to this DB ID. Integer

    2. 主机端 (doca_devemu_pci_device_db_host)

      复制
      已复制!
                  

      Usage: doca_devemu_pci_device_db_host [DOCA Flags] [Program Flags]   DOCA Flags: -h, --help Print a help synopsis -v, --version Print program version information -l, --log-level Set the (numeric) log level for the program <10=DISABLE, 20=CRITICAL, 30=ERROR, 40=WARNING, 50=INFO, 60=DEBUG, 70=TRACE> --sdk-log-level Set the SDK (numeric) log level for the program <10=DISABLE, 20=CRITICAL, 30=ERROR, 40=WARNING, 50=INFO, 60=DEBUG, 70=TRACE> -j, --json <path> Parse all command flags from an input json file   Program Flags: -p, --pci-addr PCI address of the emulated device. Format: XXXX:XX:XX.X -g, --vfio-group VFIO group ID of the device. Integer -r, --region-index The index of the DB region as defined in devemu_pci_type_config.h. Integer -d, --db-index The index of the Doorbell to write to. The sample will write at byte offset (db-index * db-stride) -w, --db-value A 4B value to write to the Doorbell. Will be written in Big Endian

  4. 有关每个示例的更多信息,请使用 -h 选项

    复制
    已复制!
                

    /tmp/build/<sample_name> -h

其他示例设置

  • BlueField 示例要求模拟设备已热插拔

    • 此类示例需要热插拔设备的 VUID (-u, --vuid)

    • 列表示例可用于查找是否存在任何热插拔设备及其 VUID

    • 如果不存在此类设备,则热插拔示例可用于热插拔设备

  • 主机示例要求模拟设备已热插拔,并且该设备已绑定到 VFIO 驱动程序

    • 这些示例需要 2 个参数 -p (--pci-addr) 和 -g (--vfio-group),它们是主机看到的模拟设备的参数

    • PCI 设备列表示例可从 BlueField 用于查找主机上模拟设备的 PCIe 地址

    • 找到 PCIe 地址后,主机可以使用脚本 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_vfio_bind.py 绑定 VFIO 驱动程序

      复制
      已复制!
                  

      $ sudo python3 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_vfio_bind.py <pcie-address-of-emulated-dev>

      • 该脚本是一个 python3 脚本,它需要模拟设备的 PCIe 地址作为位置参数(例如,0000:3e:00.0

      • 该脚本输出 VFIO 组 ID

      • 仅当设备首次热插拔到主机后,才必须使用该脚本一次

  • 热移除示例要求设备从 VFIO 驱动程序解绑

    • 使用位于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_vfio_bind.py 的脚本从主机解绑 VFIO 驱动程序,如下所示:

      复制
      已复制!
                  

      $ sudo python3 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_vfio_bind.py <pcie-address-of-emulated-dev> --unbind

      • 此 python3 脚本需要模拟设备的 PCIe 地址作为位置参数(例如,0000:3e:00.0)以及 --unbind 参数

示例

PCI 设备列表

此示例说明了如何列出在 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 中配置了通用类型的所有模拟设备。

示例逻辑包括:

  1. 基于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 初始化通用 PCIe 类型。

  2. 创建属于此类型的所有模拟设备的列表。

  3. 遍历模拟设备。

  4. 转储其 VUID。

  5. 转储主机看到的其 PCIe 地址。

  6. 释放资源。

参考资料

  • /opt/mellanox/doca/samples/doca_devemu/

    • devemu_pci_device_list/

      • devemu_pci_device_list_sample.c

      • devemu_pci_device_list_main.c

      • meson.build

    • devemu_pci_common.hdevemu_pci_common.c

    • devemu_pci_type_config.h

PCI 设备热插拔

此示例说明了如何创建和热插拔/热移除在 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 中配置了通用类型的模拟设备。

示例逻辑包括:

  1. 基于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 初始化通用 PCIe 类型。

  2. 获取模拟设备表示符

    • 如果用户未提供 VUID 作为输入,则创建和使用新的模拟设备。

    • 如果用户提供了 VUID 作为输入,则搜索具有匹配 VUID 的现有模拟设备并使用它。

  3. 创建 PCIe 设备上下文以管理模拟设备,并将其连接到进度引擎 (PE)。

  4. 注册到 PCIe 设备的热插拔状态更改事件。

  5. 初始化设备的热插拔/热移除

    1. 如果用户未提供 VUID 作为输入,则初始化设备的热插拔流程。

    2. 如果用户提供了 VUID 作为输入,则初始化设备的热移除流程。

  6. 使用 PE 轮询热插拔状态更改事件。

  7. 等待热插拔状态转换为预期状态(开机或关机)。

  8. 清理资源。

    • 如果请求了热移除,则也会销毁模拟设备。

    • 否则,模拟设备将保持存在。

参考资料

  • /opt/mellanox/doca/samples/doca_devemu/

    • devemu_pci_device_hotplug/

      • devemu_pci_device_hotplug_sample.c

      • devemu_pci_device_hotplug_main.c

      • meson.build

    • devemu_pci_common.hdevemu_pci_common.c

    • devemu_pci_type_config.h

PCI 设备有状态区域

此示例说明了主机驱动程序如何写入有状态区域,以及 BlueField Arm 如何处理写入操作。

此示例包含主机示例和 BlueField 示例。有必要遵循先前详细介绍的其他示例设置

BlueField 示例逻辑包括:

  1. 基于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 初始化通用 PCIe 类型。

  2. 获取与提供的 VUID 匹配的模拟设备表示符。

  3. 创建 PCIe 设备上下文以管理模拟设备,并将其连接到进度引擎 (PE)。

  4. 对于在 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 中配置的每个有状态区域,注册到 PCIe 设备的有状态区域写入事件。

  5. 使用 PE 轮询驱动程序对任何有状态区域的写入。

    • 每次主机驱动程序写入有状态区域时,都会调用处理程序并执行以下操作:

      1. 查询主机写入的有状态区域的值。

      2. 记录有状态区域的值。

    • 示例无限期轮询,直到用户按下 [Ctrl+c] 关闭示例。

  6. 清理资源。

主机示例逻辑包括:

  1. 使用匹配的 PCIe 地址和 VFIO 组初始化 VFIO 设备。

  2. 将有状态内存区域从 BAR 映射到进程地址空间。

  3. 将作为输入提供的值写入有状态区域的开头。

参考资料

  • /opt/mellanox/doca/samples/doca_devemu/

    • devemu_pci_device_stateful_region/dpu/

      • devemu_pci_device_stateful_region_dpu_sample.c

      • devemu_pci_device_stateful_region_dpu_main.c

      • meson.build

    • devemu_pci_device_stateful_region/host/

      • devemu_pci_device_stateful_region_host_sample.c

      • devemu_pci_device_stateful_region_host_main.c

      • meson.build

    • devemu_pci_common.hdevemu_pci_common.c

    • devemu_pci_host_common.hdevemu_pci_host_common.c

    • devemu_pci_type_config.h

PCI 设备 DB

此示例说明了主机驱动程序如何响铃门铃,以及 BlueField 如何检索门铃值。该示例还演示了如何处理 FLR。

此示例包含主机示例和 BlueField 示例。有必要遵循先前详细介绍的其他示例设置

BlueField 示例逻辑包括:

  • 主机 (BlueField Arm) 逻辑

    1. 基于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 初始化通用 PCIe 类型。

    2. 初始化 DPA 资源

      1. 创建 DPA 实例并将其与 DPA 应用程序关联。

      2. 创建 DPA 线程并将其与 DPA DB 处理程序关联。

      3. 创建 DB 完成上下文并将其与 DPA 线程关联。

    3. 获取与提供的 VUID 匹配的模拟设备表示符。

    4. 创建 PCIe 设备上下文以管理模拟设备,并将其连接到进度引擎 (PE)。

    5. 注册到上下文状态更改事件。

    6. 注册到 PCIe 设备 FLR 事件。

    7. 使用 PE 轮询以下任何一项:

      1. 每次 PCIe 设备上下文状态转换为运行状态时,处理程序执行以下操作:

        1. 创建 DB 对象。

        2. 向 DPA 发出 RPC,以初始化 DB 对象。

      2. 每次 PCIe 设备上下文状态转换为停止状态时,处理程序执行以下操作:

        1. 向 DPA 发出 RPC,以取消初始化 DB 对象。

        2. 销毁 DB 对象。

      3. 每次主机驱动程序初始化或销毁 VFIO 设备时,都会触发 FLR 事件。FLR 处理程序执行以下操作:

        1. 销毁 DB 对象。

        2. 停止 PCIe 设备上下文。

        3. 再次启动 PCIe 设备上下文。

      4. 示例无限期轮询,直到用户按下 [Ctrl+c] 关闭示例。

        注意

        在此期间,DPA 可能会开始接收来自主机的 DB。

    8. 清理资源。

  • 设备 (BlueField DPA) 逻辑

    1. 初始化应用程序 RPC

      1. 将全局上下文设置为指向 DB 完成上下文 DPA 句柄。

      2. 将 DB 绑定到门铃完成上下文。

    2. 取消初始化应用程序 RPC

      1. 从门铃完成上下文中解绑 DB。

    3. DB 处理程序

      1. 从完成上下文中获取 DB 完成元素。

      2. 从 DB 完成元素中获取 DB 句柄。

      3. 确认 DB 完成元素。

      4. 从 DB 完成上下文请求通知。

      5. 从 DB 请求通知。

      6. 从 DB 获取 DB 值。

主机示例逻辑包括:

  1. 初始化 VFIO 设备及其匹配的 PCIe 地址和 VFIO 组。

  2. 将 DB 内存区域从 BAR 映射到进程地址空间。

  3. 将作为输入提供的值写入给定偏移量处的 DB 区域。

参考资料

  • /opt/mellanox/doca/samples/doca_devemu/

    • devemu_pci_device_db/dpu/

      • host/

        • devemu_pci_device_db_dpu_sample.c

      • device/

        • devemu_pci_device_db_dpu_kernels_dev.c

      • devemu_pci_device_db_dpu_main.c

      • meson.build

    • devemu_pci_device_db/host/

      • devemu_pci_device_db_host_sample.c

      • devemu_pci_device_db_host_main.c

      • meson.build

    • devemu_pci_common.hdevemu_pci_common.c

    • devemu_pci_host_common.hdevemu_pci_host_common.c

    • devemu_pci_type_config.h

PCI 设备 MSI-X

此示例说明了 BlueField 如何引发 MSI-X 向量,向主机发送信号,并展示了主机如何检索此信号。

此示例包含主机示例和 BlueField 示例。有必要遵循先前详细介绍的其他示例设置

BlueField 示例逻辑包括:

  • 主机 (BlueField Arm) 逻辑

    1. 基于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 初始化通用 PCIe 类型。

    2. 初始化 DPA 资源

      1. 创建 DPA 实例并将其与 DPA 应用程序关联。

      2. 创建 DPA 线程并将其与 DPA DB 处理程序关联。

    3. 获取与提供的 VUID 匹配的模拟设备表示符。

    4. 创建 PCIe 设备上下文以管理模拟设备,并将其连接到进度引擎 (PE)。

    5. 创建 MSI-X 向量并获取其 DPA 句柄。

    6. 向 DPA 发送 RPC 以引发 MSI-X 向量。

    7. 清理资源。

  • 设备 (BlueField DPA) 逻辑

    1. 通过使用 MSI-X 向量句柄引发 MSI-X RPC。

主机示例逻辑包括:

  1. 使用匹配的 PCIe 地址和 VFIO 组初始化 VFIO 设备。

  2. 将每个 MSI-X 向量映射到不同的 FD。

  3. 在循环中从 FD 读取事件。

    1. 一旦 DPU 引发 MSI-X,与 MSI-X 向量匹配的 FD 将返回一个事件,然后该事件将打印到屏幕。

    2. 示例无限期轮询 FD,直到用户按下 [Ctrl+c] 关闭示例。

参考资料

  • /opt/mellanox/doca/samples/doca_devemu/

    • devemu_pci_device_msix/dpu/

      • host/

        • devemu_pci_device_msix_dpu_sample.c

      • device/

        • devemu_pci_device_msix_dpu_kernels_dev.c

      • devemu_pci_device_msix_dpu_main.c

      • meson.build

    • devemu_pci_device_msix/host/

      • devemu_pci_device_msix_host_sample.c

      • devemu_pci_device_msix_host_main.c

      • meson.build

    • devemu_pci_common.hdevemu_pci_common.c

    • devemu_pci_host_common.hdevemu_pci_host_common.c

    • devemu_pci_type_config.h

PCI 设备 DMA

此示例说明了主机驱动程序如何设置 DMA 内存,然后 DPU 可以使用该内存将字符串从 BlueField 复制到主机,以及从主机复制到 BlueField。

此示例包含主机示例和 BlueField 示例。有必要遵循先前详细介绍的其他示例设置

BlueField 示例逻辑包括:

  1. 基于 /opt/mellanox/doca/samples/doca_devemu/devemu_pci_type_config.h 初始化通用 PCIe 类型。

  2. 获取与提供的 VUID 匹配的模拟设备表示符。

  3. 创建 PCIe 设备上下文以管理模拟设备,并将其连接到进度引擎 (PE)。

  4. 创建 DMA 上下文以用于跨主机和 BlueField 复制内存。

  5. 设置表示主机驱动程序内存缓冲区的 mmap。

  6. 设置表示本地内存缓冲区的 mmap。

  7. 使用 DMA 上下文将内存从主机复制到 BlueField。

  8. 使用 DMA 上下文将内存从 BlueField 复制到主机。

  9. 清理资源。

主机示例逻辑包括:

  1. 使用匹配的 PCIe 地址和 VFIO 组初始化 VFIO 设备。

  2. 分配内存缓冲区。

  3. 将内存缓冲区映射到 I/O 内存。现在,BlueField 可以通过 DMA 使用 I/O 地址访问内存。

  4. 将用户提供的字符串复制到内存缓冲区。

  5. 等待 BlueField 写入内存缓冲区。

  6. 取消映射内存缓冲区。

  7. 清理资源。

参考资料

  • /opt/mellanox/doca/samples/doca_devemu/

    • devemu_pci_device_dma/dpu/

      • devemu_pci_device_dma_dpu_sample.c

      • devemu_pci_device_dma_dpu_main.c

      • meson.build

    • devemu_pci_device_dma/host/

      • devemu_pci_device_dma_host_sample.c

      • devemu_pci_device_dma_host_main.c

      • meson.build

© 版权所有 2025 NVIDIA。 上次更新时间:2025 年 2 月 12 日。