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 三种信用量的独立协商:
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 的交互频率,提升吞吐量。