PCIe Chapter 6:DMA、可見性與交易順序

【模擬資料】本章位址、資料與工作流程為教學用途建立,不代表特定硬體或平台。

先看本章的角色與路徑

軟體發布描述項,裝置寫入資料與旗標,再由主機依平台同步條件接手。軟體發布描述項,裝置寫入資料與旗標,再由主機依平台同步條件接手。驅動程式/主機端裝置:執行工作平台可供 DMA 的記憶體寫入描述項及資料依平台規則發布後通知裝置裝置寫入結果資料依適用排序寫完成旗標主機依平台同步條件接手結果

作者的簡化工作週期。PCIe 交易排序與 CPU/快取同步各有責任,兩者共同決定資料何時可用。

DMA
Direct Memory Access,裝置直接存取記憶體

DMA(Direct Memory Access,直接記憶體存取)讓裝置發起記憶體交易。要讓一次工作正確完成,軟體還需交接緩衝區所有權,並處理平台要求的同步。

前情提要:Chapter 5 已建立 Request/Completion 的概念。本章沿著軟體準備工作、裝置寫入資料、軟體接手結果的過程,區分 PCIe 排序與 CPU/快取同步的責任。

閱讀路線:DMA 位址與映射背景 → 描述項發布 → Base Table 2-42 的交易排序 → 封包屬性與主機接手條件。

合法的 PCIe 寫入,不足以單獨證明 CPU 可以安全使用結果。DMA 還需要正確位址、有效映射、裝置與軟體的所有權交接,以及適用的記憶體同步。本章用「先寫資料,再寫完成旗標」分清各層保證。

完整中文教學 · 課程路線 · English

DMA 使用裝置可到達的位址

裝置以 MRd 讀主記憶體,資料由 CplD 回來;以普通 MWr 寫入結果,則沒有一般 Write Completion。BME 只控制相關要求的發送/轉送許可,不建立緩衝區或 DMA 映射。

Linux 6.12 區分 CPU 虛擬、CPU 實體與 DMA 位址。作者案例假設 CPU 指標 p 對應實體 0x90001000–0x90001FFF,而裝置使用有效的 DMA 映射 0x40001000–0x40001FFF。因此 DMA 位址 0x40001080 對應實體 0x90001080;這組數值不是通用轉換公式。裝置 BAR0 的 0x80004000–0x80007FFF 則屬於另一項資源。

來源

Base 6.0 §2.1.1.1(p.116)、§2.2.7.1(pp.162–164)、Table 7-4(p.919);必要平台背景見 Linux 6.12 DMA 位址說明。未展開任何特定 IOMMU 的頁表格式。

資料一致性與存取順序需要分別處理

假設描述項依序放入 DMA 位址 0x40001000、長度 256 bytes 與 OWN。裝置依介面約定取得 OWN 後才讀取其餘欄位;CPU 必須讓欄位先可見,再交出 OWN,並以正確的 MMIO 存取通知裝置。裝置交回所有權後,CPU 也要按平台規則再使用資料。

MMIO
Memory-Mapped I/O,記憶體映射輸入輸出

Base 6.0 §2.4.2 不保證正在更新的資料會被單一 MRd 讀成原子快照。Linux 6.12 的 coherent memory 仍可能需要 barrier;dma_* barriers 也不保證 MMIO 順序。Streaming mapping 另須遵循 DMA API 的同步方式。這些是不同的責任,不能用「PCIe 有排序」一併取代。

MMIO
Memory-Mapped I/O,記憶體映射輸入輸出
來源與限制

Base 6.0 §2.4.2(p.228);Linux 6.12 DMA mapping Guide;Linux 6.12 memory barriers。本節說明責任,不提供通用驅動程式序列。

用 Table 2-42 判斷後一筆能否越過前一筆

假設裝置先以 MWr 寫入 0x40001000 的 64-byte 資料 D,再以 MWr 將 0x40001FF0 的旗標 F 設為 1。Table 2-42 的欄是先發交易,列是後發交易;兩者皆為 Posted Request,因此看 A2。

