ack/nak是一种由硬件实现的,完全自动的机制,目的是保证tlp有效可靠地传输。ack dllp用于确认tlp被成功接收,nak dllp则用于表明tlp传输中遇到了错误。
如上图所示,发送方会对每一个tlp在replay buffer中做备份,直到其接收到来自接收方的ack dllp,确认该dlp已经成功的被接受,才会删除这个备份。如果接收方发现tlp存在错误,则会向发送发发送nak dllp,然后发送方会从replay buffer中取出数据,重新发送该tlp。
ack/nak机制内部的详细结构图如下图所示:
下面对图中的各个elements分别做一个简单地介绍。
首先是发送端的elements:
来个大图特写:
next_transmit_seq counter
next_transmit_seq counter,即nts计数器,是一个12位的计数器。当数据链路层处于dl-down状态或者复位时,该计数器会被初始化为0。该计数器只会执行加一操作,也就是说当其到达最大值4095时,在进行加一操作则会变成0(roll over)。该计数器用于产生下一个待发送的tlp的序列号(sequence number)。每一个序列号都是与一个tlp所唯一对应的,可以说这个序列号正是整个ack/nak机制的关键。
lcrc generator
lcrc产生器用于产生一个32位的crc值,其作用于整个tlp和其对应的序列号。
replay buffer
replay buffer是mindshare书中的叫法,在pcie spec中,这个buffer的名称叫做retry buffer。replay buffer中按照传输顺序,存储了整个tlp、序列号和lcrc,如下图所示:
当发送端收到来自接收端的ack dllp时,会将buffer中相应的tlp(包括对应的序列号和lcrc)移除;如果接收到的是nak dllp,则会将buffer中响应的tlp(包括对应的序列号和lcrc)重新发送给接收端。
replay_timer count
replay_timer是一种看门狗定时器,当该定时器溢出,则表明发送端已经发送了一个或者多个tlp,但是并未收到来自接收端的应答信号(ack/nak)。此时,发送端会将replay buffer中的tlp重新发送,并将看门狗定时器重启。
只要发送端发送了任何tlp,该定时器便会启动,在接收到来自接收端的应答信号之前都会持续地运行。当收到应答信号之后,定时器会立即被清零。此时如果replay buffer仍然有tlp(表明还有tlp被发送,但是仍未得到应答),定时器又会被立即被重新启动。如果buffer中是空的,则定时器不会被重新启动,直到新的tlp被发送。
replay_num count
这是一个2位的计数器,用于记录同一个tlp发送失败的次数,当其值从11b变为00b时(溢出了,表示尝试发送某个tlp失败了4次),数据链路层会自动地强制物理层重新进行链路训练(即ltssm进入recovery状态)。当完成链路训练之后,便会重新发送之前发送失败的tlp。
当发送端接收到来自接收端的nak dllp或者发送端的看门狗定时器(replay_timer)溢出时,该计数器都会被加一;当接收到ack dllp时,该计数器则会被清零。
ackd_seq
ackd_seq寄存器用于存储最近接收到的ack或者nak dllp中的序列号。当复位或者数据链路层处于无效状态时,该寄存器会被初始化为全1。关于ackd_seq寄存器的具体用法会在后续的文章中,用例子的形式详细说明。
dllp crc check
接收端在接收到来自发送端的dllp后,首先会检查其dllp crc,如果发现有错误,则会直接将其丢弃,认为其实无效的dllp。
然后是接收端的elements:
首先来一张大图特写:
lcrc error check
顾名思义,lcrc error check用于检查接收到的tlp是否存在错误。如果存在错误,则将对应的tlp直接丢弃,然后产生一个nak dllp发送给发送端,让其重新发送该tlp。
next_rcv_seq
next_rcv_seq是一个12位的计数器,即next receive sequence number,其值为已经成功接收的tlp的序列号加1。主要用于检查当前接收到的tlp是不是应该接收到的tlp。
如果next_rcv_seq和当前接收到的tlp中的序列号的值相等,则认为这是一个有效的tlp,但是接收端并不会立即向发送端发送ack dllp,而是等到acknak_latency_timer溢出时才向发送端发送ack dllp。也就是说,一个ack dllp可能会对应多个tlp,接收端不会每成功接收到一个tlp便向发送端发送ack dllp。
如果当前接收到的tlp中的序列号小于next_rcv_seq(且差值不超过2048),则认为该tlp之前已经成功发送过了,此次是重复发送。需要注意的是,pcie spec认为重复发送并不是一个错误,只是直接将该tlp丢弃,并没有nak或者error reporting,但是会返回一个包含有上一次成功接收的tlp的序列号(nrs-1)的ack dllp给发送端。
如果当前接收到的tlp的序列号大于next_rcv_seq,表明传输过程中漏掉了一些tlp。此时,接收端会返回nak dllp,并直接丢弃该tlp。
一个简单的例子如下图所示:
nak_scheduled flag
nak_scheduled是一个标志位,当接收端产生nak dllp时,该标志位会被置位。当接收端成功接收到有效的tlp时,该标志位会被清零。需要特别注意的是,当该标志位处于置位状态时,接收端不应产生其他的nak dllp。
acknak_latency_timer
acknak_latency_timer定时器会在接收端成功接收到有效的tlp,且并未向发送端返回ack dllp之前运行。当acknak_latency_timer定时器溢出时,接收端会立即向发送端返回ack dllp(携带的序列号为nrs-1,即一个ack对应多个有效的tlp)。无论接收端返回ack还是nak,该定时器都会被复位,但是只有当接收端再次收到有效的tlp时,该定时器才会被重新启动。
该定时器(replay_timer)的值是由pcie spec规定的和lane的数量与max_payload有关,gen1的值如下图所示:
gen2(5gt/s)如下图所示:
注:该定时器(replay_timer)的值是acknak_latency_timer定时器值的三倍。
ack/nak generator
显然,ack/nak generator的功能是产生ack或者nak dllp。其格式如下:
最后,介绍一下pcie spec中推荐的包优先级顺序。我们知道,pcie总线通信中,存在多种类型的包,包括tlp、dllp和ordered sets等。为了能够是总线达到最优的传输效率,pcie spec推荐对这些包的优先级做如下的设置:(当然这只是推荐,并没有强制厂商一定要这要去实现)。
桥接模式应用场景
直男们首选配色: vivo X9磨砂黑版闪亮登场
昕诺飞2019H1财报公布,家居照明势头强劲
jquery插件开发实例(MSBar2D图效果、手风琴特效插件)
荣耀又放大招了根本停不下来,30分钟充电90%,八曲面设计强悍来袭!
Ack/Nak机制详细介绍
如何为公共场所提供高效防疫防控手段,应用人脸识别测温一体机
国内首颗微显LCOS芯片实现量产
EDA顶层丝印层怎么画
WDM-PON承载5G应用场景和技术的研究
关于霍尼韦尔医疗解决方案的介绍
集成波导与LCD屏的3D打印镜片的开发集成哪些了专利技术?
边缘计算平台是什么配置的
罗德与施瓦茨率先实现全方位的5G NR Release 17功能
布局2013连接器市场 欧美日原厂频频出招
小米手机Android 10的推送已经安排上了!
前员工谈格力:我们不满只能骂董大姐来发泄 但是格力不能没有她
为什么卫生间要装等电位?
linux查找ip地址的三种方法
PLC无线监控短信报警巨控GRM230系列GRM232Q接线电气图详解说明