試的實戰(zhàn)指南)
1. 從一根插槽說起PCIe的RC與EP到底在聊什么但凡做過板級調(diào)試、系統(tǒng)bring-up或者驅(qū)動開發(fā)的兄弟遲早都會撞上PCIe這堵墻。你手里可能有一塊FPGA加速卡、一張網(wǎng)卡、一顆NVMe盤或者干脆就是兩塊板子對著插結果上電之后系統(tǒng)里lspci什么都看不到或者看到了但速率死活協(xié)商不上去。這時候老手第一句話往往不是問“驅(qū)動裝了嗎”而是問“你這頭配的是RC還是EP”PCIePeripheral Component Interconnect Express本質(zhì)上是一個高速串行點對點互連總線它取代了早期PCI那種共享并行的總線結構。而RCRoot Complex根復合體和EPEndpoint端點是PCIe拓撲里兩個最基礎、也最容易被混淆的角色。簡單打個比方RC就像一棟大樓的物業(yè)總控室它掌管著整棵PCIe樹的枚舉、地址分配和對外通道EP則是樓里的一個個租戶設備比如網(wǎng)卡、顯卡、SSD控制器。租戶不能自己去改大樓的門牌號得等物業(yè)來分配——這個“分配門牌號”的過程就是PCIe枚舉。這個系列我打算把協(xié)議標準里那些真正影響實操的點掰開揉碎講。第一篇就聚焦RC和EP這兩種模式它們各自是什么、配置空間里哪些寄存器決定了身份、枚舉過程怎么走、為什么很多掉卡和降速問題最后都追到模式配置上。適合正在做FPGA PCIe開發(fā)、嵌入式系統(tǒng)bring-up、或者被AER報錯折磨的工程師參考。不管你是剛接觸PCIe的新手還是已經(jīng)調(diào)過幾輪鏈路的老兵這里面的細節(jié)應該都能對上你踩過的某個坑。2. RC與EP的角色定位與核心差異2.1 用“物業(yè)與租戶”理解PCIe拓撲PCIe的拓撲是一棵樹。樹根是RC樹干是Switch交換器樹葉是EP。RC是整個系統(tǒng)的“根”它通常集成在CPU或SoC內(nèi)部負責發(fā)起配置事務、管理地址空間、處理中斷。EP則是具體干活的設備它響應RC發(fā)來的配置讀寫、內(nèi)存讀寫和中斷請求。這里有個關鍵點RC是配置空間訪問的發(fā)起者RequesterEP是響應者Completer。在Type 0配置請求里RC通過配置讀寫去探測總線上有沒有設備、設備是什么類型、需要多少BAR空間。EP不能主動去枚舉別人它只能被動等待被枚舉。這就像物業(yè)可以挨家挨戶敲門登記租戶不能跑去敲物業(yè)的門要求登記自己。但現(xiàn)實里有個例外RC也可以作為Completer。當EP發(fā)起Memory Write或Memory Read比如DMA寫內(nèi)存RC要負責響應這些請求。所以RC和EP的身份不是絕對的“主”和“從”而是看誰在發(fā)起哪類事務。配置事務永遠是RC發(fā)起但內(nèi)存事務雙方都可能發(fā)起。2.2 RC模式的核心職責拆解RC模式下的設備核心職責有這么幾塊配置空間枚舉從Bus 0開始逐級掃描每個Device和Function讀取Vendor ID和Device ID判斷設備是否存在。地址空間分配根據(jù)EP的BARBase Address Register請求分配Memory空間和I/O空間現(xiàn)代PCIe基本只用Memory空間。中斷管理處理INTx傳統(tǒng)中斷和MSI/MSI-X消息中斷。事務路由把CPU發(fā)出的內(nèi)存訪問路由到正確的EP把EP的DMA請求路由到內(nèi)存。錯誤處理管理AERAdvanced Error Reporting寄存器記錄和上報鏈路錯誤。在FPGA開發(fā)里如果你用的是Xilinx的XDMA或者Intel的PCIe Hard IP通常IP核會提供一個“Root Port”配置選項。選了這個FPGA就扮演RC角色可以主動去枚舉掛在它下面的EP設備。這種場景常見于FPGA作為主控去管理下游的NVMe盤或者另一塊FPGA加速卡。2.3 EP模式的核心職責拆解EP模式下的設備職責相對“被動”但同樣關鍵響應配置請求正確返回Vendor ID、Device ID、Class Code、Header Type等信息。BAR空間聲明告訴RC“我需要多大的地址空間”等待RC分配。響應內(nèi)存讀寫處理RC發(fā)來的MMIO讀寫以及自己發(fā)起的DMA讀寫。中斷上報通過MSI/MSI-X或INTx向RC報告事件。鏈路訓練上電后與RC或Switch進行LTSSM鏈路訓練協(xié)商速率和寬度。EP模式是絕大多數(shù)外設的工作模式。你的網(wǎng)卡、顯卡、NVMe盤上電后都是EP。FPGA做加速卡時通常也配成EP插在主機板的PCIe插槽上由主機CPU的RC來枚舉它。2.4 一張表看清RC與EP的關鍵區(qū)別對比維度RCRoot ComplexEPEndpoint拓撲位置樹根樹葉配置事務角色發(fā)起者響應者枚舉能力主動掃描總線被動等待枚舉BAR空間通常不請求BAR或作為RC自身寄存器必須聲明BAR需求中斷角色接收中斷發(fā)起中斷典型載體CPU/SoC內(nèi)置、FPGA Root Port IP網(wǎng)卡、顯卡、NVMe、FPGA加速卡地址路由管理全局地址映射使用RC分配的地址常見問題枚舉失敗、資源不足掉卡、降速、AER報錯這張表建議存下來調(diào)試時對著看能快速定位問題出在哪一側(cè)。3. 配置空間與寄存器身份是怎么被“認出來”的3.1 Type 0和Type 1配置空間頭PCIe配置空間每個Function有4KB前256字節(jié)是PCI兼容區(qū)后面是PCIe擴展區(qū)。前64字節(jié)是配置空間頭分Type 0和Type 1兩種。Type 0用于EP設備。Header Type字段的bit 7為0。Type 1用于RC和Switch的端口。Header Type字段的bit 7為1。RC在枚舉時讀到Header Type bit 7為0就知道這是個EP可以給它分配BAR。讀到bit 7為1就知道這是個橋或RC端口需要繼續(xù)往下掃描次級總線。這里有個實操細節(jié)很多FPGA的PCIe IP核在配置成EP時Header Type默認就是0x00配置成RC時Header Type是0x01。如果你發(fā)現(xiàn)主機枚舉不到你的FPGA卡第一件事就是確認IP核的配置模式有沒有選錯。我見過不止一次有人把EP配成了RC結果主機掃不到設備查了半天驅(qū)動。3.2 BAR寄存器的請求與分配機制BAR是EP向RC“要地址”的窗口。EP在BAR里寫入全1然后讀回來RC就能知道這個BAR需要多大的空間。比如一個64位Memory BAR低4位是屬性位高位全1讀回來是0xFFFF_FFF0說明需要4KB空間。RC枚舉到EP后會讀取所有BAR的請求大小然后從系統(tǒng)地址空間里劃一塊給它。分配完成后RC把基地址寫回BAR。之后CPU訪問這個地址就會被路由到對應的EP。注意BAR空間大小必須是2的冪次方。如果你需要3KB空間實際得請求4KB。這是硬件限制不是軟件能改的。在FPGA EP設計里BAR的配置直接決定了主機能訪問你多少寄存器空間。常見做法是BAR0放控制寄存器BAR1放DMA描述符BAR2放大塊數(shù)據(jù)緩沖。每個BAR的大小和類型32位/64位、Memory/IO都要在IP核里提前配好綜合之后就不能改了。3.3 Capability結構里的關鍵信息配置空間里有一串Capability鏈表每個Capability有一個ID。對RC和EP來說幾個關鍵的Capability包括PCI Express CapabilityID 0x10里面有Device Type字段明確標識這是RC、Switch還是EP。還有Link Capabilities、Link Status、Link Control等寄存器鏈路速率和寬度就在這里。MSI CapabilityID 0x05消息中斷配置。MSI-X CapabilityID 0x11增強版消息中斷支持更多向量。Power Management CapabilityID 0x01電源管理。AER CapabilityID 0x01在擴展區(qū)高級錯誤報告。Device Type字段特別值得關注。它的編碼是0EP1Legacy EP4RC Integrated Endpoint5RC Event Collector6RC Integrated Endpoint Root Port9RC Root Port。如果你在調(diào)試時發(fā)現(xiàn)Device Type不對那模式配置肯定有問題。3.4 枚舉過程中RC如何“認人”枚舉過程大致是這樣的RC從Bus 0、Device 0、Function 0開始掃描。讀取Vendor ID如果是0xFFFF說明沒有設備跳到下一個Function。如果有設備讀取Header Type判斷是EP還是橋。如果是EP讀取BAR請求分配地址空間。如果是橋配置次級總線號繼續(xù)掃描下級總線。遞歸直到整棵樹掃描完畢。這個過程里RC需要維護三個寄存器Primary Bus Number、Secondary Bus Number、Subordinate Bus Number。它們決定了橋下面掛的總線號范圍。如果這三個值配錯了下游設備就會枚舉不到。實操心得如果你用FPGA做RC去枚舉下游EP發(fā)現(xiàn)只能看到第一級設備看不到Switch下面的設備大概率是Subordinate Bus Number沒配對。確保它大于等于所有下游總線的最大編號。4. 實操從零配置一個RC與EP通信鏈路4.1 場景設定與硬件選型假設我們要搭一個最小系統(tǒng)一塊FPGA做RC另一塊FPGA做EP兩塊板子通過PCIe金手指或線纜對接。目標是RC能枚舉到EP并且能通過BAR空間讀寫EP的寄存器。硬件選型上Xilinx UltraScale系列的PCIe Hard IP比較典型。RC側(cè)用XDMA IP配成Root Port模式EP側(cè)用XDMA IP配成Endpoint模式。兩塊板子各自有參考時鐘PCIe要求100MHz差分參考時鐘抖動要控制好。4.2 RC側(cè)IP核配置要點在Vivado里配置XDMA IP時RC模式的關鍵選項Mode選Root Port。Device Port Type選Root Port。Lane Width根據(jù)硬件選x1、x4、x8或x16。Max Link Speed選5.0 GT/sGen2或8.0 GT/sGen3。BAR配置RC側(cè)通常不需要大BAR但需要配置RC自身的寄存器空間。AXI接口RC側(cè)需要AXI Master去發(fā)起配置讀寫和內(nèi)存讀寫。配置完成后RC側(cè)的邏輯需要實現(xiàn)枚舉狀態(tài)機。Xilinx提供了示例設計但實際用的時候往往要自己改。枚舉狀態(tài)機的大致流程是等待鏈路訓練完成然后從Bus 0開始掃描讀Vendor ID分配BAR配置橋寄存器。4.3 EP側(cè)IP核配置要點EP側(cè)的XDMA配置Mode選Endpoint。Device Port Type選Endpoint。BAR0配成64位Memory BAR大小比如1MB用于控制寄存器。BAR1配成64位Memory BAR大小比如256MB用于DMA數(shù)據(jù)緩沖。MSI-X使能配置中斷向量表。Vendor ID和Device ID填你自己的ID別用默認的否則驅(qū)動可能認錯。EP側(cè)還需要實現(xiàn)配置空間的響應邏輯。XDMA IP會自動處理大部分配置請求但BAR的地址分配需要你在邏輯里配合。具體來說當RC寫B(tài)AR寄存器時IP會給出信號你需要把基地址存下來后續(xù)地址譯碼用。4.4 鏈路訓練與速率協(xié)商的觀察方法上電后第一件事是看鏈路有沒有訓練成功。在Vivado里可以通過ILA抓LTSSM狀態(tài)機的狀態(tài)。正常流程是Detect - Polling - Configuration - L0。如果卡在Polling說明參考時鐘或差分對有問題如果卡在Configuration可能是Lane映射不對。鏈路訓練成功后讀Link Status寄存器PCIe Capability里的偏移0x12看Negotiated Link Width和Current Link Speed。如果協(xié)商下來是x1 Gen1而你的硬件是x4 Gen3那就要查參考時鐘是否滿足要求。差分對是否接反。金手指或連接器是否有信號完整性問題。IP核的Lane配置是否和硬件一致。踩過的坑有一次兩塊板子對接鏈路死活只能到Gen1。查了半天發(fā)現(xiàn)是EP側(cè)的參考時鐘用了普通晶振抖動太大。換成專用時鐘芯片后直接協(xié)商到Gen3。PCIe對參考時鐘的要求比想象中嚴格。4.5 枚舉成功的驗證步驟枚舉成功的標志是RC能讀到EP的Vendor ID和Device ID。驗證步驟RC側(cè)發(fā)起配置讀讀Bus 0、Device 0、Function 0的Vendor ID。如果返回0xFFFF檢查鏈路是否訓練成功。如果返回正確ID繼續(xù)讀Header Type和BAR。給BAR分配地址寫回BAR寄存器。通過分配的地址讀寫EP的BAR空間驗證數(shù)據(jù)通路。在Linux下如果RC是主機CPU可以直接用lspci -vvv看設備樹。如果是FPGA做RC就需要自己寫邏輯去讀配置空間通過ILA或串口打印出來。5. 常見問題與排查技巧實錄5.1 掉卡問題的典型原因“掉卡”是PCIe調(diào)試里最讓人頭疼的問題之一。表現(xiàn)是系統(tǒng)運行一段時間后lspci里設備消失了或者驅(qū)動報設備無響應。常見原因電源問題EP側(cè)供電不足導致鏈路不穩(wěn)定。特別是FPGA加速卡功耗大電源紋波要控制好。參考時鐘抖動時鐘質(zhì)量差會導致鏈路誤碼率升高最終掉鏈路。信號完整性差分對阻抗不匹配、走線過長、過孔太多都會導致眼圖閉合。AER錯誤累積Correctable Error累積到閾值會觸發(fā)鏈路重訓練嚴重時設備掉出總線。散熱問題溫度過高導致SerDes工作異常。排查時先看AER寄存器Correctable Error和Uncorrectable Error分別是什么類型。如果是Receiver Error多查信號完整性如果是Bad TLP多查鏈路訓練參數(shù)。5.2 降速與降寬問題的排查思路降速Speed downgrade和降寬Lane downgrade通常一起出現(xiàn)。比如x4 Gen3的卡協(xié)商成x2 Gen1。排查順序確認雙方IP核的Max Link Speed和Max Link Width配置一致。檢查參考時鐘頻率和抖動。檢查差分對是否接反或虛焊。檢查Lane映射是否和硬件一致。有些板子Lane0和Lane1是反的IP核里要配Lane Reversal。用示波器看眼圖確認信號質(zhì)量。經(jīng)驗如果只有部分Lane降速比如x4里Lane2和Lane3沒起來重點查這兩對差分對的走線和連接器。如果是全部Lane都降速查參考時鐘和IP配置。5.3 AER報錯解讀與處理AERAdvanced Error Reporting是PCIe的錯誤報告機制。Correctable Error包括Receiver Error、Bad TLP、Bad DLLP、Replay Timer Timeout等。Uncorrectable Error包括Malformed TLP、Poisoned TLP、Completion Timeout、Unsupported Request等。處理AER報錯的思路Receiver Error物理層問題查信號完整性。Bad TLP/DLLP鏈路層問題可能是鏈路訓練參數(shù)不優(yōu)。Completion TimeoutEP沒在規(guī)定時間內(nèi)響應查EP邏輯是否卡死。Unsupported RequestRC發(fā)了EP不支持的請求查地址映射。在Linux下可以用lspci -vvv看AER寄存器或者用aer-inject工具注入錯誤做測試。5.4 枚舉失敗的快速定位表現(xiàn)象可能原因排查方法讀Vendor ID返回0xFFFF鏈路未訓練成功查LTSSM狀態(tài)、參考時鐘只能看到第一級設備橋的Subordinate Bus Number配錯檢查橋配置寄存器BAR分配失敗BAR請求大小超過可用空間查系統(tǒng)地址空間映射設備時有時無電源或時鐘不穩(wěn)定查電源紋波、時鐘抖動配置讀寫超時EP響應邏輯卡死查EP狀態(tài)機、Completion機制這張表建議打印出來貼在工位上遇到問題先對照排查。5.5 熱插拔功能的注意事項PCIe熱插拔Hot-Plug在服務器和存儲場景很常見。實現(xiàn)熱插拔需要Attention Button用戶按鍵請求插拔。Power Indicator指示電源狀態(tài)。Attention Indicator指示注意狀態(tài)。Slot Power Controller控制槽位電源。熱插拔的軟件流程是用戶按鍵 - 系統(tǒng)收到中斷 - 驅(qū)動卸載 - 電源關閉 - 用戶拔卡。插入時反過來。調(diào)試熱插拔時重點查Hot-Plug Capability寄存器里的各狀態(tài)位以及中斷有沒有正確上報。注意不是所有PCIe插槽都支持熱插拔。硬件上需要有Hot-Plug Controller軟件上需要驅(qū)動支持。FPGA做EP時如果要支持熱插拔IP核里要配置Hot-Plug相關寄存器。6. 從協(xié)議到實戰(zhàn)幾個容易忽略的細節(jié)6.1 配置空間讀寫的事務類型RC訪問EP配置空間用的是CfgRd0/CfgWr0Type 0或CfgRd1/CfgWr1Type 1。Type 0用于直接訪問EPType 1用于通過橋訪問下游EP。RC在枚舉時對Bus 0上的設備用Type 0對橋下面的設備用Type 1。這里有個細節(jié)Type 1配置請求里的Bus Number字段是目標設備的總線號。橋收到Type 1請求后如果目標總線號在它的Secondary和Subordinate之間就把Type 1轉(zhuǎn)成Type 0發(fā)到下游。如果不在就忽略或轉(zhuǎn)發(fā)給上級。調(diào)試時如果發(fā)現(xiàn)下游設備枚舉不到可以抓配置事務的TLP看Bus Number字段對不對。6.2 Memory BAR和IO BAR的選擇現(xiàn)代PCIe基本只用Memory BARIO BAR很少用了。Memory BAR分32位和64位。64位BAR占兩個BAR寄存器位置低4位是屬性高32位在下一個BAR里。選擇BAR類型時控制寄存器用小BAR比如4KB或8KB32位或64位都行。數(shù)據(jù)緩沖用大BAR比如64MB或256MB必須64位因為32位BAR最大只能到4GB地址空間。Prefetchable如果BAR空間支持預取設Prefetchable位。但要注意Prefetchable BAR不能有讀副作用。實操建議FPGA EP設計時BAR0放控制寄存器BAR2放DMA緩沖。BAR0用64位4KBBAR2用64位256MB。這樣主機驅(qū)動可以分別映射互不干擾。6.3 MSI-X中斷的配置與調(diào)試MSI-X比MSI更靈活支持更多中斷向量每個向量可以獨立配置地址和數(shù)據(jù)。配置MSI-X需要在配置空間里使能MSI-X Capability。分配MSI-X Table和PBA的BAR空間。驅(qū)動填寫每個向量的Message Address和Message Data。EP觸發(fā)中斷時向?qū)腁ddress寫入Data。調(diào)試MSI-X時常見問題是中斷收不到。排查MSI-X Enable位有沒有置1。Table里的Address和Data有沒有填對。EP有沒有正確發(fā)起Memory Write TLP。RC側(cè)的中斷控制器有沒有正確路由。在Linux下可以用cat /proc/interrupts看中斷計數(shù)確認中斷有沒有上來。6.4 鏈路訓練中的LTSSM狀態(tài)機LTSSMLink Training and Status State Machine是PCIe物理層的核心狀態(tài)機。主要狀態(tài)包括Detect檢測接收端有沒有設備。Polling發(fā)送訓練序列協(xié)商極性。Configuration協(xié)商鏈路寬度和速率。L0正常工作狀態(tài)。Recovery鏈路出錯后重訓練。L1/L2低功耗狀態(tài)。調(diào)試時如果鏈路起不來用ILA抓LTSSM狀態(tài)看卡在哪個狀態(tài)。Detect卡住查參考時鐘和差分對Polling卡住查極性Configuration卡住查Lane映射和速率配置。6.5 地址映射與路由的驗證方法RC需要維護一張地址映射表把CPU的物理地址映射到PCIe總線地址。EP的BAR被分配地址后CPU訪問這個地址RC就把請求路由到對應的EP。驗證地址映射的方法在RC側(cè)讀EP的BAR空間看能不能讀到預期值。用DMA從EP寫數(shù)據(jù)到RC內(nèi)存看數(shù)據(jù)對不對。檢查RC的地址譯碼邏輯確認沒有地址重疊。如果地址映射錯了輕則讀寫失敗重則寫到別的設備上導致系統(tǒng)崩潰。所以枚舉完成后一定要做地址空間的沖突檢查。7. 寫在最后一些個人體會PCIe的RC和EP模式看起來只是兩個配置選項但背后牽扯的是整個枚舉流程、地址分配、中斷路由和錯誤處理。我調(diào)過不少PCIe的板子最深的體會是協(xié)議標準里的每一個寄存器位都是有人踩過坑之后加上的。你忽略的那個bit可能就是別人熬夜查了一周的問題。新手常犯的錯誤是只關注IP核的配置界面不讀協(xié)議標準。但真正遇到詭異問題時最后還是要回到協(xié)議里找答案。比如為什么BAR大小必須是2的冪次方為什么配置空間前64字節(jié)的布局是那樣這些在協(xié)議里都有解釋。另外調(diào)試PCIe一定要有耐心。鏈路訓練、枚舉、地址分配、中斷每一步都可能出問題。建議按順序來先確保物理層鏈路訓練成功再搞枚舉再搞地址映射最后搞中斷和DMA。跳步調(diào)試只會讓你更迷茫。最后分享一個小技巧如果你手頭沒有PCIe協(xié)議分析儀可以用FPGA的ILA抓TLP。雖然不如專業(yè)分析儀方便但勝在成本低而且能看到IP核內(nèi)部的信號。抓TLP時重點看Header里的Type字段、Requester ID、Completer ID和Tag這幾個字段能幫你快速定位事務流向。