PCIe链路层里的ACK/NAK介绍

描述

编 者 按   

    读cocotbext-pcie源码,有部分牵涉到数据链路层。虽然自工作以来接触到PCIe还是蛮多的,但一般往往专注在TLP层,对于数据链路层还是接触的比较少的。PCIe Spec洋洋洒洒数千页,也不会从头到尾去通读整个协议。对于cocotbext-pcie里面牵涉到的链路层的ACK/NAK,牵涉到的PCIe背景,聊做记录。

    本文仅结合PCIe Spce与cocotbext-pcie做记录。

》ACK/NAK    

与TCP协议般,PCIe协议在数据链路层采用滑动窗口ACK/NAK协议来保证数据传输。对于传输层下发的TLP报文,数据链路层会做一次封装:

触发器

    ACK/NAK报文格式定义如下:

触发器

    关于滑动窗口机制,往上随便搜下还是蛮多的,不做过多啰嗦。链路层的滑动窗口正是基于TLP Sequence Number。   

TLP Sequence Number定义为12 bits。对于发送端而言,其会维护两个变量:

NEXT_TRANSMIT_SEQ:用于存储下一个待发送TLP报文所使用的TLP Sequence Number。初始化时赋值为0.

ACKD_SEQ: 记录从ACK、NAK中返回的 Sequence Number。初始化时赋值为0xfff。对于发送端,规定:(NEXT_TRANSMIT_SEQ - ACKD_SEQ) mod 4096 >= 2048

     若上面的条件满足则停止从传输层接收TLP,等待该条件不再成立。    

也就意味着在pending中的报文不超过2048(牵涉到报文重传)。    

那么由此发送端对于收到的ACK/NAK中协议牵涉到的处理流程Spec定义为:

触发器

    由于发送端窗口中pending待确认的报文不会超过2048,故若上面1式不成立,那么则意味着用到了尚未使用到的sequence,表示为错误的TLP报文,同样单次增加的ACKD也不会超过2048,否则也应标为错误的TLP。    

在式3中,如果条件不成立,则意味着可以窗口前移,可以从replay buffer中移出已发送成功的数据,设置ACKD_SEQ等变量。在cocotbext-pcie中关于dllp的处理也和spec保持一致:

触发器

    而对于接收端,其定义了:

NEXT_RCV_SEQ:下一个待接收TLP的Sequence Number。

    其处理流程为:

触发器

    这里可以看到,仅当收到的TLP报文的Sequence Number等于NEXT_REC_SEQ时,才会被接收。注意红框中,若条件满足则认为是重复的报文,此时则应发送ACK DLLP报文,否则认为是错误的报文,则应发送NAK。    

来看cocotbext-pcie中的处理:

触发器

    这里在563行取了<而非<=,或可有误。当收到的是期望的报文时(555行),则会更新next_recv_seq、清除nak_scheduled,拉起ack_latency_timer(不必每个TLP均发起一个ACK,但又要确保按照Spec中规定的间隔时间来发送ACK)。而如果收到的是一个重复的TLP(563行),此时将send_ack触发条件拉起,表示要立即发送ACK,而同时关掉ack_latency_timer,避免超时条件触发后多发ACK。否则(567行)将会发送NAK报文。

》One More Thing    

关于接收端的ack_latency,协议中有详细的规定,其与flow control定义有相似之处,放在后面结合cocotbext-pcie进行梳理。  




审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分