PCIE学习
+ -

PCIe学习(四)

2025-08-06 1 0

3 数据链路层

数据链路层是PCIe协议的中间一层,起着承上启下的作用。

3.1 DLLP

本节分析一下数据链路层的数据包(Data Link Layer Packet,DLLP)。

DLLP只用于链路两端的数据链路层通信。DLLP的主要用途是TLP流量控制,链路初始化,电源管理,事务层与物理层之间信息传递等。与TLP不同的是,DLLP不需要路由,只是在一条链路的两端传递。

204023764359

DLLP的大小固定,只有6-Byte的有效信息。其中Byte-0是DLLP类型编码,Byte-1/2/3根据DLLP不同类型有不同含义,Byte-4/5是16-bit的CRC。

204028954569

Gen 5中的DLLP类型编码整理如下表:

Encoding** DLLP Type**
0000 0000 Ack
0000 0001 MRInit
0000 0010 Data_Link_Feature
0001 0000 Nak
0010 0001 PM_Enter_L1
0010 0010 PM_Enter_L23
0010 0011 PM_Active_State_Request_L1
0010 0100 PM_Request_Ack
0011 0000 Vendor-specific
0011 0001 NOP
0100 0v2v1v 0 InitFC1-P
0101 0v2v1v0 InitFC1-NP
0110 0v2v1v0 InitFC1-Cpl
0111 0v2v1v0 MRInitFC1
1100 0v2v1v0 InitFC2-P
1101 0v2v1v0 InitFC2-NP
1110 0v2v1v0 InitFC2-Cpl
1111 0v2v1v0 MRInitFC2
1000 0v2v1v0 UpdateFC-P
1001 0v2v1v0 UpdateFC-NP
1010 0v2v1v0 UpdateFC-Cpl
1011 0v2v1v0 MRUpdateFC
All other encodings Reserved

表中带有MR的DLLP都是为多根虚拟化(MR-IOV)准备的,暂且忽略。

Ack/Nak DLLP格式

Ack/Nak DLLP用于数据链路层的Ack/Nak协议。

204036431407

AckNak_Seq_Num字段指示哪些TLP被影响,成功(Ack)或者不成功(Nak)。下一节详细分析数据链路层的Ack/Nak协议。

NOP DLLP格式

接收端接收到NOP,检查CRC,然后放弃该DLLP,不做任何动作。

204041261538

InitFC1/InitFC2/UpdateFC格式

InitFC1/InitFC2用于流量控制的初始化;UpdateFC用于更新流量控制的信用值。

20404678523

204052655122

Byte-0的高4-bit指示是哪种子缓冲区。

DataFC字段指示事务层中Data缓冲区的信用值,HdrFC指示Header缓冲区的信用值。

DataScale和HdrScale字段分别是Data和Header缓冲区信用值放大系数。

V[2:0]字段是虚拟通道(VC)的ID。

204058902730

各字段具体含义可参考流量控制一节。

PM DLLP格式

PM DLLP是一组DLLP的统称,用于电源管理。Byte-0的最第三位是不同的编码,目前Gen 5中的PM DLLP包括:PM_Enter_L1,PM_Enter_L23,PM_Active_State_Request_L1,PM_Request_Ack。

具体含义留到电源管理章节分析。

20410547656

Vendor-specific DLLP格式

Vendor-specific DLLP的Byte-1/2/3定义取决于产商。

20412534751

204128937787

Feature Support字段指示发送端口支持的特性,该值与其Data Link Feature Capability寄存器对应。

204135319320

3.2 ACK/NAK协议

3.2.1 Ack/Nak协议原理

数据链路层的一个重要职责是保证TLP正确传输。尤其是Posted类型的事务,请求者发出事务后就认为事务结束,但完成者是否真的接收到了事务吗?

数据链路层在向物理层传输TLP之前,给TLP前面加上序列号(Sequence Number),后面加上LCRC。序列号是连续递增的,每个TLP分配一个。有了序列号和LCRC,链路两端的数据链路层可以使用Ack/Nak协议来保证链路上的传输。

204155298158

发送端为每个TLP加上序列号和LCRC,同时将要发送的数据包存储在本地(数据链路层)的重试缓冲区(Replay Buffer)。接收端解析收到的数据包,首先计算LCRC,如果没发现有错误,向发送端发送Ack DLLP,如果有错误,向发送端发送Nak DLLP。不管是Ack DLLP还是Nak DLLP,其中都包含有序列号。

204200489907

这里需要注意,接收端并不是对每个接收到的TLP都会返回Ack/Nak DLLP,为了节省链路资源,通常是是攒齐了几个再发Ack/Nak DLLP。发送端在接到Ack DLLP后,得到其中的序列号,知道此序列号之前的TLP都已经被正确接收,因此将本地Replay Buffer中保存的这些TLP都清除掉;如果是接收到Nak DLLP,说明此DLLP中的序列号之后的TLP中,至少有一个发生传输错误,因此需要将序列号之后的TLP全部重新传输一次。

204205610112

上图是Ack/Nak DLLP的格式,Byte-0是Ack/Nak的编码。Byte-2和3是序列号字段,共有12-bit,因此序列号的最大数值是4095。初始化后,序列号计数器从0开始递增,到了4095后,下一个序列号是0,也就是说序列号的数值是回滚(Roll-back)式的。所以,对于发送端来说,有可能发生上一次正确接收的序列号是4093,下一个Ack/Nak返回的序列号是2的这种情况。

LCRC是32-bit,对序列号和整个TLP进行校验。DLLP 的CRC是16-bit,是对DLLP的校验。不要混淆了两个CRC。

