PCIe Chapter 3:從未知拓樸到完成裝置發現
【模擬資料】本章拓撲、Bus Number 與讀值為教學用途建立,不代表特定硬體或平台。
先看本章的角色與路徑
作者的教學拓樸;Bus Number 配置策略是示範,規格定義欄位及路由條件。
枚舉是由已知根部向下發現 Function 的過程。本章沿用前兩章的拓樸,先替橋接路徑建立可轉送的 Bus 範圍,再探查下游,最後記錄已找到的功能。
前情提要:Chapter 1 教你辨認 Port 與 Function;Chapter 2 教你在已知 Function 的設定空間中找欄位。現在要建立那些已知位置。
規格路線:Figures 7-1/7-2 的階層 → Figure 7-14 的橋接 Bus 欄位 → Figures 7-7/7-8 的身分與標頭。
枚舉要先建立可走的設定路徑,才能找到下游 Function。讀到某個值時,也必須分清有效身分、暫時未就緒,以及存取失敗。本章把 Bridge 的 Bus Number 配置與這些結果放在同一個流程中。
平台提供起點,Function 讀值提供下一步證據
系統先從平台取得 Host/Root Bridge 的 Segment、Bus 範圍與設定存取介面,不是任意掃描實體記憶體。Root Bridge 的平台介面與 Root Port 的對外 Link 角色不同。Firmware 3.3 要求韌體配置所有 Host Bridge,讓 OS 能處理其下游裝置。
探查 Function 時,Vendor ID 是規格建議的存在性線索,FFFFh 表示沒有 Function。但軟體可見資料不等於 Completion payload:對依賴全 1 回覆的軟體,Root Complex 會把 Configuration Request 的 UR 結果合成全 1。讀取失敗或路徑尚未建立,則不能只憑任意 buffer 值判定實體卡不存在。
來源
Firmware 3.3 §3.1.1,p.32;§3.5,pp.34–35。Base 6.0 Vendor ID:§7.5.1.1.1,p.917;未實作目標與 UR:§7.3.1,p.911;全 1 資料合成:§2.3.2,p.221。
0xFFFF0001 不是一般的 Vendor/Device ID
RRS(Request Retry Status)是 Base 6.0 用來表示指定情況下暫時不能處理要求的狀態。它只在適用的 Reset/Readiness 條件下合法,不能當作任何時刻通用的忙碌回覆。
| 讀取 | 假設值 | 意義 |
|---|---|---|
| Root Capabilities:0x8E,16 bits | 0x0001 | bit 0 支援 Configuration RRS Software Visibility。 |
| Root Control:0x8C,16 bits | 0x0010 | bit 4 已啟用可見性。 |
| 目標 offset 0x00,32 bits | 0xFFFF0001 | Root Complex 收到 RRS 後,合成 Vendor ID 0001h,其餘 bytes 全 1。 |
讀取必須涵蓋 Vendor ID 的兩個 bytes;若只讀這個 16-bit 欄位,特殊值是 0001h。這不是已配發的 Vendor ID。未啟用可見性或讀取其他位置時,不應期待相同資料格式,適用時由 Root Complex 重新發出要求。等待期限仍須依 Reset、Readiness 與平台策略判斷,不能假設所有情況都等同一個固定時間。
查詢路線
Figure 7-21(p.952)定位 +1Eh/+1Ch;Figure 7-34/Table 7-31(p.988)查能力,Figure 7-33/Table 7-30(pp.986–988)查設定。RRS 條件:§2.3.1,pp.211、214;合成值與重試規則:§2.3.2,pp.220–221。
先開放可能的下游範圍,再回填實際結果
本例採先走完一個分支再返回的搜尋策略,暫以平台授予的 3F 作 Subordinate 上限,完成後縮回實際範圍。這是教學策略,不是所有平台唯一的程序。
| 順序 | 動作 |
|---|---|
| 1 | Root Port 00:01.0 設 Secondary=01、Subordinate=3F。 |
| 2 | 找到 01:00.0 的 Switch Upstream Port,設 Secondary=02、Subordinate=3F。 |
| 3 | 找到 02:01.0 的 Downstream A,設 Secondary=03、Subordinate=3F。 |
| 4 | 確認 03:00.0 與 03:00.1;本分支完成後,A 的 Subordinate 改為 03。 |
| 5 | 回到 Bus 02,替 02:02.0 的 Downstream B 設 Secondary=04、Subordinate=3F。 |
| 6 | 確認 04:00.0;B 的 Subordinate 改為 04,最後 Upstream Port 與 Root Port 也改為 04。 |
03:00.0 的 Header Type=80h 只允許探查其他 Function;Function 1 存在是另一筆有效結果。04:00.0 的 Header Type=00h,且無其他機制指示,因此不得一律掃描 Function 1–7。本例的普通 Link 對端用 Device 0,Switch 內部 Downstream Port 則可出現在其他 Device Number。
讀 Figure 7-14 找 Secondary/Subordinate 的 0x19/0x1A,各讀寫 8 bits,再依 p.937 的定義使用。設定寫入必須完成,才能使用新路徑;本例不以 Primary Bus Number 推導 Bridge 自身 BDF。平台若有保留需求,也不一定要把最後的上限縮到 04。
- BDF
- Bus/Device/Function,匯流排、裝置與功能識別
來源
Base 6.0 §7.5.1.3,Figure 7-14,p.936;§7.5.1.3.2–§7.5.1.3.4,p.937;Header Type:Table 7-7,p.925;Device Number:§7.3.1,p.911;ECAM 寫入完成保障:p.908。
Header 的 Type 與要求封包的 Type,必須分開
Configuration Header Type 1 描述 Bridge 的標頭格式;Configuration Request Type 1 則用於向更深層路由。對目標 03:00.1,Root Port 的下一層 Bus 是 01,因此仍以 Type 1 往 Switch 送;Switch 判定 Bus 03 正是 Downstream A 的下一層,再轉為 Type 0 送到 Endpoint。對 Bridge 自身設定空間的有效 Type 0 Request,同樣可以由 Bridge 處理。
本例描述對外路由結果,不假設 Switch 的內部邏輯 Bus 是另一條實體 PCIe Link。若目標不在有效範圍,則依 UR 規則處理。(Base 6.0 §7.3.2–§7.3.3,pp.912–913。)
裝置的 Requester ID 從哪裡來?
前一節沿路由找到 Endpoint;現在換到 Endpoint 自己發出要求的方向。Non-Flit Configuration Request 的 Figure 2-33 同時有 Requester ID 和 Destination ID:前者是這筆設定要求的發起者,後者指出要設定的 Function。兩者有不同角色,不能拿主機發起設定時的 Requester ID 當成 Endpoint 日後發起交易的身分。
【模擬資料】以下資料為教學用途建立,不代表特定硬體或平台。沿用一般非 ARI 的 Endpoint Function 03:00.0,不使用 Shadow 或 Phantom Function。假設設定路徑已建立,主機送達一筆合法的 Type 0 Configuration Write,目標是這個 Function,並得到成功完成回覆。
- ARI
- Alternative Routing-ID Interpretation,替代路由識別碼解讀
讀 §2.2.6.2:Function 必須從由它完成的 Type 0 Configuration Write 擷取 Bus 與 Device Number,並將擷取值用在它自身發起要求的 Requester ID。規格建議只在成功完成的要求上擷取;本例已假設成功。Function Number 仍是該 Function 的身分,因此本例正常組成的 Requester ID 是 0300h,不是主機那筆 Configuration Write 的 Requester ID。
如果平台之後需要重新配置 Bus Number,先依 §6.4 完成相關工作停止與未完成交易的協調。假設新配置將同一 Function 設為 04:00.0,且它完成新的 Type 0 Configuration Write,Function 便需重新擷取新的 Bus/Device 值;後續自身發起的要求使用更新後的身分。本例不表示軟體可以在交易仍進行時直接改號。
首次 Configuration Write 之前,Function 不得發起 Non-Posted Request(需要 Completion 的要求),因為回覆需要有效的 Requester ID。規格對 Root Complex 內的 Functions 存取系統開機裝置有例外;本例一般 Endpoint 不套用該例外。完成設定寫入後,仍須檢查 Bus Master Enable、資源與裝置初始化;取得身分本身不代表可以立即開始 DMA。
- DMA
- Direct Memory Access,裝置直接存取記憶體
ARI(Alternative Routing-ID Interpretation,替代路由識別方式)的 Bus 擷取方式另見 Chapter 26。Flit Mode Segment 與 Shadow Function 也有各自的識別規則,應查 §2.2.6.2,不套用本例的 BDF 拆解。
PCI Express Base 6.0 §2.2.6.2,文件頁/PDF 頁 156–157;§2.2.7.1、Figure 2-33,pp.164–165;§6.4 Device Synchronization,pp.717–718。
Flit Mode 的 Configuration Write 如何帶入 Segment?
前面用 Bus、Device、Function 辨識同一階層內的 Endpoint。Flit Mode 還有獨立的 Segment 欄位,可協助跨 Hierarchy(階層)的識別與路由。先讀 §2.2.1.2 的 Segment Rules:Root Port 以 Flit Mode 送出的 Configuration Request,必須帶 OHC-A3,並設置 Destination Segment Valid(DSV,目的 Segment 有效位)及正確的 Destination Segment;即使系統只有一個 Segment 也一樣。
【模擬資料】以下資料為教學用途建立,不代表特定硬體或平台。假設 Root Port 直接連接一般 Endpoint 03:00.0,這條 Link 正以 Flit Mode 運作。平台將該階層配置為 Segment 02h,並向這個 Function 傳送合法的 Type 0 Configuration Write。假設本次寫入的 1 DW 全部 bytes 都啟用,所選 Register 允許這樣寫入;Payload 與基本 Header 的其他欄位省略。
- DW
- Double Word,4 bytes的資料單位
沿 Figure 2-6 找到 Header Base 後,再由 Table 2-6 選 Configuration Request 的 OHC-A3。Figure 2-9 顯示 OHC-A3 占 1 DW:byte 0 是 Destination Segment,byte 2 的 bit 7 是 DSV,byte 3 是 Last/First DW Byte Enable。本例的 OHC-A3 四個 bytes 可寫成 02 00 80 0F,分別表示 Segment=02h、DSV=1、Last DW BE=0000b、First DW BE=1111b;其餘保留位在這個模擬封包中為 0。
- DW
- Double Word,4 bytes的資料單位
如果 Endpoint 成功完成這筆 Flit Mode Type 0 Configuration Write,就依 §2.2.6.2 擷取 Destination Segment。再查 Device 3 Extended Capability:假設已找到其起點 200h,Figure 7-124/Table 7-110 的 Device Status 3 在相對位移 0Ch,所以讀取位置是 20Ch。Status 的 Segment Captured 是 bit 3、屬性 RO;這次收到的 DSV=1,因此該 bit 為 1。這個 bit 只表示有效 Segment 已擷取,不提供 Segment 的數值;本例的 02h 是從設定要求取得。
假設這筆 Configuration Write 的 Completion 因其他適用條件而帶有 OHC-A5。接收端要依 Figure 2-11 與 Segment Rules 判讀:Completer Segment 使用剛擷取的 02h,而 Configuration Completion 的 DSV 必須清為 0、Destination Segment 必須為 00h。不需要 OHC-A5 的完成回覆可依其適用條件省略它;不能只因 Request 的 DSV=1,就要求所有 Completion 都複製同一個 DSV。
若 Function 收到的是 Non-Flit Mode 的 Configuration Write,§7.7.9.4 要求清除 Segment Captured。這個情況不表示 Segment 值一定是零;DSV 清除時,相關 Destination Segment 欄位是 Reserved。讀到某一時點的 Status,也不能單獨還原完整的路徑模式歷史。
擷取 Segment、具備 Requester ID 與允許裝置發起 DMA 是不同檢查。一般 Memory Request 是否附帶 Requester Segment,還要依其類型與 §2.2.1.2 的條件判斷;不應因 Segment Captured=1 就假設每筆 Memory Request 都必定帶 OHC-C。
- DMA
- Direct Memory Access,裝置直接存取記憶體
PCI Express Base 6.0 §2.2.1.2、Figures 2-6、2-9、2-11/Table 2-6,文件頁/PDF 頁 123、131–133、134–135、140;§2.2.6.2,p.157;§2.2.9.2,p.199;§7.7.9.1、§7.7.9.4、Figures 7-121、7-124/Tables 7-107、7-110,pp.1072–1073、1076–1077。
已知目標 BDF,讀取卻失敗時,先檢查哪一段?
沿用本章的拓撲,目標是 Endpoint 的 03:00.1。先找到連向它的分支,再由根部向下檢查每個 Bridge 的 Secondary/Subordinate Bus Number,確認目標 Bus 是否落在該分支的設定範圍。這裡的檢查順序是查閱方法,不代表硬體一定以這個時間順序處理。
讀規格時,先用 Figure 7-14 找 Secondary/Subordinate 的位置,再讀 §7.5.1.3.3–7.5.1.3.4 了解各欄位所記錄的範圍;接著到 §7.3.3 判讀 Type 1 Request 的轉送與轉換。若寫入採 ECAM,§7.2.2 要求平台提供軟體可確認寫入已由 Completer 完成的方法;本例不指定平台必須採用哪一種方法。(Base 6.0,文件頁/PDF 頁 908、912–913、936–937。)
Function 不存在,和其中一個 Register 未實作,有什麼不同?
以可觀察到 PCIe Completion 的資料為例:指定未實作的 Bus、Device 或 Function 時,§7.3.1 規定回 Unsupported Request(UR);對已實作 Function 內未實作的 Register 讀取,在沒有其他需回報的錯誤時,§7.3.3 規定回 Successful Completion,讀取資料為 0。兩者的目標與結果不同。
如果只看到軟體的讀值,仍要先確認存取是否成功、讀的是哪個 BDF 與 offset,以及平台如何呈現交易結果。Root Complex 在 §2.3.2 所述的條件下,會為依賴全 1 讀值的軟體合成 UR 讀取結果;那不是 UR Completion 自帶的 payload。RRS 的特殊值則依前面的就緒情境判讀。(Base 6.0,文件頁/PDF 頁 220–221、911、913。)
找到 BDF 後,仍未完成資源與工作設定
枚舉結果提供 Function 清單、橋接路徑與身分線索,不能直接證明 MMIO 或 DMA 已可用。Firmware 3.3 §3.5(pp.34–35)要求開機/主控台路徑及所有 Host Bridge 完成指定配置,其他裝置可留給 OS;不能只因任意 Endpoint 尚未配置就宣告韌體違規。
- MMIO
- Memory-Mapped I/O,記憶體映射輸入輸出
讀到 0xFFFF0001,就以 Device ID FFFFh 選擇驅動程式,可以嗎?
在本例 RRS 條件下不可以。這是暫時未就緒的合成值,尚未取得真正身分;應處理重試與就緒,而非當成未知產品繼續初始化。(§2.3.2,p.220。)
最後 Subordinate 比 04 大,一定是枚舉錯誤嗎?
不一定。要核對平台授予範圍、分支一致性與保留政策;04 是本例採用的最終範圍,不是通用常數。
下一步是 Chapter 4 的 BAR 與資源配置。
- BAR
- Base Address Register,基底位址暫存器


Comments