第 6 章 PCI

Peripheral Component Interconnect(PCI),週邊部件連接,是一個標準,描述的是如何將一個系統中
的週邊以一種結構化的,可控制化的方式連接在一起。PCI標準描述了系統週邊電子元件連接的方式,
和在該標準下週邊部件的行為規格。本章探討Linux核心如何初始化系統的PCI匯流排和PCI設備。
圖6.1 基於PCI匯流排的系統
圖6.1是一個基於PCI匯流排系統的例子的邏輯框圖。PCI匯流排和PCI bridge 負責將系統中的部件連接在一起。
CPU連在PCI匯流排0﹔在主PCI匯流排(PCI 0)上掛著視頻設備。PCI-PCI bridge ,一個特殊的PCI設備將主PCI
匯流排於次PCI匯流排(PCI 1)相連。用PCI規格的術語來講,PCI匯流排1被稱作PCI-PCI bridge 的downstream,
PCI匯流排0叫做 bridge 的upstream。在第二個PCI匯流排上,是系統的SCSI和Ethernet設備。這個PCI-PCI bridge ,
第二個PCI匯流排和其上的兩區塊設備在實體上都可以在一個PCI卡上。系統中的PCI-ISA bridge 支援ISA設備。
上圖所示ISA匯流排下掛著一個多功能I/O控制器,控制系統的鍵盤,滑鼠和軟碟。
6.1 PCI位址空間
CPU與PCI設備需要存取在它們之間共享的記憶體。設備驅動程式使用這片記憶體來控制PCI設備並用來傳
送信息。一般而言,這些共享記憶體中包含設備的控制和狀態暫存器。這些暫存器用來控制設備和讀
取設備的狀態。例如,PCI SCSI設備驅動程式讀取SCSI設備的狀態暫存器以探測該設備是否已就緒
可以將一個資料塊寫入SCSI磁碟。又例如,設備驅動程式可以在控制暫存器中寫入控制資料從而使
設備開始運轉在設備電源被開啟之後。
上述的共享記憶體可以是CPU的系統記憶體。但如果這樣的話,每次PCI設備存取記憶體時,CPU將被阻塞,
等待PCI設備存取的結束。一般而言,在某個特定時刻,只能一個系統部件存取一個特定的記憶體。
所以,上述方法會使系統性能降低。另外,允許系統的週邊不在一個良好的控制下存取主記憶體不
是一個好的方法。這將會是非常危險的事情。一個“淘氣”的設備可以使得系統非常不穩定。
因此,週邊一般擁有它們自己的記憶體空間。CPU可以存取這個空間。但是反之週邊存取系統記憶體必須
在DMA(Direct Memory Access)的控制之下。ISA設備可以存取兩種位址空間,ISA I/O(Input/Output
)和ISA memory。PCI可以有三種:PCI I/O,PCI memory和PCI Configuration空間。所有的這些位址
空間都可以被CPU所存取。其中設備驅動程式要使用PCI I/O和PCI memory空間。Linux核心中的PCI初
始化程式碼要用到PCI Configuration空間。
6.2 PCI 配置頭(Configuration Header)
圖6.2 PCI Configuration Header (配置頭)
系統中的每個PCI設備,包括PCI-PCI bridge ,都有一個配置資料結構在PCI Configuration位址空間中。
這個PCI Configuraton Header(配置頭)被系統用來定位和控制一個設備。至於這個資料結構具體
位於PCI Configuration空間的何處,依賴於設備位於PCI拓樸結構中的位置。例如,一個PCI視頻
(Video)卡插在PCI 母板(motherboard)上的一個PCI槽中,它的資料配置頭結構將會在一個地方﹔
如果被插在另一個地方,其資料配置頭將會位於PCI Configuration空間中的另外一個地方。當然,
這沒有關系。不論PCI設備和PCI bridge 在哪裡,系統都將檢測到,並使用它們的配置頭中的狀態和配置
暫存器來對它們進行配置。
一般來講,每個PCI插槽的PCI配置頭都位於在PCI Configuration空間的一個偏移量(Offset)處,
這個偏移量是與每個PCI插槽的位置順序相關的。例如,PCI板上的第一個PCI插槽的PCI配置在偏
移量0﹔第二個PCI插槽的配置在偏移256處(所有的配置頭的大小是256個位元)。系統中提供一
與硬體有關的機制,使得PCI配置程式碼可以試圖檢測在一個給定的PCI匯流排上所有可能的PCI配置
頭,從而知道哪個PCI插槽上目前有設備,哪個插槽上暫無設備。這是通過讀取配置頭上的某個
域而完成的(一般是“Vendor Identification" 域)。如果一個插槽上為空,上述操作會返回一些
錯誤返回值,如0xFFFFFFFF。
圖6.2所示的是一個完整的256位元的PCI配置頭資料結構。它包含下列資料域:
Vendor Identification(廠商標識)
一個唯一的數字標識描述一個PCI設備的出處。Digital的PCI廠商標識是
0x1011; Intel的是0x8086。
Device Identification(設備標識)
一個唯一的數字標識用來描述一個設備。例如Digital的21141快速Ethernet
網路卡有一個設備標識0x0009。
Status(狀態)
這個域給出一個設備的狀態。這個域的每個位的含義是由一個標準來定義的。
Command(命令)
系統通過在這個域中寫入資料來控制設備。例如,讓設備存取PCI I/O空間。
Class Code(設備類程式碼)
這個域用來標定一個設備的類型。每一種設備都對應一個標準的類。
如video(視頻),SCSI等等。SCSI設備的類碼是0x0100。
Base Address Registers(基位址暫存器)
這些暫存器用來決定和分配一個設備可用的存儲空間類型
(如,PCI I/O和PCI memory)大小和位置。
Interrupt Pin(中斷接腳)
在每個PCI卡上,有4個實體接腳可以傳送中斷信號到PCI匯流排上。其標準的
標號是A,B,C和D。這個”Interrupt Pin"域描述的是這個PCI設備正在用
那個實體中斷接腳。通常來講,對一個特定的設備,其使用的中斷接腳是
被固定好的。也就是說,每次系統重新啟動時,該設備使用同樣的中斷接
腳。這個信息使得中斷處理子系統知道如何管理這個設備的中斷。
(譯者注:請參閱中斷處理章節。注意PCI設備於ISA設備在中斷方面的區別)
Interrupt Line(中斷線)
設備的PCI配置頭資料結構的"Interrupt Line"域用來在PCI初始化程式碼,
設備驅動程式和Linux中斷處理子系統之間傳遞一個中斷處理。這個域中的
值對於設備驅動程式而言是無意義的,但其可以使得中斷例程正確地將一個
中斷從一個PCI設備傳遞(route)到Linux中相應的設備驅動程式的中斷處理
程式碼中。請參閱第七章關於Linux如何處理中斷。
6.3 PCI I/O 和PCI Memory 位址
設備使用這兩種位址空間來與其在Linux核心中運行的設備驅動程式進行通信。例如,
DECchip 21141 快速Ethernet設備映射其內部暫存器到PCI I/O位址空間中。從而其設備驅動程
序可以讀和寫這些暫存器來控制該設備。Video磁碟機經常使用大量的PCImemory空間來存放視
頻信息。
在PCI系統初始化完成,使用上述的”command“命令允許設備存取位址空間之前,系統不能存取
這塊位址。值得注意的是只有PCI配置程式碼才讀和寫PCI Configuration位址。Linux設備驅動程
序只能讀和寫PCI I/O和PCI memory位址空間。
6.4 PCI-ISA bridge
PCI-ISA bridge 通過將對PCI I/O和PCI memory位址空間的存取轉換到對ISA I/O和ISA memory位址空間
的存取來支援對ISA設備的支援。許多系統中含有一些ISA匯流排槽和幾個PCI匯流排槽。隨著時間的推
移,這種為了向後兼容的機器配置將會消失。系統將會只支援PCI系統。在ISA位址空間中(ISA
I/O和ISA memory),系統中的ISA設備的暫存器位址被固定在某個地方(自從早期的Intel 8080 PC開
始)。例如,一個$5000的基於Alpha AXP的電腦的軟碟控制器與早期的IBM PC的在ISA位址空間中
占據的是同一片位址。PCI規格(Specification)通過在PCI I/O 和PCI memory位址空間的低端為
ISA週邊的使用保留一片區域並通過PCI-ISA bridge 來將對這片保留的PCI位址空間的存取映射到對系統中
ISA位址的存取上。(譯者注:細心的讀者不難發現,這種通過加”Layer",或“映射”的方法在
電腦軟硬體系統中幾乎無處不見。系統就是這樣一層一層的抽像出更高的概念提供給更高的層使用,
直到用戶層,從而使得一切細節的復雜性變的越來越透明。)
6.5 PCI-PCI bridge
PCI-PCI bridge 是一種特殊的PCI設備。它將系統中的PCI匯流排粘合作一起。簡單的系統只有通常一個PCI
匯流排。一個PCI匯流排上可支援的PCI設備的數目是有限的。使用PCI-PCI bridge 可以解決上述問題,允許將更
多的PCI匯流排加入系統從而支援更多的PCI設備。這對於高性能的伺服器來說是非常重要的。Linux全
面地支援PCI-PCI bridge 機制。
6.5.1 PCI-PCI bridge :PCI I/O 和PCI memory 窗口
PCI-PCI bridge 只負責傳遞一部份對PCI I/O和PCI memory讀和寫的請求到downstream(請參見第一節)。例
如,圖6.1中,僅當讀和寫請求中的PCI I/O或PCI memory位址屬於PCI-PCI bridge SCSI或Ethernet設備時
PCI-PCI bridge 才將這些匯流排上的請求從PCI匯流排0傳遞到PCI匯流排1。其他的將被忽略。這種過濾機制可以
避免位址在系統中沒必要的繁衍。為了做到這點,每個PCI-PCI bridge 必須正確地被設置好它所負責的PCI
I/O和PCI memory位址的起始和大小。當一個讀或寫請求落在其負責的範圍之內,這個請求將被映射到
次一級的PCI匯流排上。系統中的PCI-PCI bridge 一旦設置完畢,如果Linux中的設備驅動程式存取的PCI I/O
和PCI memory位址只在這些窗口之內,這些PCI-PCI bridge 是不可見的(譯者注:窗口在這裡的含義是指每
個PCI-PCI bridge 都僅負責一定範圍的空間映射﹔上述原文是:"Once the PCI-PCI bridge s in a system
have been configured then so long as the Linux device drivers only access PCI I/O and PCI
Memeory space via these windows, the PCI-PCI bridge s are invisible.")。這是個很重要的特性
使得Linux PCI設備驅動程式開發者的工作容易些。然而,這也使得Linux配置PCI-PCI bridge 變的有點迷惑。
我們將在下面的章節中看到這一點。
6.5.2 PCI-PCI bridge :PCI配置周期(Configuration Cycles)和PCI匯流排計數方法(Bus Numbering)
圖6.3 PCI配置周期類型0
圖6.4 PCI配置周期類型1
既然CPU的PCI初始化程式碼可以存取那些不在主PCI匯流排上的設備,那麼必須存在一個機制使得這些 bridge 能
夠判斷是否將一個PCI配置周期從它們的(譯者住:它們指的是PCI-PCI bridge 設備)主介面傳遞它們的次介面。
所謂一個“周期”指的是一個出現在PCI匯流排上的一個位址。PCI規格(Specification)定義了兩種PCI配
置尋址格式﹔類型0和類型1。圖6.3和圖6.4所示分別是這兩種尋址類型。PCI配置周期類型0中不含有總
線號碼,被所有的設備當作針對目前這個PCI匯流排上的PCI配置周期。類型0位址中的31-11位被用來作為
設備選擇域。一種設計方案是每一位對應一個設備。在這種情況下,位11表示插槽0上的PCI設備。位12
表示插槽2上的PCI設備並以此類推。另一種方法是直接地將設備的插槽號碼寫入位31-11中。具體採用
哪種機制依賴於系統的PCI存儲控制器(memory controller)。
類型1的PCI配置周期位址中含有一個PCI匯流排號碼。當這種類型的配置周期(或命令)出現在一個PCI匯流排
上時,除了PCI-PCI bridge 之外,所有其他的PCI設備會將其忽略。所有”看見“配置命令類型1的PCI-PCI bridge
可能選擇將類型1的配置周期傳遞到其downstream PCI匯流排上或忽略之。選擇的決定依賴於PCI-PCI bridge 的
配置。沒一個PCI-PCI bridge 有一個主PCI匯流排介面號和一個第二PCI匯流排介面號。主匯流排介面是那個離CPU更
近的﹔第二匯流排介面是那個離CPU較遠的。每個PCI-PCI bridge 還擁有一個次級匯流排號碼。這個數目代表著在
這個PCI-PCI bridge 第二匯流排介面之下的所有PCI匯流排中的最大數。換種方式講,這個次級匯流排數目是這個
PCI-PCI bridge 的PCI匯流排downstream的最大數目。當一個PCI-PCI bridge 看見一個類型1 PCI配置周期時,
bridge 的行為如下:
* 忽略這個命令,如果指定的匯流排號碼不在第二和次級匯流排號碼之間。(包含邊界值)
* 將其轉換成類型0配置命令,如果指定的匯流排號碼是 bridge 的第二級匯流排介面。
* 將其(原封不動地)傳遞到第二級匯流排介面,如果指定的匯流排號碼大於該 bridge 的第二匯流排號
但小於或等於次級匯流排號。
因此,如果我們想存取在圖6.9中匯流排3上的設備1,我們必須從CPU產生一個類型1的PCI配置命令。 bridge 1
將原封不動地將此命令傳遞到匯流排1﹔ bridge 2將忽略此命令,但 bridge 3將接受這個命令並將其轉換成一個類型0
的配置命令,然後發送到設備1所在的PCI匯流排3上。
關於在PCI配置期間如何分配匯流排號碼依賴於具體的作業系統。然而不論什麼樣的分配方案,對系統中所
有的PCI-PCI bridge 來說,必須滿足下列要求:
”在PCI-PCI bridge 後面的所有PCI匯流排的編號必須在該 bridge 的第二匯流排介面號碼和次級匯流排號碼之間“
如果違反這個規則,PCI-PCI bridge 將不會正確地傳遞和翻譯類型1的PCI配置命令。系統將不能正確地發現和
初始化系統中的PCI設備。為了完成這個賦值方案,Linux依照一個特殊的順序來配置這些PCI設備。
從圖6.6開始我們描述了Linux PCI bridge 和匯流排的號碼賦值方案。並舉出了一個例子。
6.6 Linux PCI初始化
Linux PCI 初始化程式碼邏輯上分為三個部份:
PCI設備驅動程式
這個偽設備驅動程式從匯流排0開始查詢PCI系統並且定位系統中所有的PCI設備和 bridge 。它建立一個
可以用來描述這個PCI系統拓樸層次的資料結構鏈結串列。並且對所有的發現的 bridge 編碼。
PCI BIOS
這個軟體層提供在bib-pci-bios規格中描述的服務。雖然Alpha AXP不提供BIOS服務,在其Linux
版本中包含了相應的功能。
PCI Fixup
與特定系統相關的PCI初始化修補程式碼
6.6.1 Linux核心的PCI資料結構
圖6.5 Linux 核心PCI資料結構
當Linux核心初始化PCI系統時,它建立一些可以描述系統PCI拓樸的資料結構。圖6.5所示是反映圖6.1系統
的資料結構之間的關系。
每一個PCI設備(包括PCI-PCI bridge )用一個pci_dev資料結構來描述。每個PCI匯流排用一個pci_bus結構來描述。
這樣的結果是產生了一個PCI匯流排樹狀關系結構。每個PCI匯流排結構pci_bus下掛著在該匯流排上的PCI設備。
因為除了主PCI匯流排,匯流排0,PCI匯流排只能通過PCI-PCI bridge 來存取,每個pci_bus中含有一個指向其上的PCI
設備(PCI bridge )的指標(這些設備pci_bus結構用鏈結串列連在一起,如圖6.5)。一個PCI設備是其”父“PCI匯流排的
”孩子“。(請注意圖6.5中指標children)
圖6.5中沒有顯示出來的一個指標是pci_devices。它用來指向系統中所有的PCI設備。系統中所有的PCI設
備將其pci_dev資料結構加入到這個隊列中。這個隊列被Linux核心用來快速尋找系統中的PCI設備。
6.6.2 PCI設備驅動程式
PCI設備驅動程式並不是真正的,嚴格意義上的驅動程式。它是在系統初始化時被調用的一個作業系統函數。
PCI初始化程式碼必須掃描系統中所有的PCI匯流排,尋找系統中所有的PCI設備(包括PCI-PCI bridge 設備)。
它使用PCI BIOS程式碼來發現它正在掃描的PCI匯流排上的每個插槽上是否已有設備安裝。如果在一個插槽上發現
了一個設備,一個用來描述該設備的pci_dev資料結構將被創建並且加入到被pci_devices所指向的隊列中。
PCI初始化程式碼從PCI匯流排0開始掃描。它通過讀取”Vendor Identification"和"Device Identification"
來試圖發現每一個插槽上的設備(請參閱6.2)。
如果發現了一個PCI-PCI bridge ,則創建一個pci_bus資料結構並且連入到由pci_root指向的pci_bus和pci_dev
資料結構組成的樹中。PCI初始化程式碼通過設備類程式碼0x060400來判斷一個PCI設備是否是PCI-PCI bridge 。然後,
Linux核心開始構造這個 bridge 設備另一端的PCI匯流排和其上的設備。如果還發現了 bridge 設備,就以同樣的步驟來
進行構建。這個處理過程稱之為深度優先演算法。系統的PCI拓樸在廣度查詢之前,先進行深度優先尋找。
請參閱圖6.1,由上述演算法可知,在構造PCI匯流排0上的Video設備之前,Linux將首先構造PCI匯流排1和其上的
Ethernet和SCSI設備(譯者注:這裡的前提是:圖6.1中PCI-PCI bridge 所在的插槽號碼小於video卡所在的PCI插
槽的號碼)
當Linux查詢downstream PCI匯流排時,它必須構造PCI-PCI bridge 的第二級和次級匯流排編號的號碼。下面我們將對
此進行相信描述。
構造PCI-PCI bridge ---對PCI匯流排號碼進行賦值
圖6.6構造一個PCI系統:第一步
PCI-PCI bridge 要想正確傳遞對PCI I/O,PCI Memory或PCI Configuration位址空間的讀和寫請求,必須知道下
列信息:
Primary Bus Number(主匯流排號)
該PCI-PCI bridge 的緊接的upstream匯流排的編號。
Secondary Bus Number(第二級匯流排號)
該PCI-PCI bridge 的緊接的downstream匯流排的編號。
Subordinate Bus Number(次級匯流排號)
該 bridge 的downstream匯流排中最大的匯流排編號。
PCI I/O 和 PCI Memory 窗口
對於該 bridge 的所有downstream位址中的PCI I/O和PCI Memory位址空間的窗口的基址和大小。
存在的問題是當你想要配置一個PCI-PCI bridge 的時候,你不知道這個 bridge 的次級匯流排介面號碼。
你不知道該 bridge 下是否還有其他的PCI-PCI bridge 。即使你知道,也不清楚如何對它們進行賦值。
解決方案是利用上述講過的深度遞迴演算法來掃描每個匯流排。每當發現PCI-PCI bridge 就對它們進行賦值。
當發現一個PCI-PCI bridge 時,它的第二級PCI匯流排介面號可以被確定。然後我們暫時先將其次級匯流排介面
號賦值為0xFF。緊接著,開始掃描該PCI-PCI bridge 的downstream bridge 。這個過程看起來有點復雜。
但下面的例子將給出清晰的解釋。
PCI-PCI bridge 的賦值--第一步
以圖6.6的拓樸結構為例,掃描時首先發現的 bridge 是 bridge 1( bridge 1)。 bridge 1的downstream PCI匯流排
號碼被賦值1。自然該 bridge 的第二級匯流排號碼也是1。其次級匯流排號碼被暫時賦值為0xFF。上述賦值的含義是
所有類型1的含有PCI匯流排1或更高(<255)的號碼的PCI配置位址將被 bridge 1傳遞到PCI匯流排1上。如果PCI匯流排號
是1, bridge 1還負責將配置位址的類型轉換成類型0。否則,就不做轉換。上述動作就是開始掃描匯流排1時Linux初始化
程式碼所完成的對匯流排0的配置工作。
圖6.7 構造一個PCI系統:第二步
PCI-PCI bridge 的賦值--第二步
Linux使用深度優先演算法進行掃描。所以初始化程式碼開始掃描匯流排1。從而PCI-PCI bridge 2被發現。因為在 bridge 2
下面不再發現有PCI-PCI bridge ,所以 bridge 2的次級匯流排號是2,等於它的第二匯流排介面號。圖6.7顯示了在這個時刻
匯流排和PCI-PCI bridge 的賦值情況。
圖6.8 構造一個PCI系統:第三步
PCI-PCI bridge 的賦值--第三步
PCI初始化程式碼從匯流排2的掃描中回來接著進行掃描匯流排1。這時,另外一個PCI-PCI bridge , bridge 3,被發現。它的
主匯流排號被賦值為1﹔第二級匯流排號為3。因為匯流排3上還發現了 bridge ,所以 bridge 3的次級匯流排號被暫時
賦值0xFF。圖6.8顯示了這個時刻系統配置的狀態。到目前為止,含有匯流排號1,2和3的類型1PCI配置周期都可以被正確
地傳送到相應的匯流排上。
圖6.9 構造一個PCI系統:第四步
PCI-PCI bridge 的賦值--第四步
現在Linux開始掃描PCI匯流排3, bridge 3的downstream.PCI匯流排3上有另外一個PCI-PCI bridge , bridge 4。因此
bridge 4的主匯流排號的值為3。第二匯流排號為4。由於 bridge 4下面沒有別的 bridge 設備,所以 bridge 4的次級
匯流排號為4。然後初始化程式碼回到PCI-PCI bridge 3。這時就將 bridge 3的次級匯流排號從0xFF改為4,表示匯流排4
是從 bridge 3往下走的最遠的PCI-PCI bridge 。最後,PCI初始化程式碼將4以同樣的道理賦值給 bridge 1的
次級匯流排號。圖6.9反映了系統最後的狀態。
6.6.3 PCI BIOS函數
PCI BIOS函數是一些在所有平台上都通用的一些標準例程。例如,對於Intel和Alpha AXP系統,它們都一樣。
BIOS函數的存在使得CPU可以存取所有的PCI位址空間。
只有Linux核心程式碼和設備驅動程式可以使用這些函數。
6.6.4 PCI Fixup(補充或修補)
相對於Intel系統,Alpha AXP系統的PCI fixup程式碼要作更多的事情。對於Intel系統,基本上PCI fixup
什麼也不做。
對於Intel系統,系統的BIOS在啟動時,已經基本上將PCI系統構造好了。這使得Linux只需將配置映射過來
就好了。對於非Intel系統,Linux還需做如下構建:
*為每個PCI設備分配PCI I/O和PCI Memory空間。
*為系統中的每個PCI-PCI bridge ,配置相應的PCI I/O和PCI Memory位址窗口。
*為每個設備的配置頭產生“Interrupt Line"值﹔這些值控制設備的中斷處理。
下面我們講述上述行為的實現。
查詢設備所需的PCI I/O和PCI Memory空間大小
系統對每個找到的PCI設備查詢設備所需的PCI I/O和PCI Memory空間大小。為了做到這一點,每個基址
暫存器先全寫入1然後再讀。設備將在沒有用的位上返回0值。從而我們可以得知位址空間的大小。
圖6.10 PCI配置頭:基位址暫存器
基位址暫存器分兩種類型,以表示一個暫存器是位於PCI I/O空間或PCI Memory空間。這是通過暫存器的位
0來設置的。圖6.10所示是對應於PCI I/O和PCI Memory的兩種形式的基址暫存器。
為了探測一個給定的基位址暫存器要申請的位址空間的大小,可以通過上述先向暫存器寫入全1然後再讀取
的方法。返回值即是該基位址暫存器所申請的空間大小。這種設計還保証了所有的位址空間都是2的冪數從
而且是自然對齊的。
例如當初始化DECChip 21142 PCI快速Ethernet設備時,我們會知道它需要0x100位元的PCI I/O或PCI Memory
空間。Linux PCI初始化程式碼將負責分配這片記憶體。然後,21142的控制和狀態暫存器就可以在這些位址上被
存取。
為PCI-PCI bridge 和PCI設備分配PCI I/O和PCI Memory空間
像所有的存儲空間一樣,PCI I/O和PCI Memory空間也是非常有限的,或稀少的。PCI Fixup程式碼必須非常
有效地為每個設備分配其申請的空間。PCI I/O和PCI Memory必須以自然對齊的方式來被分配。例如,如果一
個設備申請0xB0位元的PCI I/O空間,它必須對齊在一個是0xB0倍數的位址上。另外,對任何一個 bridge ,其所需
要的PCI I/O和PCI Memory必須分別對齊4K和1M的邊界。由於一個 bridge 的所有的downstream設備的位址空間都必
須位於PCI-PCI bridge 的位址空間內,所以有必要提供一個有效的演算法來進行控制。
Linux使用的演算法依賴於由PCI設備驅動程式建立的匯流排/設備樹狀資料結構中的每個設備分配的空間。空間
是朝上增長的。系統使用一個遞迴演算法來掃描pci_bus和pci_dev資料結構。掃描從PCI匯流排的根開始
(其指標是pci_root)。具體的行為如下:
*分別依照4K和1M位元的邊界,調整目前的PCI I/O和PCI Memory的基址。
*對目前匯流排上的每個設備:
。分配PCI I/O和Memory空間
。相應調整全局的PCI I/O和PCI Memory基址
。使能(enable)設備使用被分配的空間
*遞迴地對該匯流排下面的所有匯流排進行空間分配。注意這會改變PCI I/O和PCI Memory基址。
*分別依照4K和1M位元的邊界,調整目前的PCI I/O和PCI Memory的基址。並且計算出目前
PCI-PCI bridge 的PCI I/O和PCI Memory空間窗口的基址和大小。
*將上一步驟計算出來的值對目前的PCI bridge 進行賦值。
*打開 bridge 的對PCI I/O和PCI Memory位址過濾功能。這意味著如果一個在 bridge 的主匯流排上的對
PCI I/O和PCI Memory 位址的尋址落在這個 bridge 的PCI I/O和PCI Memory窗口內,該尋址指令
將被傳遞到 bridge 的第二級匯流排上。
以圖6.1 PCI系統為例,我們給出PCI Fixup程式碼的工作如下:
校准PCI基址
PCI I/O在0x4000; PCI Memory在0x100000。這使得PCI-ISA bridge 將接受所有低於這些值的尋址,作為ISA尋
址周期。
Video 設備
這個設備需要0x200000位元的PCI Memory。因為為了和要求的空間大小對齊,我們從0x20000位址開始
分配0x200000空間。PCI Memory的基址移到0x400000。PCI I/O的基址還是0x4000。
PCI-PCI bridge
現在碰到了PCI-PCI bridge 並對其分配PCI記憶體。 注意在這裡我們不需要調整基位址。
Ethernet 設備
該設備為其PCI I/O和PCI Memory空間各要求0xB0位元。在PCI Memory的基址0x400000和PCI I/O的基址
0x4000的基礎上進行分配。結果是PCI I/O基址的值為0x40B0。PCI Memory基址為0x4000B0。
SCSI 設備
該設備要求0x1000 PCI Memory空間。系統依照對齊的要求,在0x401000的基礎上開始分配。從而PCI
Memory的基址被調整至0x402000。PCI I/O的基址不變。
PCI-PCI bridge 的PCI I/O和PCI Memory 窗口
現在來設置 bridge 的PCI I/O和PCI Memory的窗口大小。PCI I/O的窗口在0x4000與0x40B0之間。
PCI Memory的窗口在0x400000與0x402000之間。這將使得 bridge 匯流排上忽略對Video的尋址,而將傳遞對
SCSI和Ethernet的尋址。