調試 intel 82580網卡在intel 8632 switch下掃不到的問題的收穫

最近在調試intel 82580這款網卡在8632 switch下掃不到的問題。耗時了三個星期的時間,在這個過程中真的是學到了很多,所以還是決定將這些都記錄下來吧。因爲漫漫長河中,我們終將會將一些事遺忘。

問題現象

硬件環境:

           G1控制器(00:11:00)
                |
           8632橋(03:00:00)
                |
   --------------------------------------------------------------------------------------------
   |  (04:00:00)       |(04:04:00)           |(04:05:00)                      |(04:06:00)
8632橋                   8632橋                    8632橋                                8632橋
                                                                   |
                                                               82580網卡(07:00:00)

在上面的硬件連接方式下,82580這個設備在pci 掃描枚舉設備的時候,就是掃不到它。讀出來的Vendorid和deviced都是0。我們換了一個插槽,將82580這個卡插到我們pcie控制器直接相連的插槽就沒有問題了。同樣我們在(04:05:00)這個插槽的位置插一個其他的網卡或者其他設備都是可以掃到的。所以這個問題的現象真的很詭異。

注意:上面的G1控制器是我們橋片內部集成的pcie控制器,它在我們的系統上的設備id是(bus:0,device:17,Func:0),它的下面接了一個Intel 8632的透明橋。這個橋下面又擴展出了4個8632的透明橋,每一個橋外接出一個pcie插槽。方便我們來接設備,其實在上面的現象中,82580接到哪一個8632的橋轉接出來的插槽上都是掃不到的。上面每一個設備的設備id都是pci在枚舉設備過程中爲其分配的bus號,device號和function號。pci總線在枚舉設備過程中,是以深度優先算法遍歷設備的,這裏不再詳細的介紹遍歷設備的過程,相信調試過pci設備的人都熟知他的過程。

嘗試的解決辦法

首先復現這個問題之後,我的第一直覺就是我們的pcie控制器也就是上面的G1控制器的配置哪裏不對導致,所以就按照這個方向去追查。幸好我們還有另外一套軟件pmon,在pmon上面是沒有問題的。無論插到上面的哪一個插槽都是可以掃到的。因此就對比G1控制器相關的phy寄存器,配置寄存器以及其他的相關的寄存器的配置在uefi和pmon中配置的差異。在pmon中,所有的初始化都是通過彙編代碼來實現的。然後就開始了對比寄存器的過程。

在BIOS下和內核下依次讀取G1控制器的配置在pmon和uefi下的區別

用ejtag在pmon和uefi在進內核之前讀取G1控制器相關的寄存器,看看有什麼差異,然後對比差異寄存器,將uefi中配置的值修改成pmon的值,但是沒有效果。都修改成一樣的之後,內核下還是掃不到。爲了確保萬無一失又將所有的pcie控制器的寄存器都對比了一下(F0-G1)都對比了,將不一致的地方修改爲一致後,還是沒有效果。這個時候開始懷疑是pci掃描部分代碼差異導致,因爲在pci掃描過程中,會對pci設備的標準配置頭中的寄存器進行配置,有可能是這裏的差異。然後就開始對比配置空間的差異。

對比G1控制器及其下面的所有子設備的配置空間的值

