CXL 驅動程式操作¶
本節中描述的裝置存在於
/sys/bus/cxl/devices/
/dev/cxl/
作為 NDTCL 專案一部分維護的 cxl-cli 庫可用於編寫與這些裝置互動的指令碼。
驅動程式¶
CXL 驅動程式分為多個驅動程式。
cxl_core - 基本初始化介面和核心物件建立
cxl_port - 初始化根並提供埠列舉介面。
cxl_acpi - 初始化根解碼器並與 ACPI 資料互動。
cxl_p/mem - 初始化記憶體裝置
cxl_pci - 使用 cxl_port 列舉實際的 fabric 層次結構。
驅動程式裝置¶
這是一個來自具有 4 個主機橋的單插槽系統的示例。 兩個主機橋連線了一個記憶體裝置,這些裝置被交織成一個記憶體區域。 記憶體區域已轉換為 dax。
# ls /sys/bus/cxl/devices/
dax_region0 decoder3.0 decoder6.0 mem0 port3
decoder0.0 decoder4.0 decoder6.1 mem1 port4
decoder1.0 decoder5.0 endpoint5 port1 region0
decoder2.0 decoder5.1 endpoint6 port2 root0
具有主機橋交織記憶體區域的 CXL fabric 圖¶
在本節中,我們將探討此配置中存在的裝置,但在下面的示例配置中,我們將更深入地探討更多配置。
基本裝置¶
CXL fabric 中的大多數裝置都是某種 埠(因為每個裝置主要路由從一個裝置到下一個裝置的請求,而不是提供直接服務)。
根¶
CXL 根 是在 cxl_acpi_probe 期間由 cxl_acpi 驅動程式建立的邏輯物件 - 如果找到 ACPI0017 計算快速連結根物件 裝置類。
根包含到以下內容的連結:
# ls /sys/bus/cxl/devices/root0
decoder0.0 dport0 dport5 port2 subsystem
decoders_committed dport1 modalias port3 uevent
devtype dport4 port1 port4 uport
# cat /sys/bus/cxl/devices/root0/devtype
cxl_port
# cat port1/devtype
cxl_port
# cat decoder0.0/devtype
cxl_decoder_root
根是 Linux CXL 驅動程式呈現的 CXL fabric 中的第一個 邏輯埠。CXL 根 是一種特殊的 交換機埠,因為它只有下游埠連線。
埠¶
埠 物件最好描述為 交換機埠。它可能代表到根的主機橋或交換機上的實際交換機埠。交換機埠 包含一個或多個解碼器,用於將記憶體請求路由到下游埠,這些埠可能連線到另一個 交換機埠 或 端點埠。
# ls /sys/bus/cxl/devices/port1
decoder1.0 dport0 driver parent_dport uport
decoders_committed dport113 endpoint5 subsystem
devtype dport2 modalias uevent
# cat devtype
cxl_port
# cat decoder1.0/devtype
cxl_decoder_switch
# cat endpoint5/devtype
cxl_port
在探測 CXL 根 時,在 cxl_acpi_probe 期間探測 fabric 中的 CXL 主機橋。這允許立即邏輯連線到根和主機橋之間。
根具有到主機橋的下游埠連線
主機橋具有到根的上游埠連線。
主機橋具有一個或多個到交換機或端點埠的下游埠連線。
主機橋 是一種特殊的 CXL 交換機埠。它透過 ACPI0016 ID 在 ACPI 規範中明確定義。主機橋 埠將在 acpi_probe 時探測,而實際交換機上的類似埠將在稍後探測。否則,交換機和主機橋埠看起來非常相似 - 它們都包含交換機解碼器,這些解碼器在上下游埠之間路由訪問。
端點¶
端點 是 fabric 中的終端埠。這是一個 邏輯裝置,並且可能是記憶體裝置呈現的許多 邏輯裝置 之一。它仍然被認為是 fabric 中的一種 埠。
端點 包含 端點解碼器 和裝置的相干裝置屬性表(描述裝置的功能)。
# ls /sys/bus/cxl/devices/endpoint5
CDAT decoders_committed modalias uevent
decoder5.0 devtype parent_dport uport
decoder5.1 driver subsystem
# cat /sys/bus/cxl/devices/endpoint5/devtype
cxl_port
# cat /sys/bus/cxl/devices/endpoint5/decoder5.0/devtype
cxl_decoder_endpoint
記憶體裝置 (memdev)¶
memdev 由 cxl_pci 驅動程式在 cxl_pci_probe 中探測和新增,並由 cxl_mem 驅動程式管理。它主要透過 /dev/cxl/memN 提供到記憶體裝置的 IOCTL 介面,並公開各種裝置配置資料。
# ls /sys/bus/cxl/devices/mem0
dev firmware_version payload_max security uevent
driver label_storage_size pmem serial
firmware numa_node ram subsystem
記憶體裝置是一個離散的基本物件,不是埠。雖然它所屬的物理裝置也可能託管 端點,但 端點 和 memdev 之間的關係未在 sysfs 中捕獲。
埠關係¶
在上面描述的示例中,有四個主機橋連線到根,並且兩個主機橋連線了一個端點。
具有主機橋交織記憶體區域的 CXL fabric 圖¶
解碼器¶
解碼器 是 CXL 主機管理裝置記憶體 (HDM) 解碼器的縮寫。它是一種透過 CXL fabric 將訪問路由到端點的裝置,並在端點將 主機物理地址 轉換為 裝置物理地址。
CXL 3.1 規範強烈暗示只有端點解碼器應該參與 主機物理地址 到 裝置物理地址 的轉換。
8.2.4.20 CXL HDM Decoder Capability Structure
IMPLEMENTATION NOTE
CXL Host Bridge and Upstream Switch Port Decode Flow
IMPLEMENTATION NOTE
Device Decode Logic
這些註釋暗示存在兩組邏輯解碼器。
路由解碼器 - 一種路由訪問但不將 HPA 中的地址轉換為 DPA 的解碼器。
轉換解碼器 - 一種將 HPA 中的訪問轉換為 DPA 以供端點服務的解碼器。
CXL 驅動程式區分 3 種解碼器型別:根、交換機和端點。只有端點解碼器是轉換解碼器,所有其他解碼器都是路由解碼器。
注意
平臺供應商請注意
Linux 強烈假設端點解碼器是 fabric 中唯一主動將 HPA 轉換為 DPA 的解碼器。 Linux 假設路由解碼器將 HPA 不變地傳遞到 fabric 中的下一個解碼器。
因此,假設 fabric 中任何給定的解碼器都將具有其上游埠解碼器的地址範圍的子集。 規範未定義對該方案的任何偏離。 Linux 優先考慮規範定義/架構行為。
如果配置為交織記憶體訪問,則解碼器可能具有一個或多個 下游目標。 這將透過 target_list 引數在 sysfs 中顯示。
根解碼器¶
根解碼器 是 CEDT 的 CFMWS 欄位中存在的物理地址和交織配置的邏輯構造。 Linux 將此資訊顯示為存在於 CXL 根 中的解碼器。 我們將此視為 根解碼器,儘管從技術上講,它存在於 CXL 規範和特定於平臺的 CXL 根實現的邊界上。
Linux 將這些邏輯解碼器視為一種 路由解碼器,並且是 CXL fabric 中從平臺的記憶體控制器接收記憶體訪問的第一個解碼器。
根解碼器 在 cxl_acpi_probe 期間建立。 為 CEDT 中的每個 CFMWS 條目建立一個根解碼器。
target_list 引數由 CFMWS 目標欄位填充。 根解碼器的目標是 主機橋,這意味著在根解碼器級別完成的交織是 主機橋間交織。
只有根解碼器才能實現 主機橋間交織。
此類交織必須由平臺配置並在 ACPI CEDT CFMWS 中描述,因為 CFMWS 中的目標 CXL 主機橋 UID 必須與 CEDT 的 CHBS 欄位中的 CXL 主機橋 UID 和 DSDT 中定義的 CXL 主機橋的 UID 欄位匹配。
根解碼器中的交織設定描述瞭如何在直接下游目標之間交織訪問,而不是整個交織集。
根解碼器中描述的記憶體範圍用於
建立一個記憶體區域(本示例中為
region0),以及將該區域與 IO 記憶體資源相關聯 (
kernel/resource.c)
# ls /sys/bus/cxl/devices/decoder0.0/
cap_pmem devtype region0
cap_ram interleave_granularity size
cap_type2 interleave_ways start
cap_type3 locked subsystem
create_ram_region modalias target_list
delete_region qos_class uevent
# cat /sys/bus/cxl/devices/decoder0.0/region0/resource
0xc050000000
在早期啟動期間,當在 EFI 記憶體對映或 E820 表(在 x86 上)中識別出 CFMWS 區域時,將建立 IO 記憶體資源。
根解碼器定義為單獨的 devtype,但由於具有下游目標,因此也是一種 交換機解碼器。
# cat /sys/bus/cxl/devices/decoder0.0/devtype
cxl_decoder_root
交換機解碼器¶
任何非根、轉換解碼器都被認為是 交換機解碼器,並將呈現型別 cxl_decoder_switch。主機橋 和 CXL 交換機(裝置)解碼器都是 cxl_decoder_switch 型別。
# ls /sys/bus/cxl/devices/decoder1.0/
devtype locked size target_list
interleave_granularity modalias start target_type
interleave_ways region subsystem uevent
# cat /sys/bus/cxl/devices/decoder1.0/devtype
cxl_decoder_switch
# cat /sys/bus/cxl/devices/decoder1.0/region
region0
交換機解碼器 在根解碼器定義的區域和下游目標埠之間具有關聯。 在交換機解碼器中完成的交織是多下游埠交織(或主機橋的 主機橋內交織)。
交換機解碼器中的交織設定描述瞭如何在直接下游目標之間交織訪問,而不是整個交織集。
交換機解碼器在 cxl_port 驅動程式中的 cxl_switch_port_probe 期間建立,並基於 PCI 裝置的 DVSEC 暫存器建立。
如果在啟動期間平臺對它們進行程式設計,則在探測期間驗證交換機解碼器程式設計(請參閱下面的 自動解碼器),如果執行時程式設計,則在提交時驗證(請參閱下面的 執行時程式設計)。
端點解碼器¶
連線到 CXL fabric 中終端點的任何解碼器(端點)都被認為是 端點解碼器。 端點解碼器的型別為 cxl_decoder_endpoint。
# ls /sys/bus/cxl/devices/decoder5.0
devtype locked start
dpa_resource modalias subsystem
dpa_size mode target_type
interleave_granularity region uevent
interleave_ways size
# cat /sys/bus/cxl/devices/decoder5.0/devtype
cxl_decoder_endpoint
# cat /sys/bus/cxl/devices/decoder5.0/region
region0
端點解碼器 與根解碼器定義的區域相關聯,並描述與此區域關聯的裝置本地資源。
與根解碼器和交換機解碼器不同,端點解碼器將 主機物理地址 轉換為 裝置物理地址 範圍。 因此,端點上的交織設定描述了整個交織集。
裝置物理地址 區域必須按順序提交。 例如,無法在 0x0 處啟動的 DPA 區域之前提交從 0x80000000 啟動的 DPA 區域。
截至 Linux v6.15,Linux 不支援不平衡交織設定,交織集中的所有端點都應具有相同的交織設定(粒度和方式必須相同)。
端點解碼器在 cxl_port 驅動程式中的 cxl_endpoint_port_probe 期間建立,並基於 PCI 裝置的 DVSEC 暫存器建立。
解碼器關係¶
在上面描述的示例中,有一個根解碼器,它透過兩個主機橋路由記憶體訪問。 每個主機橋都有一個解碼器,它將訪問路由到其單個端點目標。 每個端點都有一個解碼器,它將 HPA 轉換為 DPA 並服務於記憶體請求。
驅動程式透過解碼器程式設計來驗證埠之間的關係,因此我們可以認為解碼器以與埠類似的分層方式相關。
CXL 根、交換機和端點解碼器的圖。¶
區域¶
記憶體區域¶
記憶體區域 是一種邏輯構造,它將 fabric 中的一組 CXL 埠連線到 IO 記憶體資源。 它最終用於透過 DAX 區域 將這些裝置上的記憶體公開給 DAX 子系統。
RAM 區域示例
# ls /sys/bus/cxl/devices/region0/
access0 devtype modalias subsystem uuid
access1 driver mode target0
commit interleave_granularity resource target1
dax_region0 interleave_ways size uevent
如果在 BIOS/EFI 程式設計解碼器期間(請參閱 自動解碼器),或者透過 根解碼器 的 create_ram_region 或 create_pmem_region 介面手動建立區域,則可以在端點探測期間構造記憶體區域。
記憶體區域 中的交織設定描述了 交織集 的配置 - 並且是可以預期在端點交織設定中看到的配置。
區域基於根解碼器配置建立。 必須使用與區域相同的交織設定對端點解碼器進行程式設計。¶
DAX 區域¶
DAX 區域 用於將 CXL 記憶體區域 轉換為 DAX 裝置。 然後可以透過檔案描述符介面直接訪問 DAX 裝置,或者透過 DAX kmem 驅動程式將其轉換為系統 RAM。 有關更多詳細資訊,請參閱 DAX 驅動程式部分。
# ls /sys/bus/cxl/devices/dax_region0/
dax0.0 devtype modalias uevent
dax_region driver subsystem
郵箱介面¶
每個裝置的郵箱命令介面都在以下位置公開:
/dev/cxl/mem0
/dev/cxl/mem1
這些郵箱可以接收任何規範定義的命令。 只有在設定了構建配置 CXL_MEM_RAW_COMMANDS 時,才能將原始命令(自定義命令)傳送到這些介面。 這被認為是除錯和/或開發介面,而不是用於建立特定於供應商的命令的官方支援機制(請參閱 fwctl 子系統)。
解碼器程式設計¶
執行時程式設計¶
在探測期間,必須程式設計的唯一解碼器是 根解碼器。 實際上,根解碼器 是一種邏輯構造,用於描述主機橋級別的記憶體區域和交織配置 - 如 ACPI CEDT CFMWS 中所述。
所有其他 交換機 和 端點 解碼器都可以在執行時由使用者程式設計 - 如果平臺支援此類配置。
這種互動建立了 軟體定義記憶體 環境。
有關如何在執行時配置 CXL 解碼器的更多資訊,請參閱 cxl-cli 文件。
自動解碼器¶
自動解碼器是在啟動時由 BIOS/EFI 程式設計的解碼器,並且幾乎總是被鎖定(無法更改)。 這是由可能具有靜態配置的平臺完成的 - 或者某些怪癖可能會阻止對解碼器進行動態執行時更改(例如,需要 CPU 複合體內超出 CXL 範圍的其他控制器程式設計)。
只要與它們關聯的裝置和記憶體區域探測沒有問題,就會自動探測自動解碼器。 在探測自動解碼器時,驅動程式的主要責任是確保 fabric 是健全的 - 就像驗證執行時程式設計的區域和解碼器一樣。
如果 Linux 無法驗證自動解碼器配置,則記憶體將不會作為 DAX 裝置顯示 - 因此不會暴露給頁面分配器 - 實際上將其擱置。
交織¶
Linux CXL 驅動程式支援 跨連結優先 交織。 這決定了如何在每個解碼器步驟中程式設計交織,因為驅動程式驗證瞭解碼器與其父解碼器之間的關係。
例如,在具有 16 個端點連線到 4 個主機橋的 跨連結優先 交織設定中,linux 期望根、主機橋和端點分別具有以下方式/粒度。
解碼器 |
方式 |
粒度 |
根 |
4 |
256 |
主機橋 |
4 |
1024 |
端點 |
16 |
256 |
在根上,每個給定的訪問都將路由到第 ((HPA / 256) % 4)th 個目標主機橋。 在主機橋內,每個 ((HPA / 1024) % 4)th 個目標端點。 每個端點都基於整個 16 個裝置交織集進行轉換。
不支援不平衡的交織集 - 層次結構中相似的點上的解碼器(例如,所有主機橋解碼器)必須具有相同的方式和粒度配置。
在根上¶
根解碼器交織由 CEDT 的 CFMWS 欄位定義。 CEDT 實際上可以定義多個 CFMWS 配置來描述相同的物理容量,目的是允許使用者在執行時決定是將記憶體作為交織還是非交織聯機。
Subtable Type : 01 [CXL Fixed Memory Window Structure]
Window base address : 0000000100000000
Window size : 0000000100000000
Interleave Members (2^n) : 00
Interleave Arithmetic : 00
First Target : 00000007
Subtable Type : 01 [CXL Fixed Memory Window Structure]
Window base address : 0000000200000000
Window size : 0000000100000000
Interleave Members (2^n) : 00
Interleave Arithmetic : 00
First Target : 00000006
Subtable Type : 01 [CXL Fixed Memory Window Structure]
Window base address : 0000000300000000
Window size : 0000000200000000
Interleave Members (2^n) : 01
Interleave Arithmetic : 00
First Target : 00000007
Next Target : 00000006
在此示例中,CFMWS 為每個主機橋定義了兩個離散的非交織 4GB 區域,以及一個以兩者為目標的交織 8GB 區域。 這將導致在根中顯示 3 個根解碼器。
# ls /sys/bus/cxl/devices/root0/decoder*
decoder0.0 decoder0.1 decoder0.2
# cat /sys/bus/cxl/devices/decoder0.0/target_list start size
7
0x100000000
0x100000000
# cat /sys/bus/cxl/devices/decoder0.1/target_list start size
6
0x200000000
0x100000000
# cat /sys/bus/cxl/devices/decoder0.2/target_list start size
7,6
0x300000000
0x200000000
這些解碼器不是執行時可程式設計的。 它們用於生成 記憶體區域,以便透過在 交換機 和 端點 解碼器上執行時程式設計的設定將此記憶體聯機。
在主機橋或交換機上¶
主機橋 和 交換機 解碼器可透過以下欄位程式設計
start- 與記憶體區域關聯的 HPA 區域size- 區域的大小target_list- 下游埠列表interleave_ways- 要跨越交織的下游埠數interleave_granularity- 要交織的粒度。
Linux 期望交換機解碼器的 interleave_granularity 從其上游埠連線派生。 在 跨連結優先 交織配置中,解碼器的 interleave_granularity 等於 parent_interleave_granularity * parent_interleave_ways。
在端點上¶
端點解碼器 的程式設計方式與主機橋和交換機解碼器類似,但方式和粒度由交織集定義(例如,由關聯的 記憶體區域 定義的交織設定)。
start- 與記憶體區域關聯的 HPA 區域size- 區域的大小interleave_ways- 交織集中的端點數interleave_granularity- 要交織的粒度。
這些設定由端點解碼器用於將記憶體請求從 HPA轉換為 DPA。 這就是為什麼它們必須瞭解整個交織集。
Linux 不支援不平衡的交織配置。 因此,交織集中的所有端點都必須具有相同的方式和粒度。