Peripheral Component Interconnect(PCI) 是一種連接電腦主機板和外部裝置的匯流排標準。其取代了 ISA 和 VESA,成為現代電腦中常見的標準。
特性上,PCI 是採同步傳輸(Synchronous transaction)。這意味著 PCI bus 只使用一個 clock。預設情況下,時脈運行在 33MHz,但允許更低到甚至 0MHz 以省電。如果硬體支援,則可以運行較高的 66MHz。
PCI 是 32 位元匯流排,採用 BURST 傳輸。所謂 BURST,意指傳輸的方式為:
在 BURST 傳輸下,每次傳遞資料時不重新指定位址,位址會在每個資料的 clock cycle 自動遞增。如果要改變位址,需停止目前的傳輸並重啟另一個新的。
PCI 的另一關鍵特性是隨插即用("plug-and-play")。Host 有能力確定 PCI bus 中每個 PCI 裝置的身份,例如製造商、功能等。也可以判斷每個 PCI 裝置需要多少記憶體空間、多少中斷等資訊。除此之外,可以重新分配/映射每個裝置的記憶體空間。
Peripheral Component Interconnect Express(PCIe),是電腦匯流排(bus)的一個重要分支。沿用既有的 PCI 概念及訊號標準,並且構建了更加高速的序列通訊(Serial communication)系統標準。目前這一標準由 PCI-SIG 組織制定和維護。PCIe 僅應用於內部互連。由於 PCIe 是基於既有的 PCI 系統,所以只需修改實體層而無須修改軟體就可將現有 PCI 系統轉換為 PCIe。
PCIe 標準的演進相當快速,也反映了該規格在計算機中重要的地位。與 PCI 是 shared bus 不同,PCIe 是點對點(point-to-point)的匯流排。這意味著每個裝置都有其專屬的連接,不像PCI 那樣共享 bandwidth。也因此與 33MHz 的 PCI 相比,GEN 1 的 PCIe 就可達 2.5GHz 的速度。
截至撰文為止,各代的速度如下表所顯示:
下圖展示了一個 1 lane 的 PCIe 的連結器(connector)。可以看到共有 36 個 Pin 腳,又分成上下個 18 個成為兩列。其中只有 6 個 pin 與傳輸資料有關(其他是電源或輔助信號)。分別是:
這些成對的訊號通稱為「差分訊號(differential signal)」。因為對中的兩個信號攜帶實際上攜帶相同的資料,但相位相反。其目的主要是為了傳輸的可靠性。
PCIe 可以通過使用多個 lane 來提升速度。由於 REFCLK pair 不需要重複,因此以具有 2 個 lane 的 PCIe 為例,需要使用 1 對 REFCLK + 2 對 PET + 2 對 PER。
如下圖是一個 PCI Express(PCIe) topology:
在 PCIe 系統中,有幾個關鍵名詞/角色:
有了連接的機制,CPU 啟動後,Host 會試著去讀不同的 bus 和 device numbers 之組合下的 function 0 之 VID/DID(DFS),若成功讀取就代表這個 BDF 下具有 device,這個流程被稱作 Bus Enumeration/PCI Enumeration。
從 bus -> device -> function 的 BDF 結構構成了每個 PCIe 設備節點的 identifier。
關於硬體相關基礎知識,由於非專案因此不多深入。更多詳細知識推薦閱讀以下文章:
PCI Configuration Space 和一般記憶體空間是分離的,通常我們會以 BDF 做為 PCI 裝置的唯一位址,並以此透過晶片廠商提供的方式存取 PCI Configuration Space。以 Intel 的晶片組為例,其使用 I/O 空間的 0xCF8 來設定 Configuration Address Register 來決定要存取的 BDF(參照下圖),然後再以 0xCFC 位址來讀取或寫入 Configuration Data Register 以得到想存取的 Configuration Space 內容。
傳統的 PCI 裝置的 Configuration Space 包含了 64 bytes 的 header space 和 192 bytes 的 capability space,加起來是 256 bytes。CPU 可以透過 BDF 加上 register offset 的方式來存取 I/O address space 讀取 PCI header。
而對 PCIe 而言,Configuration Space 擴展至 4096 bytes。剩餘的 (4096 - 256) bytes 必須以 Memory map I/O 進行存取。硬體上,因為有 root complex,如果 CPU 想讀 PCIe device 的數據,可以先讓 root complex 把數據從 PCIe device 讀到 CPU memory,然後 CPU 再從 memory 讀取數據即可;反之,如果 CPU 要往 device 寫數據,先把數據在 memory 中寫入,然後再通過 root complex 寫入 PCIe 即可。
包含裝置上的 RAM 和 ROM 也可能可以透過 MMIO 的方式進行操作。總結來說,即下圖所示:
下面我們特別說明幾個重要的 configuration 欄位:
那麼 MMIO 的映射位址該如何得知呢?
該 mapping 的位置需透過過 PCI header 的 BAR0 和 BAR1 取得。當 Host 準備配置空間時,對 BAR register 發送 write request,嘗試將所有 bit 寫為 1,PCIe 收到 request 後,因為 BAR 有些 bit 是 read only 的,我們可以從保持不變的值取得所需空間的信息。以上圖為例,寫完後
低 12 bits 沒改變,表示需要 mapping 的空間大小是 4KB,此外注意到低 4 bits 表示了該存儲空間的一些屬性。
隨著 PCIe 的演進,傳輸速度也不斷提升,加上現代硬體設計更加複雜。在實際的硬體應用上,訊號的完整性問題成為一大問題。
為克服上述的訊號問題,可以在 CPU 和 Endpoint 之間加上 Repeater 以解決。Reapter 能做為一種訊號調節的裝置,以確保 Root complex 和 endpoint 之間的溝通品質。Repeater 又可以分為兩大類: Redriver 和 Retimer:
詳細可閱讀:
在 PCIe 的傳輸上,訊號協議如下圖所呈現。
除了傳輸資料(DATA Rx/Tx)的訊號以外,REFCLK 即參考時脈(reference clock),是 PCIe 可以傳輸資料的前提。PCIe 採用 100MHz 的 reference block 以使在鏈結上的 PCIe 裝置可以高速的交換資料。
此外,有三個重要的控制訊號:
當鏈路上的所有裝置獲得電源與參考時脈後,PCIe 中的實體層會進行鏈路初始化(Link Initialization & Training)。
細節可參考 PCIe Link Training Overview 一文即影片。
有關描述 PCI driver 的結構,以及如何註冊 PCI driver 的詳細說明,可參考以下資料: