关于pcie dllp FC内容:
源地址:
PCIe(三)—— PCIe协议栈,事务层和数据链路层 | Soul Orbit
3.2. 控制消息:DLLP(Data Link Layer Packet)
除了传输TLP数据包之外,数据链路层还需要很多专门用于控制的数据包,比如上面提到的Ack和Nak,这些数据包叫做DLLP(Data Link Layer Packet)。其格式如下:
注:所有的DLLP包均为固定长度的64b;8Byte。在128/130b编码下SDP内容为:0xf0ac, verdi波形显示的字符为rmlh_data[15:0] 低16bit内容(大小端的影响);且该DLLP没有EDN Token,最后16b为crc内容
DLLP中DLLP Type用来指定包的类型,而最后16位的CRC用来做校验,其主要分为以下几种类型:
3.2.1. Ack/Nak
我们在TLP事务消息传输的里就提到过Ack和Nak消息,它们可以说是DLLP中最常用的消息了。功能顾名思义,Ack表示接收成功,Nak表示接收失败,需要重传。这两个包的格式如下:
其中,AckNak_Seq_Num表示当前已经收到的最新的消息序号,所以和TCP类似,PCIe的Ack和Nak可以进行批量操作:无论是Ack还是Nak,当发送方收到这个消息之后,就可以将Retry Buffer中比这个序号老的消息全部移除了,所以Ack/Nak时只需要将最新的序号带上即可。Ack/Nak的差别在于:如果是Nak,那么发送方在移除之后,需要对Retry Buffer中这个序号之后的消息全部进行重传。
最后,DDLP的重传是由次数限制的,默认阈值是4次。如果超过四次,就出触发物理层开始重建(retrain)链路。如果依然失败,就会将该链路关闭。
实际中ACK sequence num从0一直增加到2^12时会进行回滚
3.2.2. VC(Virtual Channel)与流量控制
在说TLP的时候,我们提到了PCIe的流量控制是通过将TC(Traffic Class)映射到VC(Virtual Channel),并且利用VC的信用机制来实现的。这里我们就一起来看看这个信用机制吧!
数据链路层中的信用额度管理有两个重要的特点:
- 不同处理方式是的TLP消息有着单独的信用额度管理:Posted(P),Non-Posted(NP)和Completion(Cpl)。这三种消息的信用额度是独立的,互不影响。
- 每个VC都有着自己的独立的信用额度管理,而不是Link。也就是说,如果一个Link上有多个VC,那么每个VC都需要单独的初始化和更新
参与流量控制的消息有很多,主要有三类,每一类有三个变种(N/NP/Cpl),我们的流量控制也主要分三步,其细节和统一的消息格式如下:
- InitFC1-P/NP/Cpl:接收端设备使用此消息向发送端发起初始化流量控制的流程,并初始化信用额度,这是第一步。这个消息有接收端发起的原因是因为,不同的接收端能力不同,所以应该由接收端根据自己的能力,比如缓存的大小,来决定信用额度的大小。
- InitFC2-P/NP/Cpl:用于发送端向接收端确认InitFC1的消息,这是第二步。这个消息中会带有从第一步接收到的信用信息,但是它会被接收端忽略,并没有什么用。另外,这个消息发送之后,发送端将不会再理会任何后续的InitFC1消息了。
- UpdateFC-P/NP/Cpl:用于在信用额度初始化完成之后,接收端向发送端对信用额度进行更新。
上图为典型得dllp link up过程,即rdlh_link_up信号的拉起流程;
这个消息中各个字段含义如下:
-
Type:消息ID,映射如下:
-
VC ID(v[2:0]):Virtual Channel的Id,Id一共有3位,代表8个VC。
-
HdrFC:TLP头部的Credit数量。在发送时,一个TLP头对应着一个Header Credit,不论该TLP的大小如何。
-
DataFC:TLP数据部分的Credit数量。一个 DW(Double Word,双字,即4字节)对应着一个Data Credit。
举个例子,我们假设有一个64位地址的内存的写请求,数据长度为128字节,那么我们会需要发送一个4 DW的TLP头,加上128字节的Payload,和一个1 DW可选的TLP Digest,所以我们一共最多消耗1个Header Credit,和 (128 + 4) / 4 = 33个Data Credit。
tlp digest 当tlp header中TDbit为1是会加入32bit ecrc。
然后,为了保证发送方正常的消息发送,当接收方处理完部分消息后(或者一些特殊情况后),就会根据其当前缓存的大小,向发送方发送UpdateFC消息,告诉发送方,接收方的信用额度还剩下多少。另外,除了这种情况,接收方还会定时的向发送方上报自己的信用额度(最长间隔30us),这么做的原因是为了避免意外情况,如CRC校验出错,导致信用额度上报丢失,从而导致发送方停止发送消息的问题。
最后,数据链路层还支持Scaled Flow Control,即信用额度的数量可以是2的幂次方,这样就可以管理更大的信用额度了:
为了帮助理解,我们举一个例子:
注意:如果查看原始的包,在计算时需要注意,HdrFC和DataFC都没有对其到字节上,所以记得做好位运算。
-
首先,PCIe的Endpoint会向Switch发送如下三条消息来进行流控初始化:
-
当Switch收到这个消息后,也会向Endpoint发送三条类似的消息,进行反向的初始化。因为流程类似,从这里开始,之后Switch向Endpoint发送的反向流程我们就忽略了。
-
Switch收到了InitFC1 DLLP后,会使用InitFC2 DLLP进行确认: