本文主要是介绍PCI Express学习篇---链路层(一)ACK/NAK协议介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
声明:此文章为原创,转载请注明 转自https://blog.csdn.net/weixin_48180416/article/details/117390013
数据链路层是为了保障TLP包的可靠传输,尽管Spec中规定了误码率小于10^-12,但是仍然会发生错误带来一些问题,单个bit的错误会使整个数据包被损坏。速率的提升会使这个问题更加显著。
为了实现链路层的保护,引入错误检测的编码---LCRC,计算范围是Sequence Number+TLP header+payload+ECRC。
接收端需要检查LCRC是否正确,Sequence Number是否正确,Receiver端通过ACK包告知接收到了正确的TLP包,通过NAK告知接收到了错误的TLP包。
以下介绍实现ACK/NAK协议的组件
发送端:
- NEXT_TRANSMIT_SEQ: 记录下一个要发送的Sequence Number的值,最大值是4095之后会回0;
- LCRC Generator: 产生32bit CRC, 计算范围包含TLP和Seq;
- Replay Buffer: 按照发送的顺序存储TLP,包含Seq(2B)+Header(up to 16B)+Optional Payload(up to 4KB)+Optional ECRC(4B)+LCRC(4B),当收到ACK时会清除replay buffer内Seq小于或等于ACK包Seq的TLP,设计中允许一个ACK代表多个成功的TLP;当收到NAK时会清除replay buffer内Seq小于或等于NAK包Seq的TLP(因为NAK记录的是最后一个正确TLP的Seq),然后重传replay buffer中的所有TLP;
- REPLAY_TIMER: 实质上是一个看门狗计数器,当timeout时还是没有收到ACK/NAK包就会replay并且restart;
- REPLAY_NUM: 2bit Counter, 记录重传的次数,当从11 roll over到00(说明replay了4次),数据链路层就会自动force物理层重新训练状态机(LTSSM会进入Recovery状态);
- ACKD_SEQ: 12bit寄存器,存储着最近收到的ACK/NAK的Seq,如果收到的ACK/NAK是"later Sequence Number"(可能存在4095->0 roll over的情况)可以认为是forward progress, 这个时候就可以清除replay buffer里面的TLP(replay buffer Seq <= ACK/NAK Seq),复位REPLAY_TIMER和REPLAY_NUM;
- DLLP CRC Check: 检查DLLP的16bit CRC, 如果检测到错误,DLLP会丢弃并且会报告Correctable Error,DLLP包没有重传和校正的机制,只能期待下一个成功的ACK/NAK DLLP。
注:NEXT_TRANSMIT_SEQ - ACKD_SEQ不允许大于总Counter的一半,例如NEXT_TRANSMIT_SEQ - ACKD_SEQ = 2048时,链路层就不会从事务层接收TLP,直到有新的回应。如果发生了超过一半的情况,数据链路层会报告protocol error。
接收端:
收到的TLP会先检查LCRC错误,然后检查Sequence Number。如果没有错误的话TLP会传递到事务层,如果有错误,TLP会丢弃并且scheduled NAK除非已经有NAK outstanding。
- LCRC Error Check:检查LCRC错误,如果计算的LCRC和TLP的LCRC不匹配,说明TLP中有bit错误,就会丢弃TLP并且发NAK;
- NEXT_RCV_SEQ(NRS): 12bit计数器,跟踪下一个期待接收的Seq Num, TLP有CRC错误或无效包("nullified")或Seq Num Check有错误,就不会传到事务层,并且不会增加这个计数器;
- Sequence Number Check:检查完LCRC OK后,检查接收的TLP Seq Num与NRS是否一致,存在以下三种情况:
- TLP Seq Num equal NRS:Good TLP,是正确的情况,当AckNak_LATENCY_TIMERS expire时,发送ACK包,包含最后一包good TLP的Seq Num(即NRS-1);
- TLP Seq Num earlier than NRS: Duplicate TLP,是以前发送过的重复包,NRS - TLP Seq Num不超过2048,不认为是错误,silently dropped并且发送一个带有Seq Num为(NRS-1)的ACK包;
- TLP Seq Num later than NRS: Invalid TLP,发生丢包的情况,会发送Nak,如果没有Nak outstanding。
由于4095后Seq Num会roll over,所以实际的范围是这样定义的:(以NRS=30/31/32为例)
- NAK_SCHEDULED Flag: 当接收端schedule NAK的时候会置此标志位为1,当成功发送了一个带有Seq Num为(NRS-1)的NAK包后清零。目的是有outstanding NAK就不需要再发送NAK包;
- AckNak_LATENCY_TIMER:接收到一个正确TLP后开始计数,当timer expire会发送一个带有Seq Num为(NRS-1)的ACK包,当发送了ACK或NAK包后复位;
- Ack/Nak Generator: ACK/NAK中的Seq Num都是NRS-1,格式如下:
发送接收端具体实现细节
发送端:
- Sequence Number:从事务层发往链路层,首先需要加入Sequence Number,Seq Num可能会roll over;
- 32bit LCRC: 加入LCRC,范围是Seq Num+TLP;
- Response to ACK DLLP: 把收到的ACK的Seq load到ACKD_SEQ中,复位REPLAY_TIMER和REPLAY_NUM,清除Replay buffer中的<=SEQ NUM的TLP;
- Response to NAK DLLP:把收到的NAK的Seq load到ACKD_SEQ中,复位REPLAY_TIMER和REPLAY_NUM,清除Replay buffer中的<=SEQ NUM的TLP,重放buffer中剩余的包;
接收端:
- Physical Layer: TLP接收在物理层检测到receiver error(framing,disparity, invalid symbols)如果告知链路层,链路层发NAK包并重放TLP包,如果不告知链路层,链路层也会因为Seq Num丢包而发NAK包并重放TLP包;
- LCRC Check:检查LCRC错误,如果计算的LCRC和TLP的LCRC不匹配,说明TLP中有bit错误,就会丢弃TLP并且发NAK;
- Next Received TLP's Sequence Number: 如果LCRC正确,会比较接收到的TLP的Seq Num和NRS;
- Receiver Schedules a ACK: AckNak_LATENCY_TIMER expire后发送一个ACK,含有NRS-1的Seq Num;
- Receiver Schedules a NAK: 虽然发送端需要立刻发送NAK(因为后面的接收的其他TLP也会丢弃),但是其他的已经再处理的TLP, DLLP, Order Set优先级更高,NAK会等到它们都完成再发,同时,如果其他接收的TLP丢弃,由于NAK_SCHEDULED flag=1,就不会再有额外ACK/NAK schedule。
Replay Number Rolls Over
当REPLAY_TIMER由于没有接收到ACK或NAK而expire,replay过程可以被重复3次,如果重复大于3次,REPLAY_NUM就会从3 roll over至0.
- 如果发生这种情况一定是链路存在一些问题,链路层就会触发物理层重新训练链路(LTSSM进入Recovery状态机);
- 如果使能AER会报Replay Number Rollover error错误;
- Replay Buffer的内容会保持,数据链路层不会初始化(只是重新训练链路,不会复位链路);
- 当链路训练完成后,transmitter会再重放,以期望问题能够解决;
- Spec没有规定如何处理repeat rollover event, PCIe Technology3.0建议记录重新训练的次数,超过规定的次数后,通过Uncorrectable Fatal Error或者中断通知软件。
Transmitter DLLP Handling
Ack/Nak Error Checking模块检查ACK/NAK DLLP的16bit CRC是否存在错误,
- 如果存在错误,DLLP会丢弃,DLLP包没有重传和校正的机制;
- AER会报告Correctable Error;
- 会使ACK之间的间隔变大,REPLAY_TIMER可能会expire,导致TLP replay。
Error Situations Handled by Ack/Nak
- LCRC错误
- TLP Losts(物理层检测到错误后丢包)
- Ack/Nak包损坏
- 没有接收到Ack/Nak包
- Receiver fails to send Ack/Nak
上述情况的详细处理过程见(二)ACK/NAK实例博文。
Switch Cut-Through Mode
当TLP经过Switch的Ingress Port的时候,当没有收到TLP的整包的时候是没有办法判断LCRC是否正确的,通常情况下用到Store-Forward模式缓存整包,没问题再送到Egress Port,但是这样的情况大包会有很大的Latency,会影响性能。
为了提高性能可以采用Cut-Through模式,这种模式下Ingress Port可能会将TLP传给Egress Port后才会发现LCRC错误。
Cut-Though Mode提供一个解决方案:“nullified” TLP
- 这种TLP的LCRC是invert(按位取反)+EDB;
- 这种TLP本质上处理的时候“好像不存在一样”;
- 在Egress Port,不存入replay buffer,NEXT_TRANSMIT_SEQ回滚-1;
- 接收端的NRS不增加,AckNak_LATENCY_TIMER不启动, NAK_SCHEDULED不设置;
- 接收端只是简单的丢弃此包,不需要返回ACK/NAK。
这篇关于PCI Express学习篇---链路层(一)ACK/NAK协议介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!