> For the complete documentation index, see [llms.txt](https://freebsd-journal-cn.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://freebsd-journal-cn.bsdcn.org/2016-0506-armv8/freebsd-on-cavium-thunderx-system-on-a-chip.md).

# FreeBSD 在 Cavium ThunderX 片上系统上的运行

* 原文：[FreeBSD on Cavium ThunderX System on a Chip](https://freebsdfoundation.org/wp-content/uploads/2016/06/FreeBSD-on-Cavium-ThunderZ-System-on-a-Chip.pdf)
* 作者：**Zbigniew Bodek** 和 **Wojciech Macek**

本文描述 FreeBSD 操作系统向 Cavium ThunderX CN88XX 片上系统（SoC）的移植工作。ThunderX 是新推出的 ARM64（ARMv8）SoC，面向高性能和服务器市场。在 ARM 阵营中，目前只有它能将多达 96 个 CPU 核心集成到系统中，并拥有使其成为现实的技术。

ThunderX 紧跟计算机架构产业的最新趋势，包括对 FreeBSD 而言较新的技术（如 SRIOV，即单根 I/O 虚拟化），以及完全独有的技术（如 ARM GICv3 和 ITS）。

本文重点自底向上地介绍 ThunderX 的 FreeBSD 平台支持是如何实现的，并描述新引入的 ARMv8 技术在操作系统开发方面的优势与陷阱。文章还描述 ThunderX 系统的关键组件，并解释它们在 FreeBSD 中的支持方式。最后简要指出未来可改进的方向。

## 引言

FreeBSD 无疑是最广为人知的类 Unix 操作系统。其主要部署领域之一是服务器市场，目前仍由 Intel 和 AMD 架构的计算机主导。然而，近年来在移动产业大获成功的 ARM 架构，正作为高性能服务器 SoC 的基础受到关注。该领域的转折点是 64 位 ARM 实现（ARMv8）的出现，它包含改进的技术以实现惊人的多核能力。因此，对 FreeBSD 社区（开发者和用户）而言，紧跟基于 ARM 的服务器日益增长的趋势，并为生态系统提供与现有 Tier 1 x86 平台相当的 ARM64 BSD 操作系统，这一点至关重要。

推动 ThunderX 工作的动力来自市场对该平台上 FreeBSD 操作系统的实际需求，目标是成为高能耗方案的真正替代品。ThunderX 也是世界上唯一能将单插槽核心数扩展至 48 个的基于 ARM 的芯片，并支持双插槽配置（最多 96 个 CPU）。凭借内置的网络、存储和安全硬件加速器，以及强大的外设，ThunderX 是 FreeBSD 这类面向服务器的操作系统的理想基础，对内核开发者而言也是一项重大的工程挑战。

此处介绍的支持基于基础工作，以模拟器为主要目标（ARM Foundation Model）。因此 ThunderX 的平台支持部分与 FreeBSD 基本系统的开发并行进行，偶尔相互交织。ThunderX 也是首个从 ARM 模拟器切换到真实硬件的平台。最终结果是功能完整的操作系统，支持以下关键芯片特性：

* PCI Express
* GICv3 + ITS
* SMP（单插槽和双插槽）
* SATA
* 虚拟化网络接口

ARMv8 架构的 FreeBSD 内核通用实现不在本文范围内，仅在涉及 ThunderX 支持工作时才加以讨论。

## 硬件概览

当代基于 ARM 的芯片紧跟计算机产业的潮流，集成多处理器能力、高性能外设、总线和扩展，以及各种硬件加速器和虚拟化技术。第 8 代架构（ARMv8）通过突破以往的架构限制将这些概念提升到新高度。ThunderX 是新一代 ARM 芯片的典型代表，率先利用了大部分新引入的特性。

上述步骤大多已在 FreeBSD 中实现，因为此前已投入大量工作使其在 Qemu 和 ARM Foundation Model 上运行。然而，真实硬件仍是巨大的未探索领域。现有代码为 ThunderX 支持提供了良好的起点。开发中缺失的部分主要涉及：

* 系统引导
* 中断处理
* PCI-express
* 复杂的网络控制器
* 48/96 个 CPU 核心的 SMP 操作

每个真实硬件设备都有自己的怪癖、假设，最重要的是定制的固件。尽管 ThunderX 是符合 ARMv8 规范的平台，实际上是定制的 ARM 实现，需要比在 Qemu 和 ARM 模拟器上测试的通用 Cortex-A53/A57 更多的关注。

### 核心复合体与 CCPI

CN88XX SoC 的核心是一组 Cavium 自有的、符合 ARMv8 规范的 CPU。每个 CPU 拥有自己的 I-cache 和 D-cache，但共享 16MB L2 缓存。单个封装可容纳多达 48 个 CPU，组织为三个集群，每个集群 16 个 CPU。核心复合体可通过 Cavium 一致性处理器互联 fabric（CCPI）连接到另一个 CN88XX 处理器。系统中所有 CPU 在 L1、L2 缓存和 DMA 访问方面保持缓存一致性。系统一致性能力也扩展到通过 CCPI 连接的实体。因此，双插槽配置产生一个包含 96 个 ThunderX CPU 的完全一致系统。潜在的多插槽配置可包含四个节点，CPU 总数达 192 个 \[1]。

## 移植

将 FreeBSD 操作系统移植到新平台的工作通常可划分为几个通用阶段：

1. 工具链和构建环境支持。
2. 内核加载和引导。**locore.S** 和低层操作。内核启动代码和低层机器初始化，以及基本缓存维护、原子操作、同步原语等。
3. 基本系统操作。包括 **pmap.c** 中的虚拟内存管理、异常处理、上下文切换、中断，以及系统定时器和控制台支持。
4. 外设驱动。
5. 用户空间支持。

大量 CPU 核心和外设，以及以 PCI 为中心的架构，要求采用全新的中断信号传递方式，并对通用 ARM64 代码和 ThunderX 专用代码进行多处修改。

### 系统引导

典型的 CN88XX 启动场景从片上 Boot ROM 开始。这一阶段从 SPI 连接的 FLASH 加载 Boot 级 1 固件（BL1），随后加载 BL2 和 BL3 固件，最终系统控制权交给 Cavium 统一可扩展固件接口（UEFI）引导加载器。此时 ThunderX 系统及其接口完成初始化，启动 CPU 核心处于 EL2 异常级别（Hypervisor）。为运行 FreeBSD，ThunderX 需要加载内核 ELF 文件，并向其提供机器描述（如 DTB，设备树 Blob）、可用内存区域，以及内核在 DRAM 中的位置等信息。因此 FreeBSD 启动流程的下一步是原生 BSD **loader(8)**，它在 UEFI 运行时环境中执行。**loader(8)** 负责获取内核并跳转到其代码。ThunderX 使用真正的 ARM64 **loader(8)**，几乎不需要修改。

### 早期系统初始化

最先执行的内核代码是 **locore.S** 中的代码。它完成三个基本动作：

1. 将 CPU 置于明确的状态。
2. 为 C 代码准备执行环境。
3. 转发从引导加载器获取的模块信息。

ARMv8 处理器（处于 AArch64 状态）在最多四个异常级别之一运行：EL0-EL3，其中 EL0 拥有最低的软件执行特权，对应用户模式；EL1 可称为内核模式，EL2 是 Hypervisor，EL3 用于 ARM 的 TrustZone 安全监视模式 \[3]。启动代码通常将异常级别降至 EL1（在执行 EL2 专用配置之后）。此时创建初始映射和恒等（1:1）内核映射，以便在内存管理单元启用时将上下文切换到内核虚拟地址空间。在此之前，所有与地址转换、缓存和初始系统行为（如异常接收）相关的设置都已应用。最后，配置内核栈，CPU 跳转到 C 代码中的早期机器初始化。

ThunderX 在此阶段比 ARM Foundation Model 需要更多设置，包括：

* 允许 EL1 访问通用中断控制器的 CPU 接口。默认情况下，无法通过系统寄存器从 EL1 访问 CPU 接口。访问权限必须在仍处于 EL2 时授予。
* 扩大 TCR\_EL1 中的虚拟地址空间。在 ThunderX 的某些变体上，物理内存映射超过 512GB。因此，如果设定的地址空间不够大，将无法创建从物理地址空间跳转到虚拟地址空间所需的恒等映射。

不过，这些修改并非严格意义上的 ThunderX 专用，将适用于任何有类似需求的平台。

## 中断传递

旨在向 CPU 指示某个动作发生的异常称为中断。没有中断支持就没有合理的多线程操作系统；因此，中断是系统最基本的元素之一。前几代 ARM 处理器通常集成所谓的 ARM 通用中断控制器（GIC）或其他专有实现。

典型的 ARM GIC 由两个主要组件组成：分发器和 CPU 接口。通常，片上设备的中断线连接到分发器接口，分发器根据自身配置将中断信号路由到相应的 CPU 接口。如果中断信号已启用，CPU 将在相应的中断线（IRQ 或 FIQ）上收到通知。最后，CPU 可从 CPU 接口寄存器获取中断信息（如中断号），并改变中断的挂起状态。这种架构对 ARMv6/v7 处理器运作良好，但在以下方面存在严重限制：

* 可扩展性。最多只能将中断路由到 8 个 CPU 核心。
* 最大中断数。每个中断都需要与分发器的物理连接。
* 不支持消息信号中断。无法使用带内 PCI 中断信号。
* CPU 接口寄存器访问缓慢。每个中断至少需要几次对内存映射寄存器的读/写序列（设备内存访问缓慢，且可能出现 TLB 未命中）。

### 通用中断控制器 v3

ThunderX 这类平台需要改进的中断处理，以提供更好的 SMP 利用率、支持 PCIe 设备，并将每个中断的时间开销降至最低。这些特性随 ARM 通用中断控制器 v3 \[2] 配合中断翻译服务（ITS）引入。所贡献的工作包括 FreeBSD 对 ARM GICv3 和 ITS 的完整支持，以及 ThunderX 专用的怪癖处理，但不包括虚拟化扩展。

#### 基于亲和性的路由

与早期 GIC 架构不同，GICv3 引入了第三个额外组件——重分发器，这是与系统中每个 CPU 关联的内存映射实体。此外，CPU 接口现在可通过 CPU 的系统寄存器访问，以加速核心收到通知后的中断处理。为突破中断到 CPU 的传递限制，中断现在基于亲和性层级路由。这意味着中断目的地现在由系统中 4 级 CPU 亲和性编号寻址。GICv3 驱动在全局分发器中配置所有 SPI（共享外设中断），但 PPI（私有外设中断）、SGI（软件生成中断）和新的 LPI（本地外设中断）类通过每 CPU 的重分发器管理。每个重分发器在使用前需要启用或唤醒。幸运的是，GICv3 提供自动配置机制，允许操作系统驱动遍历设备的内存映射区域，将配置器 CPU 匹配到正确的重分发器（基于亲和性），并执行相应操作。配置完成后，重分发器接口可像全局分发器一样使用。

处理器间中断（IPI）也可基于 CPU 亲和性层级传递。由于 FreeBSD 内核在 SMP 中不按硬件亲和性枚举 CPU，每次 IPI 都需要保存并将每个 CPU 地址与请求的 CPU 组匹配。软件生成中断（通过写入 CPU 接口寄存器触发）用于执行 IPI 交换。

#### ITS 与消息信号中断

在典型场景中，外设向分发器请求中断，分发器再将其转发到相应的重分发器。最后，中断信号传递到 CPU 接口。GICv3 中重分发器所用的另一种行为是绕过分发器的中断路由。这用于 MSI，需要中断翻译服务（ITS）协助。ITS 是 GICv3 的扩展，管理任何能发送消息信号中断的设备所生成的 LPI 的路由和迁移。ITS 控制器采用的独特方式是，所有支持 MSI 的设备都可使用单个内存位置（GITS\_TRANSLATER 寄存器地址）来生成中断。中断请求号和相应的路由根据中断设备的标识符和编程到 ITS 中的翻译信息推导。中断控制器与 PCIe 总线和 IOMMU 密切协作，因为中断翻译过程中使用的唯一设备 ID 在总线事务本身中传递。ITS 的编程通过向特殊命令队列发送命令完成，需要建立 PCI 端点、LPI 编号（即中断集合）和目标重分发器之间的关系。

FreeBSD 对 ITS 的支持包括 GICv3 的从属驱动（**gic\_v3\_its.c**）以及分配和映射 MSI 的设备方法（`pic_alloc_{msi,msix}()`、`pic_map_msi()`）。控制器需要一部分系统内存来运行，这需要由操作系统提供。可能的 ITS 实现的多样性意味着存在自动检测特性，配置设备时需要重新审视。这不仅包括为控制器预留的 RAM 数量，还包括各种缓存性/共享性属性，以及 ITS 内存系统使用的页面大小。

为设备分配并指派中断翻译表（ITT）（MAPD 命令）。软件必须为翻译表条目数组提供内存；每个条目映射给定设备的中断。向 ITS 发出 MAPD 命令后，ITT 将与设备 ID 关联。

* 保留一段 LPI 编号：每个 MSI 向量作为 LPI 传递给 CPU。可用 LPI 物理编号的池从 8192 开始，可通过内存中的字节数组配置。通常支持 MSI 的端点会请求一段向量而非单个中断。因此，驱动需要找到一段空闲的 LPI 并将其分配给特定设备。LPI 记账通过位图实现，每位表示一个中断号。这直接映射到空闲 LPI 池，位图的各部分分配给每个支持 MSI 的设备。
* 将 MSI 向量映射到 LPI、设备 ID 和集合（MAPVI 命令）：中断翻译的好处是，设备发送的任何虚拟中断号都可以映射到给定的物理中断向量（LPI）。因此，每个端点可以简单地使用任何方便的消息组合。MAPVI 命令将中断翻译和到相应 CPU 的路由插入所选设备的 ITT。这最后一步提供了允许 MSI 传递的完整信息集。

ITS 驱动的 PIC 方法提供了所述步骤的实现。`PIC_ALLOC_MSI/MSIX` 分配抽象 ITS 设备，实际上是带有预分配 LPI 编号集合的中断翻译表。MSI 和 MSIX 分配的主要区别在于，MSI 以向量范围请求，而 MSIX 向量一次请求一个。公共 `PIC_MAP_MSI` 回调正是如此：将 MSI 向量映射到给定设备的 LPI。最后，LPI 需要在配置表中解除屏蔽；然而，这必须从顶层 PIC（此处为 GICv3 驱动）发起。

尽管非常复杂，此设计提供了管理消息信号中断的灵活方式，通过提供单一 MSI/MSIX 触发地址、MSI 数据的任意选择、到物理中断标识符的硬件翻译，以及大量支持的设备和中断向量，简化了每个设备的中断资源分配。

## 对称多处理

标准 ARMv7-MP 规范将支持的 CPU 核心数限制为 8 个。每 4 个核心逻辑连接形成一个集群。然后，最多两个集群可通过 CoreLink 接口组合，提供完全一致的 8 CPU 核心系统。某些厂商的 ARMv7 核心实现可提供多达 16 集群可扩展性，这似乎是该架构的理论极限。ARMv8 是巨大的进步。互联现在能够使用四级 CPU 亲和性地址（A3:A2:A1:A0）通过其逻辑位置寻址每个 CPU，允许总核心数大幅增长。

### SMP 启动

ThunderX CPU 核心通过标准 ARM 电源状态协调接口（PSCI）管理。相关代码已在 FreeBSD 源码中提供，原样使用。为支持 ThunderX 上的 SMP 操作，主要工作集中在解决以下领域的问题：

* 系统和 TLB 缓存管理
* IPI 和中断处理
* 上下文切换
* 内存排序
* 操作原子性

例如，系统维护 CPU 核心之间的缓存一致性，但仅在其共享性域内。如果通用内存映射在该域中未标记为可共享，CPU 看到的数据副本可能不同。当一个 CPU 修改共享翻译表条目而未发出并向次级核心传播适当的 TLB 维护操作时，可观察到类似结果。在这种情况下，CPU 可能在相同的虚拟地址看到具有不同访问权限的不同物理帧。

### CCPI 与双插槽操作

ThunderX 芯片提供更复杂的可扩展性。基于 Cavium 一致性处理器互联（CCPI），两个处理器可以连接创建共享内存空间。典型的双插槽配置支持 96 核心和最多 1 TB 系统内存。从操作系统视角看，完整机器看起来像有两个独立的 NUMA（非统一内存访问）节点，每个由 48 CPU 和一半内存组成。I/O 接口（如 PCIe、SATA）可由两个节点访问，但强烈建议所有 I/O 访问由拥有相应接口的插槽完成。在这种情况下，整个系统性能和外围设备翻倍。双插槽机器提供两倍的 PCIe 链路、以太网接口等，中断使用两个独立的 ITS 单元在所有 CPU 之间分布。对于更大的工作负载，双插槽 Cavium 系统可使用低延迟以太网 fabric 连接。这允许每秒数百吉比特的聚合网络带宽。

## PCIe

Cavium ThunderX 机器提供标准化的接口，所有外围设备都连接到其上。CPU 提供的唯一 I/O 是现代 PCIe 3.0 总线。所有其他设备（SATA、以太网网卡等）是典型的 PCIe 端点，可被操作系统轻松检测，除单个 PCIe 控制器驱动外不需要任何机器特定的资源管理代码。ThunderX 提供两种不同的 PCIe 接口类型：内部和外部。内部是通用 PCIe 标准的简化版本，提供对 ThunderX SoC 内所有外围设备的类 PCI 逻辑访问。外部则是完全兼容的 PCIe 3.0 链路，允许轻松连接最多 x8 通道的通用 PCIe 卡。

ThunderX 驱动分为三部分：通用 PCIe 硬件访问器、FDT 配置的内部 PCIe 控制器，以及最后表示外部 PCIe 控制器的内部 PCIe 设备。FreeBSD PCI 子系统负责 PCI 操作的几乎所有方面，除了一些非常依赖硬件的低层功能。为满足这些要求，驱动需要提供三样东西：设备配置空间访问、资源（总线地址）分配和中断映射。在 CN88XX 平台上，对内部配置空间的任何访问都使用名为 ECAM 的通用机制（即设备的所有配置头映射到主机内存空间；对该位置的每次内存访问使控制器自动为用户生成所有 PCIe 请求）。外部 PCIe 配置空间使用外部控制器支持的间接寻址访问。其次，驱动需要提供的功能是资源分配。幸运的是，Cavium UEFI 配置所有 PCIe 树并用适当的值填充每个 BAR。驱动唯一需要做的是读取这些（总线）地址，在资源管理器（**rman(9)**）中标记为已使用，并返回结果。如果驱动未初始化（例如网卡虚拟功能的情况），控制器手动分配必要的总线空间并正确配置 BAR。驱动提供的最后一样是中断映射。目前，唯一支持的中断类型是 MSI 或 MSI-X，这在 ITS 中也需要一些怪癖处理。

ThunderX 的高级架构提供大量内部 PCIe 设备（超过 200 个端点）。为避免创建庞大的 PCIe 设备树，这些设备分为三个不同的区域，每个由独立的内部 PCIe 控制器管理。还值得注意的是，外部 PCIe 控制器是连接到内部 PCIe 总线的 PCIe 设备。虽然不直观，但此方案提供了支持设备各种硬件版本的简便方式。假设一种 ThunderX 芯片只有一个可用的外部 PCIe，而另一种可能有三个。使用传统方法，硬件的每个版本需要不同的机器描述（即 DTB）文件才能让所有控制器正确检测和配置。但当外部控制器是内部 PCIe 设备时，使用标准 PCIe 枚举技术可以动态收集多个控制器。

## VNIC

CN88XX 芯片具有强大的以太网能力，包括 40 Gbps、20/10 Gbps 和 1 Gbps 接口。ThunderX 引入了灵活且高度可编程的网络子系统设计，允许高效的硬件资源虚拟化和节点间连接，无需使用外部交换机。所介绍工作的主要目标是为所有类型的可用接口提供基本网络支持。

ThunderX 的网络子系统划分为几个核心组件：

* BGX - 通用以太网接口
* NIC - 网络接口控制器
* TNS - 流量网络交换

按上述顺序，它们分别实现：MAC 层、网络接口层，以及上述组件与其他 CN88XX 设备之间的硬件交换。此外，NIC 是支持 SR-IOV \[4] 的设备，可容纳多达 128 个虚拟功能，每个虚拟功能提供完整的网络接口特性。ThunderX 包含 2 个 BGX 实例，通过 TNS 单元连接到 NIC 及其虚拟功能。然而，所述 FreeBSD 实现的 ThunderX 网络驱动不包括对 TNS 及其特性的支持。使用 TNS 旁路逻辑，将 BGX 单元直接连接到相应的 NIC TNS 接口，并允许将 Rx/Tx 队列自由分配给 BGX 提供的逻辑 MAC。

所贡献的工作位于源码树的 **sys/dev/vnic/** 目录下，由一组驱动组成，分别实现 BGX、NIC、VNIC 和 MDIO 接口。MDIO 设置和部分 BGX 配置基于 FDT 描述，这是目前唯一可用的方法。

### BGX

可编程 MAC 层在 BGX 控制器中实现。它被视为常规 PCIe 端点，无需显式机器描述即可配置；但 BGX 到以太网 PHY 的分配需要呈现给驱动。两个内置 BGX 控制器各可提供最多 4 个逻辑 MAC（LMAC），每个最大速率 10 Gbps，或单个 40 Gbps LMAC。任何 LMAC 可连接到任意的 NIC 虚拟功能。LMAC 类型由低层固件选择，FreeBSD 驱动获取此信息以进行适当的设置。

BGX 核心代码位于 **thunder\_bgx.c** 文件中，负责通用接口启动，如 SerDes 配置、LMAC 类型检测和最终以太网接口配置。由于 BGX 可连接多种以太网 PHY，需要支持不同的介质连接类型。高速接口（如 XLAUI、XAUI、DXAUI 或 XFI）由 BGX 驱动管理；但低速 SGMII 使用位于 **thunder\_mdio.c** 文件中的专用 MDIO 驱动。后者导出 **KOBJ(9)** 方法用于 PHY 连接管理（`LMAC_PHY_{CONNECT,DISCONNECT}`）以及链路状态轮询（`LMAC_MEDIA_STATUS`）。

在正常 BGX 驱动操作中，软件轮询 MAC 层状态以保持 NIC 物理功能最新。轮询本身从 **callout(9)** 上下文中执行，定期运行（每两个系统 tick 一次）。链路状态变化（如速度转换等）时执行 BGX/LMAC 重新配置。当前链路状态存储在驱动软件上下文中，每个 LMAC 一份，并按需导出到 PF 驱动。

### 物理功能

物理功能驱动位于 **nic\_main.c** 中，与 BGX 和 TNS 协作创建高度可编程的网络接口。与其他流行网卡不同，CN88XX 物理功能不提供网络能力，而是作为从属虚拟功能（VF）的资源管理器，以及 MAC 层（BGX）和网络接口层（VNIC）之间的接口。PF 使用 PCI SR-IOV \[4] 技术支持最多 128 个虚拟功能。PF 与 VF 之间的通信通过每个 VF 的专用邮箱进行。MAC 层的任何变化或配置请求通过邮箱中断通知 VF。物理功能以类似方式接收 VF 的请求。

引入的 FreeBSD 驱动使用通用 PCI IOV 子系统创建和配置虚拟功能。VF 启动的关键步骤是调用 `pci_iov_attach()`。这在设备 attach 过程中调用的 PF `nic_sriov_init()` 函数中完成。此时，PF 和 VF 的所谓配置方案（高级接口选项，如 MAC 地址选择能力）被指定并传递给 PCI IOV 子系统。代码还需要向 PCI 层提供 IOV **KOBJ(9)** 方法，如：

* **PCI\_IOV\_INIT(9)**：由 `nicpf_iov_init()` 实现，验证请求的 VF 数量并保存此值供后续实际启动时使用。
* **PCI\_IOV\_UNINIT(9)**：用于禁用先前启用的 VF。
* **PCI\_IOV\_ADD\_VF(9)**：在 SR-IOV 基础设施初始化新 VF 时调用。`pci_iov_attach()` 请求的选项可用于根据配置方案设置 VF 参数。

在正常驱动操作中，PF 代码定期通过 BGX 接口轮询 LMAC 链路，并处理 VF PF 请求，这些请求可能与 VF 队列配置、链路/MAC 状态变化等相关。

### 虚拟功能

虚拟功能实现 VNIC 的网络能力。VF 能够执行与主存之间的 DMA 事务以传输数据包流量。所介绍的 VNIC 驱动由两个逻辑独立的部分组成：**nicvf\_main.c** 和 **nicvf\_queues.c**。前者执行典型的 FreeBSD 网络接口配置并提供 **ifnet(9)** 回调，如 `if_init`、`if_ioctl` 等。由于控制器可处理多个发送队列，驱动实现了 Tx 路径的多队列变体，使用 `nicvf_if_transmit()` 函数处理传出流量。以太网介质状态通过 PF 的消息更新，因此存根 `nicvf_media_status()` 函数只是将此信息导出到上层。驱动还支持硬件和接口统计，在 `nicvf_tick_stats()` callout 中定期刷新。

驱动的第二部分位于 **nicvf\_queues.c** 中，负责控制器的资源分配以及数据包传输和接收。特别是 `nicvf_config_data_transfer()` 是 VF 队列配置的焦点。每个虚拟功能包含一个队列集（QS），由以下组成：

* 8 个完成队列（CQ）
* 8 个发送队列（SQ）
* 8 个接收队列（RQ）
* 2 个接收缓冲区环（RBDR）

完成队列包含描述所有已完成动作的数据，如数据包传输或接收。其他队列由物理功能分配给选定的 CQ，可能是多对一。

发送方使用 SQ 描述出口数据和数据包发送前需要执行的动作（如 L3、L4 校验和计算）。每个 SQ 订阅一个目标完成队列。

接收队列是 VNIC 的内部结构，描述如何接收数据包。它们需要 CQ 和 RBDR 分配。多个 RQ 可连接到同一 CQ 和 RBDR。RBDR 描述主存中可用于存储接收数据的空闲缓冲区。收到数据包时，VNIC 将传入数据移到 RBDR 描述符提供的空闲缓冲区，并将其物理地址返回到分配的完成队列。这可能是一个缺点，因为使用物理寻址在内存中定位接收缓冲区比虚拟寻址困难得多。然而，这通过专门从直接映射（Direct Map，线性映射内存的连续区域）分配内存来解决。因此，在虚拟地址空间中找到接收缓冲区相当简单。此外，RBDR 队列使用的入口缓冲区部分被适配为存储包含 **mbuf(9)** 信息以及 **bus\_dma(9)** 相关数据的小描述符。这种方法可以显著简化 mbuf 记账并减少 Rx 上的 mbuf 访问延迟。

NIC 队列集的一个有趣能力是，如果特定 VF 上的 VNIC 未启用，其队列仍可被另一个运行的 VNIC 使用。这使得可以将一个队列集分配给单个 VNIC、所有队列集分配给单个 VNIC，或介于两者之间的任何配置。目前，VF 驱动默认每个 VNIC 使用单个队列集。

## 可用性

支持已集成到主线 FreeBSD 11.0-CURRENT 中，从 SVN 修订版本 289550 起公开可用。截至撰写本文时，改进 ThunderX 上 FreeBSD 的工作仍在进行中。

## 未来开发

尽管 FreeBSD 对 ThunderX 的支持已相当完善，但仍有许多领域可以从进一步开发中受益。还有一些功能问题需要在双插槽配置完全支持主线 FreeBSD 之前解决。下面简要描述一些更有趣的开发领域：

* 主线 FreeBSD 中的双插槽支持：为提高内核性能，从 `DMAP_MIN_PHYSADDR` 到 `DMAP_MAX_PHYSADDR` 的所有物理地址静态映射到名为 DMAP（直接映射）的连续 VA 区域。当 PA 空间碎片化（如 ThunderX 双插槽配置），VA DMAP 范围巨大并超过 CPU 核心在三级翻译表模式下可寻址的限制。Semihalf 实现了一个补丁，通过创建多个 DMAP 范围区域来解决这些问题，节省空间并允许双插槽设备操作。然而，DMAP 数组中的查找可能降低性能，因此四级翻译表解决方案是首选。但当前四级页表实现不允许成功双插槽启动。这是一个需要重新设计的领域，以在主线中支持两个 ThunderX 节点。
* 多 ITS 支持：目前只有连接到 socket-0 的 ITS 可操作，但在双插槽系统的情况下，此资源翻倍。FreeBSD/arm64 缺少对多个和链式中断控制器的支持；因此需要对 ARM64 架构的中断处理代码进行更改。

## 致谢

特别感谢以下人员：

* Dominik Ermel、Michał Mazur、Tomasz Nowicki 和 Michał Stanek（Semihalf）在此项目中的工作和投入。
* Ed Maste（FreeBSD 基金会）、Andrew Wafaa（ARM）和 Larry Wikelius（Cavium）的成功合作。
* Andrew Turner（FreeBSD 项目）的深入审查和建议。
* Rafał Jaworowski（Semihalf）组织和管理此项目。

此项目的成功是 Semihalf 团队、Andrew Turner、ARM、Cavium 和 FreeBSD 基金会的联合工作。项目由 ARM、Cavium、FreeBSD 基金会和 Semihalf 赞助。

## 参考文献

\[1] Cavium, Cavium ThunderX CN88XX Hardware Reference Manual. (2015)

\[2] ARM Ltd. Processor Division, GIC Architecture Specification PRD03-GENC-010745 12.0. (2013)

\[3] ARM Ltd., ARM Architecture Reference Manual for ARMv8-A architecture profile. (2013–2015)

\[4] Intel, PCI-SIG SR-IOV Primer, 321211-002. (2011)

***

**Zbigniew Bodek**

Zbigniew Bodek 是 Semihalf 的软件工程师，专注于 ARM 和 PowerPC 计算机的 BSD 和 Linux 操作系统开发。他的主要兴趣领域是计算机科学、微处理器技术、嵌入式系统和内核开发。他从 2013 年起成为 FreeBSD 提交者。过去一年半，Zbigniew 一直参与多核 ARMv8 芯片的 FreeBSD 开发和优化。

**Wojciech Macek**

Wojciech Macek 是 Semihalf 的软件工程师，Semihalf 是一家位于世界寒冷地区的小公司。他主要关注 ARM 架构、内核内部和超快存储解决方案。他最近的工作集中在为多核 ARMv8 系统增强和优化 FreeBSD。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://freebsd-journal-cn.bsdcn.org/2016-0506-armv8/freebsd-on-cavium-thunderx-system-on-a-chip.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