相同工作,不同排序條件
條件結論
同一 Function、TC0,F 的 RO=0/IDO=0A2a:F 不得越過 D。
同一 TC,F 的 RO=1,路徑容許該放寬A2b:可能越過,但不要求一定越過。
D 在 TC0,F 在 TC1這張表不提供跨 TC 順序保證。
只改 No Snoop不改變排序;快取一致性條件則不同。
TC
Traffic Class,流量類別

表中的 Yes 表示後者必須能越過,以避免 deadlock;No 表示禁止;Y/N 表示實作可選。這些字不是在判斷交易成敗。封包沒有互相越過,也不會自動完成 CPU 端的所有權與同步工作。

排序來源

§2.4.1 Table 2-42(p.222)、A2a/A2b 及註解(p.223)、No Snoop 規則(p.224)。本例排除 Flow-Through IDE。

資料寫完就送中斷,軟體一定能先看到資料嗎?

沿用前節的資料 D,現在把後續動作換成 MSI-X(Message Signaled Interrupts Extended,以記憶體寫入通知中斷)交易。先判斷兩筆 PCIe 寫入的順序,再檢查平台如何讓 CPU 讀到結果。這兩段需要各自的證據。

MSI-X
Message Signaled Interrupts Extension,表格式訊息中斷

查閱順序是:先在 §6.1.4 確認 MSI-X 使用 Memory Write,且 RO 與 No Snoop 必須為 0;IDO 在啟用條件成立時可設為 1,本例明確設為 0。再到 §2.4.1 的 Table 2-42,以先發的 D 找欄、後發的 MSI-X 找列,讀 A2a 與 A2b。最後回 §6.1.4 的 implementation note,查資料與中斷使用不同 TC 時的同步要求。(Base 6.0,文件頁/PDF 頁 222–223、661。)

平台補充:若本例的驅動使用 Linux,資料與所有權仍依該緩衝區的映射方式及裝置介面處理;例如 consistent memory 的 DMA barrier 與 MMIO 存取有不同適用範圍。這部分參考 Linux 6.12 memory barriers 與 DMA mapping Guide,不是 Base 6.0 對所有作業系統的規定。

控制位元是許可,不是每筆交易的實際屬性

PCIe Capability 在 0x70,Device Control 在 0x78;假設讀到 0x2810,bit 4 與 bit 11 表示允許有條件地使用 RO/No Snoop,bits 14:12=010b 表示 MRRS=512 bytes。這不表示每個 TLP 都設定了 RO 或 No Snoop。

TLP
Transaction Layer Packet,交易層封包

實際封包須讀 Attr[1] 的 RO、Attr[0] 的 No Snoop 與 Attr[2] 的 IDO;三個 bits 在 Non-Flit Header 中並非全部相鄰。No Snoop 不改變排序,也不是清 cache 的命令;許可使用時,仍須保證目標位址未存在系統任何 cache 中。IDO 有獨立的啟用與身分條件,本例固定為零。MSI/MSI-X 更明定 RO/No Snoop 必須為零。

MSI
Message Signaled Interrupt,訊息中斷
欄位查詢路線

Figure 7-25(p.959)→ Table 7-21(pp.960–962)→ Figure 2-29/Tables 2-12、2-13(pp.160–161)→ Figure 2-5(p.120)。MSI 屬性限制見 p.661。

核對推論的範圍

一次讀完整描述項,就保證完整快照嗎?

沒有。正在更新的資料需要另外的介面與同步保證;§2.4.2(p.228)不提供這項原子性。

一次測試沒有看見 RO 重排,就能依賴永遠不重排嗎?

不能。「允許重排」不代表每次都重排,單次結果也不會把允許改成禁止。

下一章把資料順序接到 MSI-X 通知。查核日期:2026-10-28。

Jia-Chang

Jia-Chang

Human

Comments

  Write a comment ...