--- tags: I/O, System Software --- # PCI/PCIe(1): 基礎篇 ## Introduction ### PCI [Peripheral Component Interconnect(PCI)](https://en.wikipedia.org/wiki/Peripheral_Component_Interconnect) 是一種連接電腦主機板和外部裝置的匯流排標準。其取代了 [ISA](https://en.wikipedia.org/wiki/Industry_Standard_Architecture) 和 [VESA](https://en.wikipedia.org/wiki/Video_Electronics_Standards_Association),成為現代電腦中常見的標準。 特性上,PCI 是採同步傳輸(Synchronous transaction)。這意味著 PCI bus 只使用一個 clock。預設情況下,時脈運行在 33MHz,但允許更低到甚至 0MHz 以省電。如果硬體支援,則可以運行較高的 66MHz。 PCI 是 32 位元匯流排,採用 BURST 傳輸。所謂 BURST,意指傳輸的方式為: * 開始傳輸 * 第一個 clock cycle 用於指定 32 位元位址 * 之後的許多 clock cycles 用來傳遞資料 * 結束傳輸 在 BURST 傳輸下,每次傳遞資料時不重新指定位址,位址會在每個資料的 clock cycle 自動遞增。如果要改變位址,需停止目前的傳輸並重啟另一個新的。 PCI 的另一關鍵特性是隨插即用[("plug-and-play")](https://en.wikipedia.org/wiki/Plug_and_play)。Host 有能力確定 PCI bus 中每個 PCI 裝置的身份,例如製造商、功能等。也可以判斷每個 PCI 裝置需要多少記憶體空間、多少中斷等資訊。除此之外,可以重新分配/映射每個裝置的記憶體空間。 ### PCIe [Peripheral Component Interconnect Express(PCIe)](https://zh.wikipedia.org/zh-tw/PCI_Express),是電腦匯流排(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 的速度。  > [PCIe_vs_PCI](https://commons.wikimedia.org/wiki/File:PCIe_vs_PCI.gif) 截至撰文為止,各代的速度如下表所顯示:  > [PCI_Express](https://zh.wikipedia.org/zh-tw/PCI_Express) ## PCIe Connector 下圖展示了一個 1 lane 的 PCIe 的連結器(connector)。可以看到共有 36 個 Pin 腳,又分成上下個 18 個成為兩列。其中只有 6 個 pin 與傳輸資料有關(其他是電源或輔助信號)。分別是: * 一對 REFCLK * 一對 PER,與資料接收有關(receive) * 一對 PET,與資料發送有關(transmit)   > [fpga4fun: PCI Express - Connector](https://www.fpga4fun.com/PCI-Express1.html) 這些成對的訊號通稱為「[差分訊號(differential signal)](https://en.wikipedia.org/wiki/Differential_signalling)」。因為對中的兩個信號攜帶實際上攜帶相同的資料,但相位相反。其目的主要是為了傳輸的可靠性。 PCIe 可以通過使用多個 lane 來提升速度。由於 REFCLK pair 不需要重複,因此以具有 2 個 lane 的 PCIe 為例,需要使用 1 對 REFCLK + 2 對 PET + 2 對 PER。 ## PCIe Topology 如下圖是一個 [PCI Express(PCIe)](https://en.wikipedia.org/wiki/PCI_Express) topology:  > [PCI-SIG specifications](https://pcisig.com/specifications) 在 PCIe 系統中,有幾個關鍵名詞/角色: * Hierarchy 是含 Root Complex 的 port 上,以及通過 Switch、Bridge 關聯至 RC 上的所有裝置形成的網路,如上圖所呈現即是一個 Hierachy * [Root Complex(RC)](https://en.wikipedia.org/wiki/Root_complex) 是整個 I/O 架構的根節點,其將 CPU 和 memory subsystem 連接到 Switch 或 Endpoint,以構成 PCIe 的 Hierarchy * PCIe to PCI/PCI-X Bridge 提供 PCIe Hierarchy 和 PCI/PCI-X Hierarchy 之間的連結 * Switch 是多個虛擬 PCI-PCI bridge 的邏輯組合 * Endpoint 在 topology 中是指一種 function,可以是 PCIe 任務的 requester 或 completer,又可分三種 * Legacy * PCIe * RCiEP 有了連接的機制,CPU 啟動後,Host 會試著去讀不同的 bus 和 device numbers 之組合下的 function 0 之 VID/DID(DFS),若成功讀取就代表這個 BDF 下具有 device,這個流程被稱作 **Bus Enumeration/PCI Enumeration**。  從 bus -> device -> function 的 **BDF** 結構構成了每個 PCIe 設備節點的 identifier。 :::info 關於硬體相關基礎知識,由於非專案因此不多深入。更多詳細知識推薦閱讀以下文章: > [深入PCI与PCIe之一:硬件篇](https://zhuanlan.zhihu.com/p/26172972) ::: ## PCI Configuration Space PCI Configuration Space 和一般記憶體空間是分離的,通常我們會以 BDF 做為 PCI 裝置的唯一位址,並以此透過晶片廠商提供的方式存取 PCI Configuration Space。以 Intel 的晶片組為例,其使用 I/O 空間的 0xCF8 來設定 Configuration Address Register 來決定要存取的 BDF(參照下圖),然後再以 0xCFC 位址來讀取或寫入 Configuration Data Register 以得到想存取的 Configuration Space 內容。  > [[BIOS]PCI Read/Write](https://medium.com/@jacksonchen_43335/bios-pci-read-write-14356b013c43) 傳統的 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 欄位: * CMD (0x4): 一般情形下,Host會在 init controller 時將 BME 跟 MSE bit 設為 1 * BME : 允許 controller 能夠向 Host 發送 DMA Read/Write Memory request * MSE : 控制能不能存取 controller register * CC(class code, 0x9): 可用來判別 controller 類型為 NVMe * BAR: 透過讀寫 BARs 可以得知目標 function 需要的記憶體空間大小,並可藉其提供配置空間位址的資訊 * BAR0: – Memory Register Base Address, lower 32-bits * BAR1: – Memory Register Base Address, upper 32-bits * capability pointer(0x34): linked capability 那麼 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 Signaling ### Reapter 隨著 PCIe 的演進,傳輸速度也不斷提升,加上現代硬體設計更加複雜。在實際的硬體應用上,訊號的完整性問題成為一大問題。 為克服上述的訊號問題,可以在 CPU 和 Endpoint 之間加上 Repeater 以解決。Reapter 能做為一種訊號調節的裝置,以確保 Root complex 和 endpoint 之間的溝通品質。Repeater 又可以分為兩大類: Redriver 和 Retimer: * Redriver: 主要用於訊號增強,能夠增強 PCIe 訊號的強度和穩定性,補償訊號衰減,常用於較短距離的連接,如主機板內部 * Retimer: 不僅可以增強訊號,還能重整訊號、提供時脈並復原數據等功能。可以在長距離連接中恢復和補償傳輸時的時序失真,確保高資料率傳輸的品質 詳細可閱讀: > [車用PCIe中繼IC:訊號的穩定高速之旅](https://phisonblog.com/zh-tw/the-automotive-pcie-repeater-a-high-speed-journey-of-stable-signals/) ### Signal 在 PCIe 的傳輸上,訊號協議如下圖所呈現。  > [從硬體的角度,解析 PCIe 介面初始化](https://www.eagletek.com.tw/post/analyzes-pcie-interface-initialization-from-a-hardware-perspective) 除了傳輸資料(DATA Rx/Tx)的訊號以外,REFCLK 即參考時脈(reference clock),是 PCIe 可以傳輸資料的前提。PCIe 採用 100MHz 的 reference clock 以使在鏈結上的 PCIe 裝置可以高速的交換資料。 此外,有三個重要的控制訊號: * PERST#: PERST# 被稱基礎復位(fundamental reset),該訊號要一直被拉低直到 power rail 和 reference clock 穩定,當鏈路初始化的開始,便由低電位轉為高電位,通常這也就意外著鏈路的初始化(Link Initialization)完成 * CLKREQ#: 與低功耗狀態的轉換有關。這是一個 active-low 並用來請求 reference clock 的訊號 * WAKE#: 與低功耗狀態的轉換有關。同樣是一個 active-low 訊號,用於將 PCIe 裝置從低功耗模式重置到運作(active)模式 ### Link Training 當鏈路上的所有裝置獲得電源與參考時脈後,PCIe 中的實體層會進行鏈路初始化(Link Initialization & Training)。 細節可參考 [PCIe Link Training Overview](https://www.ti.com/lit/an/snla415/snla415.pdf) 一文即影片。 ## 驅動程式介面 有關描述 PCI driver 的結構,以及如何註冊 PCI driver 的詳細說明,可參考以下資料: * [How To Write Linux PCI Drivers: pci_register_driver() call](https://docs.kernel.org/PCI/pci.html#pci-register-driver-call) ## Reference * [深入PCI与PCIe之一:硬件篇](https://zhuanlan.zhihu.com/p/26172972) * [深入PCI与PCIe之二:软件篇](https://zhuanlan.zhihu.com/p/26244141) * [原來 PCIe 技術原理這麼簡單!](https://www.gushiciku.cn/dc_tw/110022319) * [老男孩读PCIe之六:配置和地址空间](http://www.ssdfans.com/?p=8210) * [PCIe(一) —— 基础概念与设备树](https://r12f.com/posts/pcie-1-basics/) * [PCI Bus Subsystem](https://docs.kernel.org/PCI/index.html) * [Linux makes your PCIe topology visible in sysfs (/sys)](https://utcc.utoronto.ca/~cks/space/blog/linux/PCIeTopologyInSysfs) * [Fun and Easy PCIE - How the PCI Express Protocol works](https://www.youtube.com/watch?v=sRx2YLzBIqk) * [fpga4fun - PCI](https://www.fpga4fun.com/PCI.html) * [fpga4fun - PCIe](https://www.fpga4fun.com/PCI-Express.html)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.