Ack/Nak是一種由硬件實現(xiàn)的,完全自動的機制,目的是保證TLP有效可靠地傳輸。Ack DLLP用于確認(rèn)TLP被成功接收,Nak DLLP則用于表明TLP傳輸中遇到了錯誤。
如上圖所示,發(fā)送方會對每一個TLP在Replay Buffer中做備份,直到其接收到來自接收方的Ack DLLP,確認(rèn)該DLP已經(jīng)成功的被接受,才會刪除這個備份。如果接收方發(fā)現(xiàn)TLP存在錯誤,則會向發(fā)送發(fā)發(fā)送Nak DLLP,然后發(fā)送方會從Replay Buffer中取出數(shù)據(jù),重新發(fā)送該TLP。
Ack/Nak機制內(nèi)部的詳細(xì)結(jié)構(gòu)圖如下圖所示:
下面對圖中的各個Elements分別做一個簡單地介紹。
首先是發(fā)送端的Elements:
來個大圖特寫:
NEXT_TRANSMIT_SEQ Counter
NEXT_TRANSMIT_SEQ Counter,即NTS計數(shù)器,是一個12位的計數(shù)器。當(dāng)數(shù)據(jù)鏈路層處于DL-Down狀態(tài)或者復(fù)位時,該計數(shù)器會被初始化為0。該計數(shù)器只會執(zhí)行加一操作,也就是說當(dāng)其到達最大值4095時,在進行加一操作則會變成0(Roll Over)。該計數(shù)器用于產(chǎn)生下一個待發(fā)送的TLP的序列號(Sequence Number)。每一個序列號都是與一個TLP所唯一對應(yīng)的,可以說這個序列號正是整個Ack/Nak機制的關(guān)鍵。
LCRC Generator
LCRC產(chǎn)生器用于產(chǎn)生一個32位的CRC值,其作用于整個TLP和其對應(yīng)的序列號。
Replay Buffer
Replay Buffer是Mindshare書中的叫法,在PCIe Spec中,這個Buffer的名稱叫做Retry Buffer。Replay Buffer中按照傳輸順序,存儲了整個TLP、序列號和LCRC,如下圖所示:
當(dāng)發(fā)送端收到來自接收端的Ack DLLP時,會將Buffer中相應(yīng)的TLP(包括對應(yīng)的序列號和LCRC)移除;如果接收到的是Nak DLLP,則會將Buffer中響應(yīng)的TLP(包括對應(yīng)的序列號和LCRC)重新發(fā)送給接收端。
REPLAY_TIMER Count
REPLAY_TIMER是一種看門狗定時器,當(dāng)該定時器溢出,則表明發(fā)送端已經(jīng)發(fā)送了一個或者多個TLP,但是并未收到來自接收端的應(yīng)答信號(Ack/Nak)。此時,發(fā)送端會將Replay Buffer中的TLP重新發(fā)送,并將看門狗定時器重啟。
只要發(fā)送端發(fā)送了任何TLP,該定時器便會啟動,在接收到來自接收端的應(yīng)答信號之前都會持續(xù)地運行。當(dāng)收到應(yīng)答信號之后,定時器會立即被清零。此時如果Replay Buffer仍然有TLP(表明還有TLP被發(fā)送,但是仍未得到應(yīng)答),定時器又會被立即被重新啟動。如果Buffer中是空的,則定時器不會被重新啟動,直到新的TLP被發(fā)送。
REPLAY_NUM Count
這是一個2位的計數(shù)器,用于記錄同一個TLP發(fā)送失敗的次數(shù),當(dāng)其值從11b變?yōu)?0b時(溢出了,表示嘗試發(fā)送某個TLP失敗了4次),數(shù)據(jù)鏈路層會自動地強制物理層重新進行鏈路訓(xùn)練(即LTSSM進入Recovery狀態(tài))。當(dāng)完成鏈路訓(xùn)練之后,便會重新發(fā)送之前發(fā)送失敗的TLP。
當(dāng)發(fā)送端接收到來自接收端的Nak DLLP或者發(fā)送端的看門狗定時器(REPLAY_TIMER)溢出時,該計數(shù)器都會被加一;當(dāng)接收到Ack DLLP時,該計數(shù)器則會被清零。
ACKD_SEQ
ACKD_SEQ寄存器用于存儲最近接收到的Ack或者Nak DLLP中的序列號。當(dāng)復(fù)位或者數(shù)據(jù)鏈路層處于無效狀態(tài)時,該寄存器會被初始化為全1。關(guān)于ACKD_SEQ寄存器的具體用法會在后續(xù)的文章中,用例子的形式詳細(xì)說明。
DLLP CRC Check
接收端在接收到來自發(fā)送端的DLLP后,首先會檢查其DLLP CRC,如果發(fā)現(xiàn)有錯誤,則會直接將其丟棄,認(rèn)為其實無效的DLLP。
然后是接收端的Elements:
首先來一張大圖特寫:
LCRC Error Check
顧名思義,LCRC Error Check用于檢查接收到的TLP是否存在錯誤。如果存在錯誤,則將對應(yīng)的TLP直接丟棄,然后產(chǎn)生一個Nak DLLP發(fā)送給發(fā)送端,讓其重新發(fā)送該TLP。
NEXT_RCV_SEQ
NEXT_RCV_SEQ是一個12位的計數(shù)器,即Next Receive Sequence Number,其值為已經(jīng)成功接收的TLP的序列號加1。主要用于檢查當(dāng)前接收到的TLP是不是應(yīng)該接收到的TLP。
如果NEXT_RCV_SEQ和當(dāng)前接收到的TLP中的序列號的值相等,則認(rèn)為這是一個有效的TLP,但是接收端并不會立即向發(fā)送端發(fā)送Ack DLLP,而是等到AckNak_LATENCY_TIMER溢出時才向發(fā)送端發(fā)送Ack DLLP。也就是說,一個Ack DLLP可能會對應(yīng)多個TLP,接收端不會每成功接收到一個TLP便向發(fā)送端發(fā)送Ack DLLP。
如果當(dāng)前接收到的TLP中的序列號小于NEXT_RCV_SEQ(且差值不超過2048),則認(rèn)為該TLP之前已經(jīng)成功發(fā)送過了,此次是重復(fù)發(fā)送。需要注意的是,PCIe Spec認(rèn)為重復(fù)發(fā)送并不是一個錯誤,只是直接將該TLP丟棄,并沒有Nak或者Error Reporting,但是會返回一個包含有上一次成功接收的TLP的序列號(NRS-1)的Ack DLLP給發(fā)送端。
如果當(dāng)前接收到的TLP的序列號大于NEXT_RCV_SEQ,表明傳輸過程中漏掉了一些TLP。此時,接收端會返回Nak DLLP,并直接丟棄該TLP。
一個簡單的例子如下圖所示:
NAK_SCHEDULED Flag
NAK_SCHEDULED是一個標(biāo)志位,當(dāng)接收端產(chǎn)生Nak DLLP時,該標(biāo)志位會被置位。當(dāng)接收端成功接收到有效的TLP時,該標(biāo)志位會被清零。需要特別注意的是,當(dāng)該標(biāo)志位處于置位狀態(tài)時,接收端不應(yīng)產(chǎn)生其他的Nak DLLP。
AckNak_LATENCY_TIMER
AckNak_LATENCY_TIMER定時器會在接收端成功接收到有效的TLP,且并未向發(fā)送端返回Ack DLLP之前運行。當(dāng)AckNak_LATENCY_TIMER定時器溢出時,接收端會立即向發(fā)送端返回Ack DLLP(攜帶的序列號為NRS-1,即一個Ack對應(yīng)多個有效的TLP)。無論接收端返回Ack還是Nak,該定時器都會被復(fù)位,但是只有當(dāng)接收端再次收到有效的TLP時,該定時器才會被重新啟動。
該定時器(REPLAY_TIMER)的值是由PCIe Spec規(guī)定的和Lane的數(shù)量與Max_Payload有關(guān),Gen1的值如下圖所示:
Gen2(5GT/s)如下圖所示:
注:該定時器(REPLAY_TIMER)的值是AckNak_LATENCY_TIMER定時器值的三倍。
Ack/Nak Generator
顯然,Ack/Nak Generator的功能是產(chǎn)生Ack或者Nak DLLP。其格式如下:
最后,介紹一下PCIe Spec中推薦的包優(yōu)先級順序。我們知道,PCIe總線通信中,存在多種類型的包,包括TLP、DLLP和Ordered Sets等。為了能夠是總線達到最優(yōu)的傳輸效率,PCIe Spec推薦對這些包的優(yōu)先級做如下的設(shè)置:(當(dāng)然這只是推薦,并沒有強制廠商一定要這要去實現(xiàn))。
-
ACK
+關(guān)注
關(guān)注
0文章
28瀏覽量
11144 -
PCIe
+關(guān)注
關(guān)注
15文章
1234瀏覽量
82584 -
NAK
+關(guān)注
關(guān)注
0文章
4瀏覽量
3722
原文標(biāo)題:【博文連載】PCIe掃盲——Ack/Nak 機制詳解(一)
文章出處:【微信號:ChinaAET,微信公眾號:電子技術(shù)應(yīng)用ChinaAET】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論