1. CXL 技术概述:发展背景与协议族

各位好,我是今天这门课的主讲。说实话,做了十几年芯片验证和 ATE 测试,CXL 算是我见过演化最快、也最让人头疼的互连接口之一。它不是什么凭空冒出来的新标准,而是数据中心里那帮做 CPU、GPU、内存和加速器的老哥们,被 PCIe 的痛点逼出来的产物。

我最早接触 CXL 是在 2019 年,当时一个客户拿着他们自研的 AI 加速器来找我们做 ATE 测试方案。芯片本身性能没问题,但跟 CPU 之间的一致性问题搞得团队焦头烂额。那时我就在想:要是有个专门管缓存一致性、又能低延迟访问内存的协议该多好。嗯,没过多久 CXL 1.0 就发布了。

CXL 发展背景——为什么我们需要它

先捋一下背景。传统数据中心里,CPU 用 PCIe 连加速器或内存扩展设备。PCIe 本质上是一个外设总线,它不维护缓存一致性。你想想看,加速器里的数据如果被 CPU 改了,加速器根本不知道,只能靠软件做数据同步——这又慢又容易出错。

另一方面,内存带宽和容量一直往上走,但 CPU 能直接挂的 DRAM 插槽有限。大家需要一种方式,让 CPU 可以低延迟地访问加速器或内存池里的内存,同时保证数据的一致。

简单说,CXL 就是解决这两件事的:提供缓存一致性 + 内存池化访问。它跑在 PCIe 物理层之上(PCIe 5.0/6.0 的电气特性),但协议层重新设计,加入了 cache coherency 和 memory access 的机制。

我个人经验:在早期项目里,很多团队把 CXL 当成“更快的 PCIe”来设计,结果一致性协议一跑就崩。CXL 最核心的差异化就在 cache 和 mem 这两条通道上,千万别只盯着 io 那点带宽。

CXL 协议族——三兄弟各司其职

CXL 规范定义了三个子协议,我习惯叫它们“三兄弟”:CXL.io、CXL.cache 和 CXL.mem。这三条通道可以独立工作,也可以组合使用,具体看设备类型。

下表把它们的定位和典型应用场景列了一下,方便对比:

协议 核心功能 典型应用 需要一致性?
CXL.io 设备枚举、配置、DMA、中断等非一致性数据传输 智能网卡、存储控制器、通用加速器 否(类似 PCIe)
CXL.cache 设备缓存与 CPU 缓存之间的数据维持一致性 带本地缓存的加速器(如 GPU、AI 芯片) 是(MESI/Snoop)
CXL.mem 设备以内存语义直接访问主机内存或池化内存 内存池扩展、计算存储、CXL 类型 3 设备 部分一致(取决于访问模式)

看到这个表,你可能会问:“那 CXL.cache 和 CXL.mem 到底怎么分工?” 我举个例子:假设你有一块 AI 加速卡,上面有自己的 SRAM 或 HBM 缓存。这块卡在做推理时,需要知道 CPU 是否改了模型权重——这就要靠 CXL.cache 来维护缓存一致性,它会走 snoop 或 directory 协议,确保卡上的 cache 和 CPU 的 cache 始终同步。

而 CXL.mem 更像是让设备能像访问本地内存一样,直接读写主机或内存池里的物理地址。这种访问不需要经过 PCIe 的 BAR 空间翻译,延迟能降到几十纳秒级。

至于 CXL.io,它其实跟普通 PCIe 的 Transaction Layer 很接近。设备初始化、控制面通信、DMA 传输这些活,全归它管。你可以把它看成三兄弟里的“老大哥”——没它,另外两个通道都拉不起来。

三通道如何协同工作?

真正在芯片实现时,这三条通道是并行跑的。CPU 侧的 Root Complex 会把请求按类型分发到对应的虚拟通道(VC)。我画了张图展示它们的关系:

CXL 协议栈架构 PCIe 物理层 (PHY + Logical Sub-block) CXL 链路层 (Link Layer) — 数据包封装/校验/流量控制 CXL.io 配置/中断/DMA CXL.cache Snoop / Directory CXL.mem 内存语义访问 设备应用 / 主机软件 (驱动、一致性管理器) 缓存一致性协议实现、内存地址映射、设备控制 物理层 链路层 CXL.io CXL.cache CXL.mem 应用

这张图从上往下读:最底层是 PCIe 物理层,上面是 CXL 链路层,然后分叉成三条虚拟通道。应用层则运行在协议之上。我们在 ATE 测试中,需要针对每一条通道构造不同的激励和检查点。

避坑指南:我曾经在一个项目中,只测了 CXL.io 通道就以为覆盖了所有内容,结果 CXL.cache 的 snoop 响应超时问题到了系统集成才暴露。建议各位在测试计划里,把三条通道的测试点分开列出来,每条通道至少要有独立的压力测试用例。

CXL 设备的三种类型

根据设备实现哪些通道,CXL 规范定义了三种设备类型:

  • Type 1:只实现 CXL.io 和 CXL.cache。典型场景是带本地缓存的加速器(如专用协处理器)。
  • Type 2:实现 CXL.io、CXL.cache 和 CXL.mem。既能维护缓存一致性,又能访问主机或池化内存。这算是功能最全的,比如智能 DPU 或 AI 训练卡。
  • Type 3:只实现 CXL.io 和 CXL.mem。没有缓存,纯粹的内存扩展。内存池设备一般都是 Type 3。

我刚开始学 CXL 时,总记不住这些类型的对应关系。后来我想了个笨办法:“1 有缓存、2 都有、3 没缓存”。Type 1 通过 CXL.cache 保持自己的缓存一致,Type 2 全都要,Type 3 就是个内存扩展器。嗯,这么记就不会乱了。

特别注意:在 ATE 测试中,Type 2 设备因为同时跑 cache 和 mem 两条通道,容易产生死锁或协议层级冲突。我记得有一次 debug 一个 Type 2 芯片,mem 读请求正常,但 cache 的写回请求总被链路层阻塞。后来发现是事务层仲裁策略没处理好。所以如果你测 Type 2,务必加入通道间并发和优先级翻转的测试场景。

小结