pci設備的標準配置頭是64字節,pcie的是256字節。這裏我只對比了前64字節寄存器的值也就是從偏移0x0到0x40內的值,這個時候我發現所有的橋的command寄存器的第6和8bit不一致,查看pci規範,卻發現無關緊要。這裏設置的不一樣是由於pmon和uefi在pci掃描部分的代碼差異,對command寄存器的初始化不一致。
同時還發現(04:05:00)這個橋上面偏移0x20-0x23MemoryBase/MemoryLimit這兩個寄存器的值不一致。在pmon上面是分配了地址的,但是在uefi下面沒有。現在知道,這個寄存器分配的地址就是爲下游設備使用的,下游設備分配的pci memory空間就是從這個地址開始的。如果沒有發現下游設備,當然這裏不會有值。這裏需要注意,橋和普通pci設備的差異。普通pci設備,它自己的寄存器如果映射到memory空間,那麼映射的起始地址就是bar空間中的一個,具體使用的哪一個bar不一定。而橋的bar空間是映射的自己寄存器的值。如果是透明橋,bar0和BAR1是不需要寫地址的,不需要爲自己的寄存器分配映射的地址空間,一般透明橋是不需要配置什麼的。對比了這條鏈路上所有設備的標準配置頭,並將不一致的修改爲一致之後,還是沒有效果。現在標準配置空間修改爲一致後還是滅有效果,寄存器也都修改爲一致。實現沒有別的懷疑的地方了。後面就開始懷疑硬件信號的問題,但是是什麼導致硬件信號還不清楚。然後開始讀取pcie擴展配置空間的信息,看看是否在鏈路上就出錯了。
我們從擴展配置空間的信息中,看出了虛通道協商出錯了。這個錯誤是非常致命的錯誤。根據這個現象就知道爲什麼沒有掃到它下面插的82580網卡了。根據上面的狀態,猜測是pcie信號不好導致硬件鏈路協商的時候出現了問題,所以想通過將8632橋復位來看看是否有效果。

復位8632橋

根據8632使用手冊,可以通過橋的配置空間的Bridge COntrol寄存器的第22bit來複位這個橋以及其下游的設備,將這個bit寫1.硬件會自動完成復位操作,並且屬於hot reset。配置空間的寄存器不需要重新初始化。
這裏在uefi下添加這部分代碼,但是還是沒有效果。在掃描到這個橋以及 其下游設備的時候,如果掃不到,那麼就復位這個橋,然後繼續去掃這個橋下游的設備。添加了這麼個邏輯後,代碼就死循環在裏面了。一直處於復位掃描復位掃描的循環狀態。到這裏真的就束手無策了,不知道還能做什麼操作。開始懷疑我們這樣只操作這一個寄存器,可能並沒有真的復位,但是從手冊上卻找不到其他的復位的方法。所以準備開始從內核下手,看看內核中pci掃描部分時候有關於設備復位的函數,但是猜測有的可能性也不帶,因爲大多數復位操作都在具體的設備的驅動中完成的。pci bus層是不會有的。懷着僥倖的心裏去閱讀內核的代碼。
最後從內核的代碼中,也沒有找到爲什麼會掃不到這個設備。這時突發奇想可以將pmon的彙編移植到uefi中看看是否就會有效果呢?然後就開始將pmon的代碼往uefi中移植。

將pmon中的彙編移植到uefi中

由於pmon中這部分配置都是彙編實現的,而uefi是用C實現的,所以只能將這部分移植到uefi的start.s中,但是在初始化pci之前還有一部分7a初始化的代碼以及ht相關的代碼都一起移植過去了。移植過程中解決了很多編譯錯誤的問題,也學到了很多東西。移植完之後,發現真的就可以掃到了。所以現在確定這部分代碼彙編和C肯定是有差異的。然後就一點點的翻譯彙編代碼,又將這部分彙編從新翻譯成了C,但是發現還是不行。這種現象真的就很奇怪,反覆的對比代碼修改代碼還是不行。然後又只將C中的pci初始化的代碼替換爲彙編。發現這樣也是可以的。所以肯定就是這部分代碼的問題。然後就不斷的將彙編代碼才分成單獨的函數,然後一個函數一個函數的替換,到底是那個函數的問題。最後定位到了最簡短的函數。然後一點點的對比,發現彙編的延時和C中的延時不一致,最後將C中的延時函數加長就可以掃到了。最後定位爲延時不夠,導致初始化的狀態不穩所致。這種問題真的是很難猜到。延時不夠居然會影響這麼大。所以以後和硬件相交互的時候,一定要確保時間上要滿足硬件的要求,否則出現什麼奇怪的現象都不好說。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章