Linux PCI裝置驅動程式碼必須掃描系統中所有的PCI匯流排,尋找系統中所有的PCI裝置(包括PCI-PCI橋裝置)。系統中的每條PCI匯流排都有個編號number,根PCI匯流排的編號為0。系統當前存在的所有根匯流排(因為可能存在不止一個Host/PCI橋,那麼就可能存在多條根匯流排) 都通過其pci_bus結構體中的node成員連結成一個全域性的根匯流排連結串列,其表頭由struct list_head型別的全域性變數pci_root_buses來描述,我們在/linux-2.4.18/linux/drivers/pci/pci.c的38行可以看到如下定義:
Linux PCI初始化程式碼從PCI匯流排0開始掃描,它通過讀取"Vendor ID"和"Device ID"來試圖發現每一個插槽上的裝置。如果發現了一個PCI-PCI橋,則建立一個pci_bus資料結構並且連入到由pci_root_buses指向的pci_bus和pci_dev資料結構組成的樹中。PCI初始化程式碼通過裝置類程式碼0x060400來判斷一個PCI裝置是否是PCI-PCI橋。然後,Linux核心開始構造這個橋裝置另一端的PCI匯流排和其上的裝置。如果還發現了橋裝置,就以同樣的步驟來進行構建。這個處理過程稱之為深度優先演算法。PCI-PCI橋橫跨在兩條匯流排之間,暫存器PCI_PRIMARY_BUS和PCI_SECONDARY_BUS的內容就說明了其上下兩端的匯流排號,其中PCI_SECONDARY_BUS就是該PCI-PCI橋所連線和控制的匯流排,而PCI_SUBORDINATE_BUS則說明自此以下、在以此為根的子樹中最大的匯流排號是什麼。
問題是配置一個PCI-PCI橋的時候,並不知道這個PCI-PCI橋的subordinate bus number。那麼就不知道該PCI橋下面是否還有其他的PCI-PCI橋。即使你知道,也不清楚如何對它們賦值。解決方法是利用上述的深度掃描演算法來掃描每個匯流排。每當發現PCI-PCI橋就對它進行賦值。當發現一個PCI-PCI橋時,可以確定它的secondary bus number。然後我們暫時先將其subordinate bus number賦值為0xFF。緊接著,開始掃描該PCI-PCI橋的downstream橋。這個過程看起來有點複雜,下面的例子將給出清晰的解釋:
圖3 配置PCI系統 第一步
PCI-PCI橋編號--第一步
以圖3的拓撲結構為例,掃描時首先發現的橋是Bridge1。Bridge 1的downstream PCI匯流排號碼被賦值1。自然該橋的secondary bus number也是1。其subordinate bus number暫時賦值為0xFF。上述賦值的含義是所有型別1的含有PCI匯流排1或更高(<255)的號碼的PCI配置地址將被Bridge 1傳遞到PCI匯流排1上。如果PCI匯流排號是1,Bridge 1 還負責將配置地址的型別轉換成型別0(對於這裡說的型別0和型別1,請參考淺談(一))。否則,就不做轉換。上述動作就是開始掃描匯流排1時Linux PCI初始化程式碼所完成的對匯流排0的配置工作。
圖4 配置PCI系統 第二步
PCI-PCI橋編號--第二步
由於Linux PCI裝置驅動使用深度優先演算法進行掃描,所以初始化程式碼開始掃描匯流排1。從而Bridge 2被發現。因為在Bridge 2下面發現不再有PCI-PCI橋,所以Bridge 2的subordinate bus number是2,等於它的secondary bus number。圖4顯示了在這個時刻匯流排和PCI-PCI橋的賦值情況。
圖5 配置PCI系統 第三步
PCI-PCI橋編號--第三步
Linux PCI裝置驅動程式碼從匯流排2的掃描中回來接著進行掃描匯流排1,發現Bridge 3。它的primary bus number被賦值為1,secondary bus number為3。因為匯流排3上還發現了PCI-PCI橋,所以Bridge 3的subordinate bus number暫時賦值0xFF。圖5顯示了這個時刻系統配置的狀態。到目前為止,含有匯流排號1,2,3的型別1的PCI配置都可以正確地傳送到相應的總線上。
圖6 配置PCI系統 第四步
PCI-PCI橋編號--第四步
現在Linux開始掃描PCI匯流排3,Bridge 3的downstream。PCI匯流排3上有另外一個PCI-PCI橋,Bridge 4。因此Bridge 4的primary bus number的值為3,secondary bus number為4。由於Bridge 4下面沒有別的橋裝置,所以Bridge 4的subordinate bus number為4。然後回到PCI-PCI Bridge 3。這時就將Bridge 3的subordinate bus number從0xFF改為4,表示匯流排4是從Bridge 3往下走的最遠的PCI-PCI橋。最後,Linux PCI裝置驅動程式碼將4以同樣的道理賦值給Bridge 1的subordinate bus number。圖6反映了系統最後的狀態。