一、PCI裝置BAR空間的初始化

在PCI Agent裝置進行資料傳送之前,系統軟體需要初始化PCI Agent裝置的BAR0~5暫存器和PCI橋的Base、Limit暫存器。系統軟體使用DFS演算法對PCI匯流排進行遍歷時,完成這些暫存器的初始化,即分配這些裝置在PCI匯流排域的地址空間。當這些暫存器初始化完畢後,PCI裝置可以使用PCI匯流排地址進行資料傳遞。

值得注意的是,PCI Agent裝置的BAR0~5暫存器和PCI橋的Base暫存器儲存的地址都是PCI匯流排地址。而這些地址在處理器系統的儲存器域中具有映像,如果一個PCI裝置的BAR空間在儲存器域中沒有映像,處理器將不能訪問該PCI裝置的BAR空間。

如上文所述,處理器通過HOST主橋將PCI匯流排域與儲存器域隔離。當處理器訪問PCI裝置的地址空間時,需要首先訪問該裝置在儲存器域中的地址空間,並通過HOST主橋將這個儲存器域的地址空間轉換為PCI匯流排域的地址空間之後,再使用PCI匯流排事務將資料傳送到指定的PCI裝置中。

PCI裝置訪問儲存器域的地址空間,即進行DMA操作時,也是首先訪問該儲存器地址空間所對應的PCI匯流排地址空間,之後通過HOST主橋將這個PCI匯流排地址空間轉換為儲存器地址空間,再由DDR控制器對儲存器進行讀寫訪問。

不同的處理器系統採用不同的機制實現儲存器域和PCI匯流排域的轉換。如PowerPC處理器使用Outbound暫存器組實現儲存器域到PCI匯流排域間的轉換,並使用Inbound暫存器組實現PCI匯流排域到儲存器域間的轉換。

而x86處理器沒有這種地址空間域的轉換機制,因此從PCI裝置的角度上看,PCI裝置可以直接訪問儲存器地址;從處理器的角度上看,處理器可以直接訪問PCI匯流排地址空間。但是讀者需要注意,在x86處理器的HOST主橋中仍然有儲存器域與PCI匯流排域這個概念。只是在x86處理器的HOST主橋中,儲存器域的儲存器地址與PCI匯流排地址相等,這種“簡單相等”也是一種對映關係。

1、 儲存器地址與PCI匯流排地址的轉換

下文根據PowerPC和x86處理器的主橋,抽象出一個虛擬的HOST主橋,並以此為例講述PCI Agent裝置之間,以及PCI Agent裝置與主儲存器間的資料傳送過程。

我們假設在一個32位處理器中,其儲存器域的0xF000-0000~0xF7FF-FFFF(共128MB)這段實體地址空間與PCI匯流排的地址空間存在對映關係。

當處理器訪問這段儲存器地址空間時,HOST主橋將會認領這個儲存器訪問,並將這個儲存器訪問使用的實體地址空間轉換為PCI匯流排地址空間,並與0x7000-0000~0x77FF-FFFF這段PCI匯流排地址空間對應。

為簡化起見,我們假定在儲存器域中只映射了PCI裝置的儲存器地址空間,而不對映PCI裝置的I/O地址空間。而PCI裝置的BAR空間使用0x7000-0000~0x77FF-FFFF這段PCI匯流排域的儲存器地址空間。

在這個HOST主橋中,儲存器域與PCI匯流排域的對應關係如圖3‑1所示。

當PCI裝置使用DMA機制,訪問儲存器域地址空間時,處理器系統同樣需要將儲存器域的地址空間反向對映到PCI匯流排地址空間。假設在一個處理器系統中,如果主儲存器大小為2GB,其在儲存器域的地址範圍為0x0000-0000~0x7FFF-FFFF,而這段地址在PCI匯流排域中對應的“PCI匯流排地址空間”為0x8000-0000~0xFFFF-FFFF。

因此PCI裝置進行DMA操作時,必須使用0x8000-0000~0xFFFF-FFFF這段PCI匯流排域的地址,HOST主橋才能認領這個PCI匯流排事務,並將這個匯流排事務使用的PCI匯流排地址轉換為儲存器地址,並與0x0000-0000~0x7FFF-FFFF這段儲存器區域進行資料傳遞。

