【PCIE-3】---PCIE設備的枚舉掃描(經典好文)


前面兩個小節大致總結了下PCIE的基本知識,算是掃盲篇吧。本文主要總結PCIE設備的枚舉掃描過程,此部分才是PCIE模塊的重點,無論是在BIOS下還是系統驅動下都會用到。

按照國際慣例,先列問題:

 1. 系統如何判斷PCIE設備是否在位?

 2. 設備中的配置空間的數據一開始就有嘛?誰寫的?

 3. Bus號,Dev號,和Fun號與硬件有關系嘛?P

 4. Bridge和Device的區別?

 5. Device和Function的區別?

 6. 枚舉的流程是怎么樣的?

 

系統如何判斷PCIE設備是否在位

  BIOS代碼在枚舉設備的時候,會去讀每個設備的VID,如果讀到的是不是FFFF,則表示此位置有設備存在,若為FFFF,則表示設備不存在。DID&VID是出廠時就固定在PCIE設備配置空間中的數據,表示每個不同的設備,同理,我們在BIOS中也可通過判斷這個ID值來尋找指定的PCIE設備。

 

設備中的配置空間的數據一開始就有嘛?誰寫的?

  每個設備在出廠時,其配置空間中的值都有一些default值,枚舉該設備時為每個設備分配BDS號和內存資源時,會再寫入部分值。

 

Bus號,Dev號,和Fun號與硬件有關系嘛?硬件鏈接與BDS號的分配是否有關?

  這個問題很關鍵,我想應該大部分的同學都會弄得不是很清楚,筆者一直以為BDS號是在枚舉過程中全部由軟件分配的,但實際應該不是這樣的。與多個同事討論后,基本斷定:Dev和Fun號應該是和硬件設計有關系,也就是硬件就已經固定,軟件的枚舉過程是更多的是在分配Bus號。為什么這么說呢?這里要着重講解下:

  PCI是總線結構,而PCIE已經是點對點機構,這個點對點結構很重要,待會重點講到。首先先來看下一個典型的Pcie系統框圖如下:

                           

  從CPU出來,有一個Root Compex(RC),從PCIE設備斷端來看的,我更傾向於簡單的把這個RC理解為一個HostBridge,這樣可能大家都會理解的更加清楚。OK,從RC出來,最典型也是最簡單的結構就是一個Root Port和一個Endpoint設備直接組成一個點對點設備,重點來了哈,這里面我們僅僅掛載了一個端點設備,但當一個root port僅和一個EndPoint設備相連時,該EndPoint設備就需要一條Bus,我和同事討論了下,大致原因是從CPU出來的每個port都是一個Bridge,有一個Bridge就要對應一條Bus,即使該Bus下僅有一個Dev,也需要給他單獨分配一個Bus號。

  上面介紹了一個Root Port和一個EndPont設備相連時的情況,這是最典型的PCIE點對點結構,現在討論一個Port下掛載多個設備時要怎么做? 這種情況下一般就需要Switch了,Switch物理上一般是一個芯片,我更傾向於把他理解為一個分線器,RootPort對應一條Bus,該Bus由於Switch的存在可以掛載多個dev,也就是對應多個Dev的情況。

  那么問題中所說的每個設備的Dev和Fun是由硬件固定的是怎么回事呢?那加入這兩個固定,對於到軟件枚舉又如何對應呢?情況大致是這樣:

  a. Dev和Fun硬件固定,這個是由硬件決定,為何這樣定,后續我做實驗后貼數據上來,現在我們就這樣認為;

  b. 上面已經介紹了PCIE點對點結構,從一個Port出來即使僅有一個設備,也需要給該設備重新分配一條Bus。那么假設我插入了兩個設備,在沒有掛接到switch上時,這兩個設備正如上面所說,組成了root port - endpoint dev的兩個設備對,每個設備在枚舉時,都會被重新分配一條Bus號,這種情況不會沖突。

  c. 假如這兩個設備接在了同一個Switch上,原本應該是Switch屬於某個Bus下一個分線器,分別掛接來不同的設備,亦有不同的Dev和Fun。那么在這種情況下,如果Dev和Fun一致,枚舉軟件自動會把這Switch的兩個port再次當成一個與Root Port類似的port。每個Port也可當作一個Bridge來使用,由於兩個設備Dev和Fun一樣,所以會再給這兩個設備分配 兩個新的Bus號,以表示區別,其他的設備則按原計划枚舉掃描。大概是這樣的過程。

  這個說法不知道會不會顛覆部分人的認識,后續我會找個實際的PCIE設備插入不同設備來進行驗證,但就目前查閱的資料來看,應該是此過程!

 

Bridge和Device的區別?

  PCIE設備樹的實現,離不開Bridge,我個人更傾向於簡單一點去看帶着Bridge和Device,或許可以這樣說:Bridge是一條Bus的管理者,當你看到一個Bridge的時候,也會對應的有一條Bus。那Device就簡單的多了,簡單的一個終端設備。不過目前在我看來Bridge某種意義上也可以算的上一種Device

因為在枚舉掃描的時候,接下來掃到的這個是什么?你假設它為Bus1,Dev0,Fun0,然后發現有設備,去讀了配置空間的Header和ClassCode后才知道這是一個Bridge還是device,但實際上你已經假設它為一個Device了,不是嘛?哈哈

  這里對橋和設備的判斷是通過HeaderType和ClassCode來判斷的,如下:

  待添加:

 