为了实现Ack/Nak机制,PCIe设备需要在数据链路层实现相关的逻辑设计。

204210751429

3.2.2 发送端设计

对于发送端,需要实现:

  • 12-bit的NEXT_TRANSMIT_SEQ计数器。此计数器生成将分配给下一个传入TLP的序列号。在系统复位期间,此计数器值复位成0,随后在系统正常工作期间递增,到了4095后回滚到0,继续递增
  • LCRC生成器,用于产生32-bit的CRC,对序列号和TLP进行校验
  • Replay Buffer,此缓冲区按照传输顺序存储TLP,包括序列号和LCRC。当发送端接收到Ack时,它从重试缓冲器中清除序列号等于或早于Ack中编号的TLP。通过这种方式,该设计允许一个Ack代表几个成功的TLP,从而减少了必须发送的Ack的数量。如果接收到Nak,在Nak中的序列号仍然指示接收到的最后一个成功传输的数据包。因此,即使接收到Nak也会导致发射端的Replay Buffer中清除TLP,即Nak DLLP中的序列号之前的TLP(包含该序列号指示的TLP)都会从Replay Buffer中清除,而序列号之后的TLP会被重新传输
  • REPLAY_TIMER计数器,代表的是计时器。如果超时,说明发送端发送了一个或多个TLP,但是在预期的时间内没有得到Ack或者Nak。超时会触发Replay Buffer中的所有内容被重新传输,并重置此计数器
  • 2-bit的REPLAY_NUM,用于跟踪接收到Nak或REPLAY_TIMER超时后的重试次数。当REPLAY_NUM计数从11b回滚到00b(表示4次尝试传递同一组TLP失败)时,数据链路层自动强制物理层重新训练链路(LTSSM进入恢复状态)
  • 12-bit的ACKD_SEQ寄存器,用于保存最近一次接收到的Ack/Nak DLLP中的序列号
  • DLLP CRC检查模块,校验接送端返回的Ack/Nak DLLP中的CRC值
  • #

  • #

  • 3.2.3 接收端设计

对于接收端,需要实现:

  • LCRC检查模块,校验TLP的LCRC值
  • 12-bit的NEXT_RCV_SEQ计数器,用于跟踪预期序列号,验证顺序数据包接收。在系统复位时或数据链路层处于非活动状态时,它被初始化为0,并且对于转发到事务层的每个良好TLP,它会递增一次
  • 序列号检查模块
  • NAK_SCHEDULED标志,当接收端准备返回Nak给发送端时,置高该标志位,当接收端成功的接收到TLP时,清除该标志位
  • AckNak_LATENCY_TIMER,每当接收端成功接收到尚未确认的TLP时,此计时器就会运行。一旦计时到期,接收端就需要发送一个Ack或Nak。
  • Ack/Nak生成器,对正常接收的TLP产生Ack,对失败的TLP产生Nak。
  • 3.2.4 PCIe数据包优先级

实际上,PCIe是双单工传输,从PCIe组件角度看需要实现上述的全部逻辑。

到这里,我们总结一下PCIe链路上的数据包,有TLP/DLLP/Ordered Sets三种,Ordered Sets是在物理层,后面再讲。PCIe协议建议的处理优先级如下(从高到底):

    1. Completion of any TLP or DLLP currently in progress (highest priority)
    1. Ordered Sets
    1. Nak DLLP
    1. Ack DLLP
    1. Flow Control
    1. Replay Buffer re‐transmissions
    1. TLPs that are waiting in the Transaction Layer
    1. All other DLLP transmissions (lowest priority)
  1. 3.2.5 直通模式

最后,提一下Switch的直通模式(Cut-Through Mode)。对于Switch,只是负责转发TLP,正常做法是Switch的TLP从入口(Ingress)进入Switch,Switch检查接收到的TLP,如果没有传输问题,则向出口(Egress)转发TLP。如果TLP的数据载荷很大,这种方式无疑会增加延迟。另外一种选择是,Switch很快从TLP Header中得到路由信息(PCIe是串行总线,TLP Header先于Data传输),接下来Switch可以假设数据包是好的,直接向出口转发。这种方式就是Switch直通模式。

不过直通模式存在一个问题,如果随后在Switch入口端口发生了传输错误,入口可以发送Nak要求重新传输。但是对于出口端口,该如何处理?不能简单粗暴的清除出口的Replay Buffer,因为出口端口的链路对端还在等待继续接收。这时出口需要向对端指出该TLP“失效(nullified)”。失效数据包以EDB符号而不是END符号终止,TLP的32位LCRC从原始计算值反转(1的补码)。接收到无效数据包的接收端则会直接丢弃该数据包,不做任何处理。

下面是一个Switch直通的示例,TLP传输方向从左向右。

    1. 一个TLP发送到Switch的Ingress端口,该TLP在传输过程中被损坏,但是现在还不知道
    1. Switch解析TLP Header,向Egress端口转发
    1. Switch接收到完整的TLP,通过LCRC发现传输错误,向上游发送Nak
    1. 在Switch的Egress端口,Switch用EDB替换坏TLP末端的END帧符号,并反转计算的LCRC值。TLP现在变成“失效”,Switch将其从Replay Buffer中丢弃。
    1. Switch下游的EP检测到EDB符号和反转的LCRC,知道这是一个无效数据包,直接丢弃数据包。注意,EP不会返回Nak。
  1. 204224514049

【待续】

本文转自于公众号《老秦谈芯》,版权归《老秦谈芯》所有。

0 篇笔记 写笔记

关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!