作者:高志凱
一次常規調試中發現上電后交換機多個口同時打流會導致卡死的現象,最后一步步分析問題出現的原因是位寬不夠導致的溢出。這讓我回想起團隊已經量產的某款芯片,也是因為某個寄存器位寬設置過小的原因,導致組播組設置的時候不能超過31,否則就會溢出,只能想辦法通過軟件來解決這個問題。這次出現問題的交換機是基于共享緩存的架構,希望后面引以為戒,設計每個小的寄存器時都要考慮全面。
背景
在使用verilog進行程序設計時,尤其需要注意數據位寬問題。當我們將程序燒入fpga的時候電路已經固定,不能像C語言那樣動態改變數組長度,因此數據位寬設計不恰當會引入意想不到的問題。例如我們使用二進制進行計數時,位寬為5的數據表示范圍為0-31,當數據為32時由于位寬不夠,實際顯示則為0,如果此時你需要對這個數進行大小判斷,那么可能會得到錯誤的結果。筆者在交換機功能調試、解決bug的過程中對此深有體會。
首先我們來看一下交換機對數據的處理流程,網絡測試儀發出的數據首先經過接口進入分流模塊,我們的交換機支持TT業務(時間觸發)和ET業務(普通以太網),本文就ET業務進行分析。以太網幀進入MAC核進行CRC校驗,
并將8位輸入數據轉32位輸出,轉換模塊將數據轉換為128位總線數據,并支持反壓。接著數據經過輪詢進入分組處理模塊,分組處理模塊一方面將數據幀傳入接收總線,另一方面根據幀信息提取結果和流分類信息將接受幀信息傳入入隊模塊進行邏輯入隊,邏輯入隊模塊管理著一個虛擬的存儲塊,每一個虛擬的存儲塊對應著真實的物理數據,也就是數據幀。緩存管理模塊根據入隊和出隊情況更新存儲塊信息,同時更新的還有隊列的長度等信息。數據幀出隊時首先由邏輯預出隊模塊根據優先級輪詢隊列,并給出出隊號,邏輯出隊模塊根據端口號查詢出隊信息,然后控制總線發送數據,數據經過轉換模塊轉32位然后經mac核輸出。
粗略了解了交換機的結構,言歸正傳,數據溢出為什么會導致交換機“假性卡死”?
現象
首先我們需要深入了解一下邏輯出隊預出隊模塊,這個模塊會產生出隊號,并將出隊號傳入schedule_dequeue模塊,然后schedlue_dequeue模塊根據出隊號獲得出隊幀首地址,并查詢虛擬塊地址,從而獲得數據的物理存儲地址,進行數據搬移。
現在我們說一下現象,上板時,交換機4個口接到testcenter,每個口打1Gbps數據流,固定幀長為64Bytes,其中1、2口打對流,3、4口打對流。當testcenter準備好后直接給交換機4個口同時打數據流,這時有兩個口正常工作,但是另外兩個口卡死,沒有幀出來。如果在一開始將數據流速率控制在90%,打一陣流之后在將4個口速率提升到100%,則不會出現上述卡死現象。我們經過分析,認為交換機是能夠處理每個端口1Gbps速率的數據流,否則另外兩個正常工作的隊列便無法解釋。那么問題出在哪里了?
我們根據經驗,首先對入隊和出隊關于幀長信息的更新,入隊與出隊產生沖突時隊列頭部和尾部信息的更新等等進行了檢查,經過仿真和對比更新數據,確實發現了一些小bug,本以為這就是最終bug,結果興沖沖的跑了一版程序去上板測試,發現還是上述現象!這說明我們沒有找到關鍵點。
發現問題
這里要為大家介紹一種調試代碼的方法,就是計數法。為了找出問題出在哪里,我們對邏輯入隊、物理入隊的各隊列幀數進行統計,將其與邏輯出隊、物理出隊的各隊列幀數進行對比。這時我們發現,邏輯入隊和物理入隊幀數目一致,
邏輯出隊和物理出隊幀數目一致,但是入隊和出隊數目不一致,兩者相差256,但是隊列里顯示有255個幀,這是由隊列門限決定的,那么其實有經驗的你就能大概猜到這個差值256有點問題。是的沒錯,問題就出在這里。
我們查看代碼發現,
這里的port_state_data_in_b會根據優先級更新相應隊列的幀數目,顧名思義,它的低8位代表的是優先級為0幀的數目。當入隊的隊列號為00并且入隊成功后,其低8位會加1,出隊成功則減1,上圖展示的便是出隊時的代碼。但是我們要知道,優先級為0的隊列最多有8個,因為隊列號是由{端口號,優先級}的形式組成的,也就是說一個優先級對應8個端口號。前面我們說了一個隊列的門限是256,也就是0-255。那么當優先級為0的a隊列已滿,這時優先級為0的b隊列再來一個幀,port_state_data_out_b的值就會達到256,由于其只有8位,所以port_state_data_out_b的值其實是0!這就很麻煩了,因為機器不夠智能,只能夠按照你的代碼按部就班的執行。
所以卡死的原因出來了,由于port_state_data_out_b溢出置0,導致pri_val一直為0,所以狀態機一直在進行一個循環,不能完成正常跳轉!而這個模塊提供了出隊號,當其沒有提供出隊號時,schedule_dequeue模塊就無法產生出隊指令,總線也沒辦法進行數據搬移,從而對外顯示為“卡死狀態”。
解決問題
發現了問題,解決起來就很簡單了,我們只需要將優先級對應的隊列計數器計數上限設置到八個端口的最大值2048即可,也就是12位的數據位寬。如下圖:
寫在最后,往往最微不足道的問題最不容易讓人發現。這個位寬不足所導致的問題筆者找了很久,檢查過很多模塊,雖然這其中發現了一些其他bug,但是解決這個大bug的過程卻是費時費力的,但是設計者在設計代碼時只需要認真考慮承載功能所需要的位寬,便能為后續調試減輕許多麻煩!原我們都養成一個良好的習慣。
編輯:hfy
-
以太網
+關注
關注
40文章
5449瀏覽量
172176 -
交換機
+關注
關注
21文章
2647瀏覽量
99868 -
Verilog
+關注
關注
28文章
1351瀏覽量
110190 -
C語言
+關注
關注
180文章
7613瀏覽量
137247
發布評論請先 登錄
相關推薦
評論