Device和Function的區別?

  這個問題困擾了筆者很久的時間,其實真正弄懂了以后發現,可以不用鑽的太深,最大的疑惑是: Dev到底對應的是不是一個設備,Fun是不是這個設備的具體的一個功能?請教了好多人,每個人給的回復都不一樣。其實筆者后來總結部分情況下是這樣的,對於你插入的某個設備,其Function號對應的就是它不同的功能。

 

枚舉的流程是怎么樣的?

  又是一長串的知識掃盲,以上問題都是困擾了筆者許久的問題,因此單獨列出來,作下說明,希望能解答和我有同樣疑惑的你們。接下來就要進入正式的枚舉過程了,如下圖是枚舉之后的兩個圖,希望各位同學對着這兩個圖,來看這個過程,你就會知道枚舉到底是怎么回事了?

                                             

 1. 對CPU來說,最開始僅僅知道Bus0的存在,Bus0下面都有什么設備,PCIE樹是怎么樣的一概不知。因此首先從Bus0,Dev0(橋A)開始,先去讀Dev0中Fun0的DID&VID(一定是從Fun0開始),看其是否返回0,如果不為0則表示設備存在,繼續下一步。若返回FFFF,則Dev0中沒有Fun0(任何設備的第一種功能一定是0),因此該設備不存在,繼續探查Bus0,Dev1,Fun0

 2. Bus0,Dev0,Fun0存在,讀其Header寄存器的值為“1”,則表示這是一個PCI To PCI Bridge(橋B),每一個bridge對應一個Bus,那么接下來就開始填寫這個Dev0,Fun0的配置空間,將其總線號寄存器設置如下:

  Primary Bus Number = 0;                    以下簡稱為PBN

  Secondary Bus Nymber = 1;               以下簡稱為SBN   

  Subordinate  Bus Number = 1;            以下簡稱為SuBN 

  至此,橋B知道了他管理的下游的一條Bus,編號為1,下游最遠(也就是Bus號最大的那個Bus是1)

 3. 更新HostBridge的SuBN = 1

 4. PCIE設備掃描遵循深度優先法則,因此在進行Bus0其他Dev掃描之前,必須首先掃面Bus1

 5. 軟件讀取Bus1,Dev0,Fun0的DID&VID,若返回不為FFFF,則該設備存在。在此查看Header寄存器值為1,表名Bus1,Dev0,Fun0依舊是一個PCI to PCI Bridge,。且Bit7是0.說明橋C是單功能設備

 6. 至此開始設置橋C的總線號寄存器

  Primary Bus Number = 1;                  

  Secondary Bus Nymber = 2;               

  Subordinate  Bus Number = 2;        

  然后再更新橋A,橋B的 SuBN = 2

 7. 繼續延續深度優先法則,開始掃描橋C下管理的Bus2總線,首先讀取Dev0,Fun0的DID&VID,會發現結果與之前一直,Bus2,Dev0,Fun0設備存在,其Header寄存器值為1,表明又是一個PCI to PCI Bridge(橋D),bit7為0,說明橋D也是單功能設備。

 8. 設置橋D的總線號寄存器

  Primary Bus Number = 2;                  

  Secondary Bus Nymber = 3;               

  Subordinate  Bus Number = 3;        

  然后再更新橋A,橋B,橋C的 SuBN = 3

 9. 繼續深度優先法則,掃描橋D下的Dev0,Fun0, 發現DID&VID存在,則表示Bus3,Dev0,Fun0存在,查看其Header寄存器的值為0,表名是一台端點設備,不是在是Bridge,且Bit7是一台多功能,這就對應到某個具體設備的多個功能了,Bridge的話就僅有一個功能--橋接。

 10. 然后接着掃描Bus3, Dev0, Fun1-7,會發現僅有Fun1存在。

 至此基於深度掃描法則的一條支路掃描完畢,其實到這個地方大家應該就能發現,深度掃描的意思大概是什么了,簡而言之就是只要有Bridge就往下一直走,走到最后不是Bridge的那個點,PCIE設備樹的結構也是在這樣的基礎上完成的。

 

 11. Bus3掃面完畢后,枚舉軟件返回到上層Bus,也就是Bus2上的其他設備。之前已經掃描國Bus2 Dev0,Fun0,並且屬於這個分支的都已經掃描完畢,接下來要掃描Bus2,Dev1,Fun0. 同樣DID&VID存在,且Heade寄存器表明該設備是一個Bridge設備(橋E)。

 12. 設置橋E的總線號寄存器

  Primary Bus Number = 2;                  

  Secondary Bus Nymber = 4;               

  Subordinate  Bus Number = 4;        

  然后再更新橋A,橋B SuBN = 4

  這個地方要注意了,橋E是掛載Bus2下載設備,因此PBN = 2沒有問題,但是這個SBN = 4,SuBN = 4相比大家應該也不會有任何問題吧,截止到橋E(一個橋代表有一個Bus,編號分到Bus4),該分支下最遠的Bus應該就是到Bus4,所以這樣設置,但是再更新上游橋的SuBN就已經沒有橋C的了,這是為什么呢?  ---  因為橋C和E是不同的支路。而每次更新SuBN,我們僅僅更新同一條支路上的所有Bridge上的SuBN的值。

 13. Bus4(橋E)也分配好了,接下來掃描Bus4下的設備,首先就是Dev0,Fun0,其Header寄存器值為0表示是一台端點設備,bit7為0表示一台單功能設備,OK,已經到頭,且此Dev0沒有更多Fun,此條支路到此結束。

 

其他的支路掃描與上述過程類似,在此不再贅述。截至此,基本描述完PCIE設備的枚舉過程,過程還是比較簡單的,就是要結合很多硬件設計的知識,以及其這樣設計的初衷和原理,對此的了解會更加深刻一些!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM