2. 信用量(Credit)基础:信用量的类型(Posted/Non-Posted/Completion)、初始值与最大值

2.1 信用量的核心作用

PCIe 流量控制的核心是信用量(Credit)机制。发送端(Transmitter)在发送事务层包(TLP)之前,必须确保接收端(Receiver)有足够的缓冲区空间来接收该 TLP。这个“缓冲区空间”就是通过信用量来量化的。信用量机制防止了接收端缓冲区溢出,实现了无丢包的可靠传输,同时允许发送端在未收到确认的情况下连续发送多个 TLP,从而提升总线利用率。

关键概念:信用量不是数据,而是接收端缓冲区可用空间的“代币”。发送端持有代币才能发送数据,接收端处理完数据后返还代币。

2.2 信用量的三种类型

根据 TLP 的事务类型,PCIe 定义了三种独立的信用量类型,每种类型对应独立的缓冲区池:

信用量类型 对应 TLP 类型 缓冲区用途 典型示例
Posted (P) Posted 请求 存储不需要响应的写请求 Memory Write (MWr)、Message
Non-Posted (NP) Non-Posted 请求 存储需要响应的读/写请求 Memory Read (MRd)、I/O Read/Write、Configuration Read/Write
Completion (Cpl) 完成报文 存储对 Non-Posted 请求的响应数据 Completion (Cpl)、Completion with Data (CplD)
调试要点:三种信用量相互独立,互不影响。例如,Posted 信用量耗尽不会阻塞 Completion 报文的发送。在调试死锁或性能瓶颈时,必须分别检查每种信用量的状态。

2.3 信用量的粒度:单位与计量

信用量的计量单位不是字节,而是数据单元(Data Unit)。一个数据单元的大小由接收端在其能力结构(Device Capabilities Register)中通告,通常为 16 字节或 64 字节。发送端和接收端必须就数据单元大小达成一致。

  • 信用量消耗:发送端每发送一个 TLP,消耗的信用量数量 = ceil(TLP 数据载荷长度 / 数据单元大小)。对于没有数据载荷的 TLP(如仅 Header 的读请求),消耗 1 个信用量。
  • 信用量返还:接收端从缓冲区中取出 TLP 并处理后,通过发送 InitFC1/UpdateFC DLLP 将信用量返还给发送端。
// 信用量消耗计算示例(假设数据单元 = 16 字节)
TLP 数据载荷 = 32 字节
消耗信用量 = ceil(32 / 16) = 2 个信用量

TLP 数据载荷 = 0 字节(如 MRd 读请求)
消耗信用量 = 1 个信用量(仅 Header 占用)

2.4 初始值与最大值

信用量的初始值和最大值在链路初始化阶段通过 InitFC1 和 InitFC2 两个阶段协商确定。

参数 含义 协商阶段 典型值范围
初始信用量 (InitFC) 链路初始化完成后,发送端立即可以使用的信用量数量 InitFC1 + InitFC2 1 ~ 2047 (Header) / 0 ~ 2047 (Data)
最大信用量 (MaxFC) 接收端缓冲区能够支持的最大信用量上限 InitFC2 1 ~ 2047 (Header) / 0 ~ 2047 (Data)
常见误解:初始信用量不一定等于最大信用量。接收端可能只通告较小的初始信用量,但在处理过程中通过 UpdateFC 逐步增加可用信用量,直到达到最大信用量。调试时如果发现信用量增长缓慢,应检查接收端的数据处理速率。

2.5 信用量协商流程(SVG 图)

下图展示了链路初始化阶段信用量协商的完整流程,包括 Posted、Non-Posted 和 Completion 三种信用量的独立协商:

信用量协商流程(InitFC1 / InitFC2) 发送端 (Transmitter) 等待信用量通告 接收端 (Receiver) 通告缓冲区能力 InitFC1 (P/NP/Cpl 各 1 个) InitFC2 (完整信用量通告) InitFC2 通告内容(每种类型独立) Posted (P) InitFC=16, MaxFC=128 Non-Posted (NP) InitFC=8, MaxFC=64 Completion (Cpl) InitFC=8, MaxFC=64 调试观察点 1. InitFC1 仅通告 1 个信用量,用于发送第一个 TLP 以触发完整协商。 2. InitFC2 通告完整的初始信用量和最大信用量,之后进入正常流量控制。 3. 三种信用量的 InitFC 和 MaxFC 可以不同,取决于接收端的设计。

2.6 信用量状态机与调试案例

在调试过程中,工程师需要关注每个信用量类型的当前可用值。以下是一个典型的信用量状态转换表:

事件 Posted 信用量变化 Non-Posted 信用量变化 Completion 信用量变化
链路初始化完成 InitFC = 16 InitFC = 8 InitFC = 8
发送 1 个 MWr (32B) 16 - 2 = 14 8 (不变) 8 (不变)
发送 1 个 MRd (无数据) 14 (不变) 8 - 1 = 7 8 (不变)
接收端处理完 1 个 MWr 14 + 2 = 16 7 (不变) 8 (不变)
接收端返回 1 个 CplD 16 (不变) 7 (不变) 8 - 1 = 7
调试案例:某 Gen3 x8 设备在压力测试下出现写性能骤降。通过读取链路状态寄存器发现 Posted 信用量长期为 0,而 Non-Posted 和 Completion 信用量充足。进一步分析发现接收端的 Posted 缓冲区处理速率不足,导致信用量无法及时返还。优化固件中的写请求处理流水线后,Posted 信用量恢复动态平衡,性能恢复正常。

2.7 信用量最大值的设计考量

最大信用量(MaxFC)直接决定了接收端缓冲区的深度。设计时需要权衡以下因素:

  • 延迟容忍度:较大的 MaxFC 允许发送端在未收到返还的情况下发送更多 TLP,适合延迟敏感的应用。
  • 芯片面积与功耗:更大的缓冲区意味着更多的门电路和静态功耗。
  • 链路宽度与速率:高带宽链路需要更大的 MaxFC 来保持流水线满载。
// 最大信用量计算示例(假设数据单元 = 16 字节)
目标:支持 4KB 的 Posted 写请求缓冲
MaxFC (Posted Data) = 4096 / 16 = 256 个信用量
MaxFC (Posted Header) = 256 个信用量(每个 TLP 至少 1 个 Header 信用量)
工程建议:在调试初期,优先检查 InitFC 和 MaxFC 的比值。如果 InitFC 远小于 MaxFC,说明接收端依赖频繁的 UpdateFC 来补充信用量,这可能导致发送端出现周期性停顿。适当增大 InitFC 可以减少 UpdateFC 的交互频率,提升吞吐量。