ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux CXL Type-3 内存设备配置全流程解析:从 Early Boot 到 DAX 与页分配器

Linux CXL Type-3 内存设备配置全流程解析:从 Early Boot 到 DAX 与页分配器 Linux CXL Type-3 内存设备配置全流程解析从 Early Boot 到 DAX 与页分配器【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux导读本文以 Linux 内核仓库中的 CXL 驱动文档 overview.rst 为骨架系统梳理一颗 CXL Type-3 内存设备Memory Expander从系统启动、驱动探测到最终呈现为DAX设备或普通内存页的完整配置流水线。读者将掌握五个阶段Early Boot → ACPI/PCI 驱动 → CXL 驱动 → DAX 驱动 → Memory Hotplug中各内核对象root、port、decoder、region、dax_region、memory block的生成时机理解EFI_MEMORY_SP、CONFIG_EFI_SOFT_RESERVE、CONFIG_MHP_DEFAULT_ONLINE_TYPE、nosoftreserve等关键开关如何决定 CXL 内存的最终归属并能结合/sys/bus/cxl/devices/与源码文件自行验证。CXL Type-3 内存配置的总览CXL Type-3 内存设备CXL Memory Expander通过 PCIe 枚举、MMIO Mailbox 传递配置信息其系统物理地址SPA空间的贡献由 HDMHost Managed Device MemoryDecoder 定义。Linux 侧的处理可划分为五个阶段其中以圆点bullet标注的步骤是内核对象生成的节点Early BootBIOS/EFI 与内核启动参数决定内存属性生成软保留Soft-Reserved资源、NUMA 节点、默认内存层级、CMA 预留。ACPI 与 PCI 驱动识别 PCI 设备为 CXL 设备交由 CXL 驱动接管探测。CXL 驱动运行创建 base 设备root、port、memdev、decoderroot/switch/endpoint、逻辑设备memory_region、endpoint并建立设备间关联最终把 region 以 DAX region 形式呈现。DAX 驱动运行把 DAX region 呈现为kmem转热插拔内存块或hmem保持 dax 文件接口两种模式。Memory Hotplug把 dax 设备的内存区域切分为多个 memory block接入页分配器并上线到指定 zone。从源码结构看CXL 子系统分布在 drivers/cxl/ 目录下其核心对象模型struct cxl_port、struct cxl_decoder、struct cxl_region等定义在 drivers/cxl/cxl.hregion 与 DAX region 的关联实现在 drivers/cxl/core/region.c 与 drivers/cxl/core/region_dax.c。阶段一Early Boot——不可变资源的初始化Linux 的配置被划分为 Early Boot 与其余阶段两大部分。Early Boot 期间即带有__init修饰的内核函数运行期Linux 建立 NUMA 节点等不可变资源并把 EFI/BIOS 通过 ACPI 表如 CEDT、SRAT、HMAT描述的资源转换为内核可消费的资源。启动阶段涉及 4 个关键选项它们决定了内存如何被管理。BIOS/EFI 与内核构建、启动参数选项类型作用EFI_MEMORY_SPBIOS/EFI 选项标记内存是 SystemRAM 还是 Specific Purpose专用内存。专用内存将被延迟交给驱动管理不会立即暴露为系统 RAMCONFIG_EFI_SOFT_RESERVE内核构建选项决定内核是否支持 Specific Purpose 内存Soft ReserveCONFIG_MHP_DEFAULT_ONLINE_TYPE内核构建选项决定被转换为 dax 设备的专用内存如何被管理保持 DAX或作为 SystemRAM 上线到ZONE_NORMAL/ZONE_MOVABLEnosoftreserve内核启动参数关闭 Soft Reserve 支持与CONFIG_EFI_SOFT_RESERVE作用类似内存映射创建Memory Map Creation内核解析 EFI 内存映射时如果支持并检测到Specific Purpose内存会将该区域单独设置为SOFT_RESERVED软保留为 CXL 驱动接管做准备。若EFI_MEMORY_SP0、CONFIG_EFI_SOFT_RESERVEn或nosoftreserveyLinux 会把 CXL 设备内存区域默认当作 SystemRAM暴露给页分配器的ZONE_NORMAL可用于大多数分配包括struct page与页表。若Specific Purpose已设置且被支持CONFIG_MHP_DEFAULT_ONLINE_TYPE_*决定内存是否默认上线_OFFLINE或_ONLINE_*以及上线到哪个 zone_NORMAL或_MOVABLE。若放入ZONE_MOVABLE该内存不用于大多数内核分配如struct page、页表这在内存容量较大时可能显著影响性能。这里需要注意一个前提ZONE_MOVABLE的语义是保留内存块的热插拔能力以便整块区域日后可热拔出而ZONE_NORMAL上的容量应视为永久附加到页分配器详见 memory-hotplug.rst。NUMA 节点创建Linux 通过 SRAT 中定义的 Proximity DomainPXM在acpi_numa_init中创建 NUMA 节点通常PXM与 NUMA 节点 ID 为 1:1 关系。CEDT 补充描述 SPA 范围Linux 可能将其映射到一个或多个 NUMA 节点。如果 CFMWS 中存在 CXL 范围但 SRAT 中没有对应项Linux自 v6.15 起会创建伪PXM未来版本可能因为邻近域关联的歧义而拒绝未被 SRAT 描述的 CFMWS。NUMA 节点无法在运行时创建。所有可能的 NUMA 节点都在__init时间具体在mm_init期间被识别因此 CEDT 与 SRAT 必须包含足够的PXM数据使 Linux 能识别 NUMA 节点及其关联内存区域。相关实现位于 drivers/acpi/numa/srat.c。内存层级Memory Tier创建内存层级是按性能特征分组的 NUMA 节点集合。__init期间Linux 初始化一个包含所有标记为N_MEMORY节点的默认内存层级memory_tier_init在启动时为默认在线的节点调用memory_tier_late_init在 late-init 阶段为驱动配置期间建立的节点调用。节点只有在拥有在线内存时才会被标记N_MEMORY。层级成员可通过/sys/devices/virtual/memory_tiering/memory_tierN/nodelist查看。所有节点默认属于 DRAM 层级除非 HMAT/CDAT 信息通过access_coordinates上报给 memory_tier 组件。若同一层级内节点性能差异明显应检查 CXL 节点的 HMAT 与 CDAT 信息详见 access-coordinates.rst。连续内存分配CMA的限制连续内存分配器CMA允许在 Early Boot 期间为 NUMA 节点预留连续内存但CMA 无法在未于启动期上线的 NUMA 节点上预留内存void __init hugetlb_cma_reserve(void) { if (!node_online(nid)) /* do not allow reservations */ }这意味着如果用户打算把 CXL 内存延迟交给驱动管理Soft Reserved就无法用 CMA 保证巨页分配。若选择在 Early Boot 期间把 CXL 内存作为ZONE_NORMAL的 SystemRAM 启用则可通过内核命令行参数cma_pernuma或numa_cma按节点预留 CMA。阶段二ACPI 与 PCI 驱动——识别 CXL 设备PCI 层检测到设备具备 CXL 能力后将其标记为交由 CXL 驱动探测。这一阶段由cxl_acpi与cxl_pci驱动协同完成cxl_acpi初始化根解码器并交互 ACPI 数据CEDT 中的 CHBS、CFMWS 等。cxl_pci利用 cxl_port 枚举实际 Fabric 层级并探测内存设备memdev。BIOS/EFI 负责生成足够的 ACPI 表CEDT、SRAT、HMAT 等与平台特定配置HPA 空间、host bridge 级 interleave使 CXL 驱动能够在运行时配置 Fabric 中的设备。HDM decoder 与 switch port 的编程并非必需可根据管理策略如 udev 规则延迟到 CXL 驱动处理。部分平台因 quirks如 Zen5 地址转换需要预编程 HDM decoder 并锁定但这并非常规、预期的配置路径。详见 bios-and-efi.rst。阶段三CXL 驱动运行——对象层级与设备关联CXL 驱动操作阶段涉及的设备对象均可在/sys/bus/cxl/devices/与/dev/cxl/下查看。CXL 驱动实际拆分为多个驱动cxl_core基础初始化接口与核心对象创建cxl_port初始化 root提供端口枚举接口cxl_acpi初始化根解码器交互 ACPI 数据cxl_p/mem初始化内存设备cxl_pci使用 cxl_port 枚举实际 Fabric 层级Base 设备创建以一个单插槽、4 个 host bridge、其中 2 个各挂一颗内存设备并交织为单一 region已转 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 root0Root由cxl_acpi驱动在cxl_acpi_probe中创建当找到ACPI0017Compute Express Link Root Object 设备类时。Root 包含指向 Host Bridge PortCEDT CHBS 定义、Downstream Port、Root DecoderCEDT CFMWS 定义的链接。Root 是 CXL Fabric 中第一个逻辑端口是一种特殊的 switch port只有下游端口连接。例如root0的devtype为cxl_port其子设备decoder0.0的devtype为cxl_decoder_root。Port更准确地说是一个 switch port可代表连接到 Root 的 host bridge或实际 switch 上的端口。一个 switch port 含一个或多个用于把内存请求路由到下游端口的 decoder。Host Bridge 通过ACPI0016ID 显式定义是特殊的 CXL switch port在acpi_probe时即被探测switch 上类似端口则在更晚时被探测。EndpointFabric 中的终端端口属于逻辑设备可能是内存设备呈现的多个逻辑设备之一仍被视为一种 port。Endpoint 包含 endpoint decoder 与设备的 Coherent Device Attribute TableCDAT描述设备能力。Memory Devicememdev由cxl_pci驱动在cxl_pci_probe中探测、由cxl_mem驱动管理。它主要提供内存设备的 IOCTL 接口/dev/cxl/memN并暴露设备配置数据如firmware_version、label_storage_size、ram、pmem、serial、numa_node。memdev 不是 port尽管其物理设备可能同时承载 endpoint但 endpoint 与 memdev 的关系并不在 sysfs 中体现。Decoder 创建Decoder 全称是 CXL Host-Managed Device Memory (HDM) Decoder负责把访问路由到 endpoint并在 endpoint 处把 Host PhysicalHPA翻译为 Device PhysicalDPA地址。CXL 3.1 规范8.2.4.20 节 HDM Decoder Capability Structure 的 Implementation Note强烈暗示只有 endpoint decoder 应参与 HPA→DPA 的翻译因此存在两组 decoderRouting Decoder只路由访问、不翻译 HPA→DPA。Translating Decoder翻译 HPA→DPA 供 endpoint 服务。CXL 驱动区分三种 decoder 类型root、switch、endpoint。只有 endpoint decoder 是 Translating Decoder其余均为 Routing Decoder。平台厂商须知Linux 做出强假设——endpoint decoder 是 Fabric 中唯一主动翻译 HPA→DPA 的 decoder路由 decoder 会把 HPA 原样传递给下一级。因此任何 decoder 的地址范围都必须是其上游端口 decoder 的子集。任何偏离该方案的配置在规范中都是未定义的Linux 优先遵循规范/架构定义的行为。Root Decoder由 CEDT 中 CFMWS 字段的物理地址与交织配置逻辑构造而成是 Fabric 中首个接收平台内存控制器访问的 decoder每个 CFMWS 条目对应一个 root decoder在cxl_acpi_probe期间创建。其target_list由 CFMWS 的 target 字段填充target 是 Host Bridge因此 root 级交织即 Inter-Host-Bridge Interleave只有 root decoder 具备该能力。root decoder 的内存范围用于(1) 创建 memory region如region0(2) 将 region 与 IO Memory Resourcekernel/resource.c关联。该 IO 资源在 Early Boot 阶段从 EFI Memory Map 或x86 的E820 表中识别 CFMWS 区域时创建可通过cat /sys/bus/cxl/devices/decoder0.0/region0/resource查看。Switch Decoder所有非 root 的路由 decoder 均视为 switch decoder类型为cxl_decoder_switchHost Bridge 与 CXL Switch设备的 decoder 都属于此类。switch decoder 建立 root decoder 定义的 region 与下游目标端口之间的关联其交织为多下游端口交织对 host bridge 即 Intra-Host-Bridge Interleave。switch decoder 在cxl_port驱动的cxl_switch_port_probe中基于 PCI 设备的 DVSEC 寄存器创建其编程在探测期平台启动时已编程见 Auto Decoders或提交期运行时编程被验证。Endpoint Decoder附着于 Fabric 终端点endpoint的 decoder类型为cxl_decoder_endpoint与 root decoder 定义的 region 关联并描述该 region 对应的设备本地资源。与前两者不同endpoint decoder 翻译 HPA→DPA其交织设置描述整个交织集interleave set。DPA 区域必须按序提交例如从 0x0 开始的 DPA 区域必须先于从 0x80000000 开始的区域提交。自 Linux v6.15 起Linux 不支持非平衡交织配置交织集中的所有 endpoint 必须有相同的交织设置granularity 与 ways 必须一致。endpoint decoder 在cxl_port驱动的cxl_endpoint_port_probe中基于 DVSEC 寄存器创建。逻辑设备创建与设备关联Memory Region连接 Fabric 中一组 CXL 端口与一个 IO Memory Resource 的逻辑构造最终通过 DAX Region 把设备内存暴露给 DAX 子系统。region 可以在 endpoint probe 期间构造若 decoder 由 BIOS/EFI 编程见 Auto Decoders或通过 root decoder 的create_ram_region/create_pmem_region接口手动创建。region 的交织设置描述的是 Interleave Set 的配置与 endpoint 交织设置一致。DAX Region把 CXL Memory Region 转换为 DAX 设备。DAX 设备可通过文件描述符接口直接访问或通过 DAX kmem 驱动转换为 System RAM。设备关联存在两种路径Auto-decoderBIOS 编程的 decoder驱动在 probe 时验证配置、构建关联并锁定配置。Auto Decoder 几乎总是被锁定不可修改常见于静态配置平台或因平台 quirks如 CPU 复杂体内需要超出 CXL 范围的控制器编程无法运行时动态修改的场景。探测 Auto Decoder 时驱动首要职责是确保 Fabric 处于正常状态如同验证运行时编程的 region 与 decoder。如果 Linux 无法验证 auto-decoder 配置内存将不会被呈现为 DAX 设备也不会暴露给页分配器——实际上等于被搁置stranded。用户配置user-configured验证与关联在 decoder 提交commit时构建也就是cxl-cli等工具所操作的Software Defined Memory运行时环境。Mailbox 接口每个设备的 mailbox 命令接口暴露在/dev/cxl/mem0、/dev/cxl/mem1可接收任何规范定义的命令。原始命令自定义命令只有在构建配置CXL_MEM_RAW_COMMANDS开启时才能发送这被视为调试/开发接口而非厂商特定命令的官方支持机制厂商命令应走fwctl子系统。交织Interleave配置语义Linux CXL 驱动支持Cross-Link First交织。以 16 个 endpoint 挂在 4 个 host bridge 下的 4x4 Cross-Link First 配置为例各层级 decoder 的 ways/granularity 期望如下decoderwaysgranularityroot4256host bridge41024endpoint16256在 root 处每次访问被路由到((HPA / 256) % 4)号目标 host bridge在 host bridge 内路由到((HPA / 1024) % 4)号目标 endpoint每个 endpoint 基于整个 16 设备交织集翻译。非平衡交织集不受支持——层级中相似位置的 decoder如所有 host bridge decoder必须具有相同的 ways 与 granularity。各层级编程要点Root交织由 CEDT CFMWS 定义。CEDT 可能用多个 CFMWS 配置描述同一物理容量让用户运行时决定内存按交织或非交织上线。示例中 CFMWS 定义了每个 host bridge 两块独立的非交织 4GB 区域以及一块同时指向两者的交织 8GB 区域这会在 root 下呈现 3 个 root decoderdecoder0.0、decoder0.1、decoder0.2。root decoder 不可运行时编程仅用于生成 Memory Region以便在 switch 与 endpoint decoder 上以运行时编程设置把内存上线。Host Bridge/Switch可编程字段包括startregion 关联的 HPA 区域、size、target_list下游端口列表、interleave_ways交织的下游端口数、interleave_granularity交织粒度。Linux 期望 switch decoder 的interleave_granularity由其上游端口连接推导在 Cross-Link First 配置中decoder 的 granularity 等于parent_interleave_granularity * parent_interleave_ways。Endpoint编程方式与 Host Bridge/Switch 类似区别在于 ways 与 granularity 由交织集即关联 Memory Region 的交织设置定义。这些设置被 endpoint decoder 用来翻译 HPA→DPA因此它必须知晓整个交织集。注root decoder 的交织设置描述的是紧邻下游目标之间的交织方式而非整个交织集switch decoder 同理。这与 endpoint decoder 描述整个交织集的语义不同。阶段四DAX 驱动运行——kmem 与 hmem 两种模式DAXDirect Access驱动最初用于为类似内存的块设备提供内存式访问机制后被扩展支持 CXL 内存设备。CXL 子系统依赖 DAX 子系统完成两件事之一通过/dev/daxN.Y为用户态生成类文件接口或调用 memory-hotplug 接口把 CXL 内存加入页分配器。DAX 子系统通过cxl_dax_region驱动暴露该能力dax_region提供 CXLmemory_region与 DAX Device 之间的转换实现参考 drivers/cxl/core/region_dax.c。DAX Device/dev/daxN.Y类文件接口。通过 dax 设备暴露的内存区域可被用户态软件用mmap()系统调用访问结果是 CXL 容量被直接映射到任务页表。希望手动管理 CXL 内存分配的用户应使用该接口。hmem 模式dax 设备保持 daxdev 形态作为文件访问——旅程到此结束。kmem 模式dax_kmem驱动把 DAX Device 转换为由kernel/memory-hotplug.c管理的一系列热插拔内存块hotplug memory blocks容量按用户选择的 zone 暴露给页分配器。该模式会创建 DAX kmem IO Resource。memmap_on_memory设置包括全局设置与 DAX 设备本地设置决定该内存的struct folio描述符从何处分配若开启内存热插拔会从 memory block 容量中划出一部分分配 folio若关闭则通过普通GFP_KERNEL分配——结果很可能落在执行热插拔操作的 CPU 的本地 NUMA 节点上。阶段五Memory Hotplug——把 CXL 内存交给页分配器将 CXL 内存呈现给页分配器的最终阶段是 DAX 驱动通过 memory-hotplug 组件呈现Driver Managed驱动管理内存区域。有四个主要配置维度需要考虑1. 默认上线行为Default Online Behavior热插拔内存的默认上线行为由以下项决定按优先级从高到低CONFIG_MHP_DEFAULT_ONLINE_TYPE构建配置memhp_default_state启动参数/sys/devices/system/memory/auto_online_blocks值热插拔内存块到达时处于三种状态之一Offline、ZONE_NORMAL在线、ZONE_MOVABLE在线。ZONE_NORMAL意味着该容量可用于几乎所有分配ZONE_MOVABLE意味着该容量应仅用于可迁移分配以保留内存块未来整体热拔出的能力。2. 热插拔内存块大小在大多数架构上默认的热插拔内存块大小为 128MB 或 256MB。x86 上当总内存容量超过 64GB 时块大小会增加到 2GB。自 v6.15 起Linux 决定热插拔内存块大小时不会考虑ACPI CEDT CFMWS 区域的大小与对齐详见 Early Boot 文档。平台厂商的实践建议源自 bios-and-efi.rst自 v6.14 起热插拔内存系统要求内存区域在大小与对齐上保持一致。虽然 CXL 规范允许小至 256MB 的内存区域但热插拔内存支持的块大小与对齐是架构定义的。为获得最佳跨版本支持平台厂商应将 CXL 内存放置在2GB 对齐的基地址region 也应为 2GB 对齐这还有助于避免创建数千个内存设备每块一个。3. 内存映射资源位置Memory Mapstruct folio分配的位置由以下系统设置决定/sys/module/memory_hotplug/parameters/memmap_on_memory/sys/bus/dax/devices/daxN.Y/memmap_on_memory若两者都为 true则该容量的struct folio会从正在上线的 memory block 中划出——如果该内存延迟特别高且其struct folio成为热点争用对象会有性能影响。若任一参数为 falsestruct folio从执行热插拔过程的处理器本地节点分配GFP_KERNEL分配落在该节点ZONE_NORMAL。拥有极大量ZONE_MOVABLE内存如 CXL 内存池的系统必须确保本地ZONE_NORMAL有足够容量来承载热插拔容量的内存映射。4. 驱动管理内存Driver-Managed MemoryDAX 驱动以Driver Managed身份把内存呈现给 memory-hotplug。这不是可配置项但很重要驱动管理内存被明确排除在 kexec 使用之外。这是为了确保功能系统重启如 probe 时 reset期间 CXL 设备可能承受的任何复位或带外操作都不会导致 kexec 内核的某些部分被覆盖。结果呈现mhp 组件把 dax 设备内存区域作为多个 memory block 呈现给页分配器这些块出现在/sys/bus/memory/devices中并链接到某个 NUMA 节点块被上线到请求的 zoneNORMAL 或 MOVABLE内存被标记为Driver Managed以避免 kexec 将其作为内核更新区域使用。验证路径与进一步阅读查看运行时对象/sys/bus/cxl/devices/root/port/endpoint/memdev/decoder/region/dax_region、/dev/cxl/memNmailbox、/dev/daxN.YDAX 设备、/sys/bus/memory/devices热插拔内存块。驱动实现drivers/cxl/cxl.h核心对象模型、drivers/cxl/core/region.cregion 逻辑、drivers/cxl/core/region_dax.cDAX region 转换、drivers/acpi/numa/srat.cNUMA 节点创建。相邻主题文档early-boot.rst启动参数细节、cxl-driver.rst驱动对象细节、dax-driver.rstDAX 模式细节、memory-hotplug.rst热插拔细节、bios-and-efi.rst平台侧期望。配置示例单设备直连配置见 single-device.rsthost bridge 交织、intra-host-bridge 交织与多级交织分别见 hb-interleave.rst、intra-hb-interleave.rst、multi-interleave.rst。掌握这条流水线后读者即可针对具体平台判断 CXL 内存为何以 DAX 设备、SystemRAM 或被搁置状态呈现并在 BIOS 设置EFI_MEMORY_SP、内核构建CONFIG_EFI_SOFT_RESERVE、CONFIG_MHP_DEFAULT_ONLINE_TYPE与启动参数nosoftreserve、memhp_default_state、cma_pernuma之间做出符合预期部署目标的组合决策。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表