在一個實際的處理器系統中,很少有系統軟體採用這樣的方法,實現儲存器域與PCI匯流排域之間的對映,“簡單相等”還是最常用的對映方法。本章採用圖3‑1的對映關係,雖然增加了映射覆雜度,卻便於讀者深入理解儲存器域到PCI匯流排域之間的對映關係。下文將以這種對映關係為例,詳細講述PCI裝置BAR0~5暫存器的初始化。

2、 PCI裝置BAR暫存器和PCI橋Base、Limit暫存器的初始化

PCI橋的Base、Limit暫存器儲存“該橋所管理的PCI子樹”的儲存器或者I/O空間的基地址和長度。值得注意的是,PCI橋也是PCI總線上的一個裝置,在其配置空間中也有BAR暫存器,本節不對PCI橋BAR暫存器進行說明,因為在多數情況下透明橋並不使用其內部的BAR暫存器。下文以圖3‑2所示的處理器系統為例說明上述暫存器的初始化過程,該處理器系統使用的儲存器域與PCI匯流排域的對映關係如圖3‑1所示。

在PCI裝置的BAR暫存器中,包含該裝置使用的PCI匯流排域的地址範圍。在PCI裝置的配置空間**有6個BAR暫存器,因此一個PCI裝置最多可以使用6組32位的PCI匯流排地址空間,或者3組64位的PCI匯流排地址空間。這些BAR空間可以儲存PCI匯流排域的儲存器地址空間或者I/O地址空間,目前多數PCI裝置僅使用儲存器地址空間。而在通常情況下,一個PCI裝置使用2到3個BAR暫存器就足夠了。

為簡化起見,我們首先假定在圖3‑2中所示的PCI匯流排樹中,所有PCI Agent裝置只使用了BAR0暫存器,其申請的資料空間大小為16M位元組(即0x1000000位元組)而且不可預讀,而且PCI橋不佔用PCI匯流排地址空間,即PCI橋不含有BAR空間。並且假定當前HOST主橋已經完成了對PCI匯流排樹的編號。

根據以上假設,系統軟體該PCI匯流排樹的遍歷過程如下所示。

(1) 系統軟體根據DFS演算法,系統軟體率先尋找到第一組PCI裝置,分別為PCI裝置31和PCI裝置32[1],並根據這兩個PCI裝置需要的PCI空間大小,從PCI匯流排地址空間中(0x7000-0000~0x77FF-FFFF)為這兩個PCI裝置的BAR0暫存器分配基地址,分別為0x7000-0000和0x7100-0000。

(2) 當系統軟體完成PCI匯流排3下所有裝置的BAR空間的分配後,將初始化PCI橋3的配置空間。這個橋片的Memory Base暫存器儲存其下所有PCI裝置使用的“PCI匯流排域地址空間的基地址”,而Memory Limit暫存器儲存其下PCI裝置使用的“PCI匯流排域地址空間的大小”。系統軟體將Memory Base暫存器賦值為0x7000-0000,而將Memory Limit暫存器賦值為0x200-0000。

(3) 系統軟體回朔到PCI匯流排2,並找到PCI匯流排2上的PCI裝置21,並將PCI裝置21的BAR0暫存器賦值為0x7200-0000。

(4) 完成PCI匯流排2的遍歷後,系統軟體初始化PCI橋2的配置暫存器,將Memory Base暫存器賦值為0x7000-0000,Memory Limit暫存器賦值為0x300-0000。

(5) 系統軟體回朔到PCI匯流排1,並找到PCI裝置11,並將這個裝置的BAR0暫存器賦值為0x7300-0000。並將PCI橋1的Memory Base暫存器賦值為0x7000-0000,Memory Limit暫存器賦值為0x400-0000。

(6) 系統軟體回朔到PCI匯流排0,並在這條總線上發現另外一個PCI橋,即PCI橋4。並使用DFS演算法繼續遍歷PCI橋4。首先系統軟體將遍歷PCI匯流排4,並發現PCI裝置41和PCI裝置42,並將這兩個PCI裝置的BAR0暫存器分別賦值為0x7400-0000和0x7500-0000。

(7) 系統軟體初始化PCI橋4的配置暫存器,將Memory Base暫存器賦值為0x7400-0000,Memory Limit暫存器賦值為0x200-0000。系統軟體再次回到PCI匯流排0,這一次系統軟體沒有發現新的PCI橋,於是將初始化這條總線上的所有PCI裝置。

(8) PCI匯流排0上只有一個PCI裝置,PCI裝置01。系統軟體將這個裝置的BAR0暫存器賦值為0x7600-0000,並結束整個DFS遍歷過程。