☰
第十四章:NVMe CAP 寄存器怎么看?FPGA Host 初始化参数不能直接写死
2026/10/23 2:50:25 网站建设 项目流程

本篇位置:FPGA NVMe Host 实战连载 · 第二阶段 · 第 14 篇

第 13 章已经通过 PCIe Memory Read 读到了三星 980 1TB 的控制器寄存器。CAP 的实测值是00000030_3C033FFFh,VS 为00010400h,设备报告 NVMe 1.4.0。

接下来,Host 要让 SSD 从“可以读取寄存器”进入“可以接收命令并传输数据”的状态。这里会遇到队列深度、连续内存、页大小等参数。先不用记住它们的缩写和位号,我们先看一次 NVMe 读写怎样完成,再解释为什么需要这些参数。

这些参数不能只从一份能跑通的工程里复制。CAP 是 Controller Capabilities,即控制器能力。Host 需要先理解它给出的限制,再结合自己的队列存储、请求处理和数据通路选择参数。

本章的控制路径是:

PL Memory Read → SSD BAR/MMIO → CplD → CAP 字段解析 → Host 参数校验 → 后续队列与控制器初始化

本章继续使用 XC7Z100、PCIe Gen2 x4、三星 980 1TB 在 2026-07-31 保存的实板结果。这里重点解释能力值怎样影响设计;具体 Admin Queue 内存布局和控制器启用过程将在后续章节展开。

1. 先看一次 NVMe 读写怎样完成

前几章读取 Vendor ID、CAP 和 VS,都是访问一个确定位置,取得少量字段。读取 SSD 中的用户数据则不同:Host 需要说明读哪个逻辑块、读多少数据,以及把结果放到哪块内存;SSD 还需要返回这条命令是否执行成功。

NVMe over PCIe 使用队列完成这种协作。队列在这里就是一段按固定大小划分位置的 Host 内存,Host 和 SSD 按规定写入、读取其中的内容。这里的 Host 内存可以由 FPGA 侧的 BRAM、PS DDR 或 PL DDR 提供,关键是 SSD 能通过 PCIe 正确访问它。

1.1 先分清命令、执行结果和用户数据

区域保存什么由谁写、由谁读
提交队列,Submission Queue,简称 SQ一条条命令,例如读取哪些逻辑块、数据缓冲区在哪里Host 写入,SSD 取走处理
完成队列,Completion Queue,简称 CQ已完成命令的编号、执行状态等SSD 写入,Host 检查
用户数据缓冲区真正从 SSD 读出的数据,或准备写入 SSD 的数据读操作由 SSD 写入;写操作由 SSD 读取
SSD 的 BAR/MMIO 寄存器窗口配置、状态和 Doorbell 寄存器Host 通过 Memory Read/Write 访问

这四个区域的作用不同。SQ 中放的是命令描述,CQ 中放的是执行结果,用户数据单独放在缓冲区里。Doorbell 位于 SSD 的寄存器窗口中,用来更新队列位置,不用来承载整条命令或用户数据。

因此,即使应用要读取 8 KiB 数据,也不会把这 8 KiB 放进一个 SQ 命令项。命令会记录读取范围和数据缓冲区地址,SSD 再通过 PCIe 将实际数据传到指定缓冲区。

1.2 为什么有 Admin Queue 和 I/O Queue

Admin 是管理用途。Admin Queue 用于获取控制器信息、创建或删除 I/O 队列等工作;前一章提到的 Identify Controller 就通过它取得型号、序列号和固件版本。

I/O Queue 则用于实际数据访问,例如常用 NVM 命令集中的 Read 和 Write。Host 先建立基本控制与管理能力,再创建需要的 I/O 队列,之后才能提交正常的数据读写命令。

图 1:NVM Express《NVM Express Base Specification Revision 2.4》Figure 6,PDF p.48,文档页码 22。官方示例将管理 SQ/CQ 与 I/O SQ/CQ 放在 Host 一侧,控制器从中取得命令并回写执行结果。

图中的 Core 是官方处理器系统示例,说明队列可以服务不同的工作单元,不表示 FPGA Host 必须有多个 CPU。对于我们的 PL 路线,这些队列可以由硬件状态机和可寻址存储管理。

1.3 用一条 Read 命令串起来

假设控制器已经启用、I/O 队列已创建,Host 希望从 SSD 读取一段数据。一个简化过程如下:

  1. Host 准备好数据缓冲区,把 Read 命令写入 SQ。命令说明逻辑块范围,并提供数据缓冲区的位置。
  2. Host 确保命令内容对 SSD 可见,然后写 SQ Tail Doorbell,告诉控制器提交队列的新末尾位置。
  3. SSD 根据队列基地址和位置,通过 PCIe 请求取得命令内容。
  4. SSD 处理读取请求,通过 PCIe 将数据写入命令指定的 Host 缓冲区。
  5. SSD 向 CQ 写入完成项,报告对应命令的执行结果。
  6. Host 检查完成项中的命令编号和状态,在确认成功及数据可见后使用缓冲区中的数据。
  7. Host 更新 CQ Head Doorbell,通知控制器哪些完成项已经处理。

图 2:NVMe over PCIe 工作过程示意。假设初始化、队列和缓冲区已就绪,分别展示命令、读取数据、完成项和 Doorbell 的传递;该图不是本章新增的板上读写实测。

Write 的命令提交和完成项处理类似,数据方向相反:Host 先准备要写入的数据,SSD 根据命令中的指针从 Host 缓冲区取得它们,再处理写入。应用是否需要 Flush、怎样保证持久化,则按写命令、缓存和相关能力规则进一步处理。

这个过程中,SSD 会主动向 Host 发起 PCIe 访问,所以 Host 不能只实现“向 SSD 发包”。还需要正确响应 SSD 对队列和数据缓冲区的访问。这就是后续设计要涉及 Host 存储、地址映射、DMA 和缓存可见性的原因。DMA 在这里指设备按指定地址直接传输数据,不要求 CPU 逐个字节参与搬运。

1.4 队列深度为什么会影响并发

队列通常按环形缓冲管理。假设为 SQ 分配了四个位置,Host 依次填入命令,位置到末尾后按规则回到开头;旧命令尚未被消费时,不能直接覆盖相应位置。

“队列深度”说的是分配了多少个命令或完成项位置,不是一个位置能放多少用户数据。增加深度,可以给持续提交和并发处理提供更多空间,但也需要更多存储、命令跟踪和完成项管理。

Host 不必每写一条命令就停下来等待它执行结束,可以按队列规则继续提交其他命令。SSD 从 SQ 取得命令的顺序与命令完成顺序不必相同,因此 Host 还要根据完成项中的编号找到对应任务。

实际能同时运行多少条命令,还要服从队列空满规则和 Host、SSD 的能力。这里先建立一个概念:队列深度提供的是存放与协作空间,不能直接当作吞吐率承诺。

2. 把 CAP 参数放回这条工作流程

现在再看那些参数,就能对应到具体的问题。

参数主题工作流程为什么需要它本章随后查看的依据
队列深度Host 与 SSD 必须约定 SQ/CQ 有多少个位置,才能判断末尾、回绕和容量I/O 队列看 MQES,管理队列看 AQA
连续内存SSD 已知队列起点后,需要按固定项大小找到后续命令或完成项I/O 队列连续性看 CQR,管理队列另有要求
页大小命令提供数据地址,SSD 必须知道如何解释数据页边界和页指针;队列起点也需要对齐MPSMIN/MPSMAX 与 Host 选择的 CC.MPS
Doorbell 间距管理和 I/O 队列各有位置更新寄存器,Host 必须写到对应队列的正确地址DSTRD
Ready 超时Host 建好必要配置并启用控制器后,需要确认设备已接受该配置并进入就绪状态CC.EN、CSTS.RDY 和适用的 TO/CRTO 规则
命令集与仲裁方式双方必须约定可以执行哪些命令;有多个队列时,控制器还要选择怎样调度它们CSS、AMS 与相应 CC 选择字段

这些参数分别解决数量、地址、通知、状态和工作方式问题。CAP 让 Host 知道 SSD 在这些方面支持什么;Host 再选择满足设备限制、也符合自身资源的配置。

页大小可以再用一个例子理解:假设数据缓冲区按 4 KiB 对齐,一次读取 8 KiB,就会涉及两页数据。命令中的 PRP,即 Physical Region Page 数据指针,描述这些页的位置。页大小编码决定页边界在哪里;它不表示 SSD 每次只能读 4 KiB,也不等于磁盘逻辑块大小。

Ready 则对应准备阶段:队列尚未建立、控制器尚未就绪时,不能按前面的读写流程直接提交命令。CAP.TO 等待参数让 Host 在检查设备状态的同时,有一个明确的超时判断依据。

后面的位号和公式不用一次记住。先沿用上面的工作过程,遇到某个字段时,回看它负责解决哪一个问题,再核对当前三星 980 的具体值。

3. 先把 CAP 从十六进制数变成字段

CAP 是 64 位只读属性,位于 NVMe MMIO Offset00h。第 13 章已经说明其访问、返回和拼接方式,这一章从有效完整值开始解析。

图 3:项目 CAP 结果解析图。原始值来自 2026-07-31 实板 ILA CSV,4096 个 CAP 采样一致;各字段通过位移和掩码提取,该图不表示已经完成后续初始化。

第一次读 CAP,可以先按下面三个用途看:

  • 队列与内存:MQES、CQR、MPSMIN、MPSMAX。
  • 寄存器与状态:DSTRD、TO。
  • 支持的工作方式:CSS、AMS,以及其他可选能力。

CAP 不是让 Host 写入的参数表。Host 读取 CAP,再在 CC、AQA、队列创建命令和自己的地址管理逻辑中配置相应参数。

还要先核对 VS。文章使用 NVMe Base 2.4 官方文档解释字段,但当前三星 980 报告的是 NVMe 1.4.0。新版本增加的属性和能力不能因为“最新版文档里有”就在旧设备上直接使用。

4. MQES:最大队列项数为什么要加一

MQES 位于 CAP bits15:0,含义是 Maximum Queue Entries Supported。对于 NVMe over PCIe,它描述 Host 创建的 I/O Submission Queue 和 I/O Completion Queue 的单队列项数上限。

图 4:NVM Express《NVM Express Base Specification Revision 2.4》Figure 36,PDF p.84,文档页码 58。完整保留 AMS、CQR 和 MQES 的位号、适用范围及零基编码说明。

MQES 使用零基编码:字段为0表示一个位置,字段为N-1表示 N 个位置;实际合法最小值还要遵守规范,图 4 明确最小 MQES 为1h,即至少两项。

本项目读取到:

MQES = CAP[15:0] = 3FFFh = 16383

因此:

最大 I/O 单队列项数 = MQES + 1 = 16384

加一必须先扩展数值宽度。若用 16 位变量保存FFFFh + 1,结果会溢出成零,而规范中这一编码对应 65536 项。字段位宽和解析后的数量位宽不能默认相同。

16384 是上限,不是 Host 必须分配的深度

例如 Host 为某个 I/O 队列选择 64 项,对应队列大小字段填 63。这个选择小于三星 980 的能力上限,之后还要核对命令格式、队列内存和关联关系。

对于常用 NVM I/O 路线,若提交项采用 64 字节、完成项采用 16 字节:

每个队列的项数SQ 项存储量CQ 项存储量
4256 字节64 字节
644096 字节1024 字节
163841048576 字节262144 字节

这里计算的是队列项自身占用的字节数,实际分配还要考虑页对齐和地址空间。它也不包含用户数据缓冲区、PRP List 和 Host 的命令管理记录。

所以,把队列直接开到最大值,会同时增加存储和管理需求,却不保证吞吐率提高。Host 还需要有对应的命令跟踪、完成项处理、数据缓冲和错误恢复能力。

MQES 不是队列数量,也不是单次传输长度、SSD 容量或吞吐率。队列数组有多少位置,也不能直接等同于可同时提交多少未完成命令;后者还受环形队列规则、控制器和 Host 并发管理能力限制。

5. Admin Queue 要看 AQA,不能照搬 MQES

Admin Submission Queue 和 Admin Completion Queue 使用 Queue ID 0,初始化前通过 AQA、ASQ 和 ACQ 配置。它们有独立的大小与内存要求。

图 5:NVM Express《NVM Express Base Specification Revision 2.4》§3.1.4.8、Figure 44,PDF p.92,文档页码 66。原文给出 Admin SQ/CQ 的物理连续要求,以及 AQA 的 2~4096 项、零基编码规则。

AQA 中,ASQS 是 Admin SQ 大小字段,ACQS 是 Admin CQ 大小字段,二者采用零基编码。每个队列最少两项、最多 4096 项,不能因为 CAP.MQES 允许 16384 项,就把 Admin Queue 也配置成 16384 项。

项目起步验证选择两个管理队列各 4 项,因此两个大小字段都填3。这是一项便于核对的项目选择,不是 SSD 要求只能建 4 项。

同样,一页 4096 字节内存不等于队列自动有 4096 项。队列深度由配置字段决定,存储需求由“项数 × 每项大小”决定;内存分配大小、页大小和队列项数要分别记录。

6. CQR:连续的是队列地址,不是整块用户数据

CQR 位于 CAP bit16。图 4 说明,当 CQR=1 时,控制器要求 I/O SQ 和 I/O CQ 位于物理连续内存中;创建相应队列时,Physically Contiguous(PC)位需要设置为 1。

三星 980 的 CQR=1,所以 Host 不能把 I/O 队列随意拆到几个不连续的页面后,仍声称它满足连续队列要求。

“物理连续”关注 SSD 按命令提供的地址能否连续访问整个队列。对本项目的 PL 地址响应器,连续的 PCIe 地址范围可以被实现为 BRAM 或 DDR 后面的存储;但地址译码和访问映射必须覆盖全部队列,不能中间有空洞。

对 PS 软件路线,只得到一个连续的虚拟地址指针还不够。还要确认 SSD 可见的 DMA 地址、页面映射和缓存可见性符合要求。DMA 地址转换方式取决于具体平台,不能仅看软件打印的地址就判断 SSD 能否正确访问。

CQR=0 也不能省略管理队列连续性

CQR 的这一能力定义针对 I/O 队列。即使某设备 CQR=0,图 5 给出的 Admin SQ/CQ 连续要求仍要遵守。

CQR 也不直接规定一条 Read/Write 命令的全部用户数据必须放在一块大连续内存中。用户数据页由 PRP 等数据指针描述,其约束与队列自身的连续性是不同问题,后续数据缓冲章节会展开。

7. MPSMIN/MPSMAX:数值为零,页大小却是 4 KiB

MPSMIN 位于 CAP bits51:48,MPSMAX 位于 bits55:52。两个字段分别描述控制器支持的最小、最大 Host 内存页大小。

图 6:NVM Express《NVM Express Base Specification Revision 2.4》Figure 36,PDF p.82,文档页码 56。完整页大小公式、CSS 支持位图和 NSSRS 定义。

公式是:

页大小(字节)= 2^(12 + 字段值)

因此:

编码对应页大小
04096 字节,4 KiB
18192 字节,8 KiB
216384 字节,16 KiB

三星 980 的 MPSMIN=MPSMAX=0,说明该控制器支持的这项页大小范围为 4 KiB。Host 的 CC.MPS 需要满足:

CAP.MPSMIN ≤ CC.MPS ≤ CAP.MPSMAX

所以当前项目选择 CC.MPS=0,对应 4 KiB,不能写成 1 后期待控制器按 4 KiB 处理。

页大小会影响哪些地方

  • Admin SQ/CQ 基地址需要按配置页大小对齐。
  • PRP 中的数据页边界和地址拆分以控制器配置的页大小为依据。
  • 队列存储和数据指针管理要使用一致的页参数。

这个 4 KiB 不是 SSD 的 LBA 大小,也不是 PCIe TLP 的 Payload 大小。LBA 格式后续通过 Identify Namespace 核对;PCIe MPS/Max Read Request Size 属于 PCIe 参数,与 NVMe CC.MPS 只是缩写相似,不能混用。

例如某个 SSD 的 LBA 为 512 字节,而控制器内存页为 4096 字节,两者可以同时成立。应用每次读多少 LBA、Host 数据缓冲区跨多少页、PCIe 每个包承载多少字节,属于不同层次的计算。

8. DSTRD:每个 Doorbell 都是32位,间距可以不同

DSTRD 位于 CAP bits35:32。它描述相邻 Doorbell 寄存器的地址间距,单位换算为:

stride = 2^(2 + DSTRD) = 4 << DSTRD

图 7:NVM Express《NVM Express Base Specification Revision 2.4》Figure 36,PDF p.83,文档页码 57。完整保留 DSTRD、TO 定义和新版 CRTO/Ready 模式说明,没有截断 TO 的后续适用条件。

三星 980 的 DSTRD=0,间距为 4 字节。若另一块设备报告 DSTRD=1,间距则为 8 字节,但每个 Doorbell 的寄存器宽度仍是 32 位,中间增加的是地址间隔。

NVMe over PCIe 把 Doorbell 区域起点定义在 MMIO Offset1000h。

图 8:NVM Express《NVMe over PCIe Transport Specification Revision 1.4》Figure 4 在 PDF p.9 的表格部分。完整保留 SQ0、CQ0、SQ1、CQ1 四行及 Start/End 地址公式;后续队列编号继续按同一规则排列。

Queue ID 为 q 时,对应地址为:

SQ Tail Doorbell = base + 1000h + (2 × q) × stride

CQ Head Doorbell = base + 1000h + (2 × q + 1) × stride

用本项目 base=80000000h、stride=4 计算:

Doorbell相对 Offset当前 MMIO 地址
Admin SQ0 Tail1000h80001000h
Admin CQ0 Head1004h80001004h
I/O SQ1 Tail1008h80001008h
I/O CQ1 Head100Ch8000100Ch

这张表表示地址计算,不表示当前已经创建了全部队列。队列不存在时不能直接写对应 Doorbell;在队列内存和 DMA 路径准备好之前,也不能仅因为地址算对就提交命令。

如果换用 DSTRD=1 的设备,却仍固定给 CQ0 写base+1004h,就会错用地址。这样的错误很容易表现为“Memory Write 发送成功,但 SSD 没有按预期继续处理”。

另外,16 KiB BAR 窗口的大小不能用来推断设备支持多少个 I/O 队列。地址是否落在窗口内,与相应队列是否存在、是否已创建,是不同检查点。

9. TO:30秒是Ready转换等待依据,不是每次都睡30秒

TO 位于 CAP bits31:24。对于本章报告 NVMe 1.4.0 的设备,该字段按 500 ms 为单位解释:

TO = 3Ch = 60

Ready 超时依据 = 60 × 500 ms = 30000 ms = 30 秒

等待的对象是 CSTS.RDY 状态转换:启用控制器时等待 RDY 从 0 变 1,禁用控制器时等待 RDY 从 1 变 0。典型转换可能很快,不能把 30 秒写成一个无条件固定延时。

正确思路是在有效的状态转换起点开始计时,持续读取 CSTS。若 RDY 达到目标状态,就结束等待;若发生控制器错误或访问失败,记录相应原因;到达适用超时条件仍未完成,再报告超时。

三种时间不要混在一起

时间等待对象参数来源
PCIe Completion 等待当前 Memory Read 的返回请求引擎与 PCIe 超时处理策略
Controller Ready 等待CC.EN 改变后 CSTS.RDY 的变化设备版本、CAP.TO 或适用的 CRTO 规则
NVMe 命令执行等待队列中某条命令的完成项命令类型和 Host 命令超时策略

一个 MRd 没有返回,不能继续把残留的 CSTS=0 当作“控制器还没 Ready”一直轮询。读取失败和有效读取到 RDY=0 必须走不同分支。

在FPGA里计时,要核对时钟和位宽

假设用 250 MHz 时钟逐周期计时,30 秒需要:

250000000 × 30 = 7500000000 个周期

32 位计数器只能表示到4294967295,不足以覆盖这个等待。应使用足够宽的计数器,或者先生成可靠的毫秒时间基准,再按毫秒累计。

这个 250 MHz 只是说明位宽计算的例子。项目使用的实际时钟频率要从 IP 配置和时钟约束取得,不能把示例频率直接套到其他工程。

还要计算轮询事务本身花费的时间。如果每轮先延时 1 ms,再发送 MRd 并等待返回,那么累计 30000 次轮询的实际时间会大于 30 秒。若要求准确地检查总等待时间,应使用持续运行的时间基准或截止时间,不能只把“轮询次数 × 延时”当作精确墙钟时间。

新版规范为什么还提到CRTO

图 7 的 TO 说明中有 CRTO.CRWMT、CRTO.CRIMT 和 CC.CRIME,它们用于适用版本和能力下的 Controller Ready 模式及超时处理。

因此面向多种 SSD 的 Host,需要先核对 VS 和对应能力,再使用适用的等待规则。本章三星 980 的结果按其 NVMe 1.4.0 语境解释,不直接读取新版属性,也不把TO×500 ms作为所有新旧控制器唯一的启动超时规则。

10. CSS和AMS:支持位图不能原样写进选择字段

命令集是一组控制器能够解释的命令及其规则,例如常用块存储路线的 Read、Write。仲裁方式则是在多个提交队列都有命令时,控制器怎样选择从哪个队列取下一条命令。前者决定可以做什么,后者决定多个任务怎样分配处理机会。

图 6 中的 CAP.CSS 是 Command Sets Supported,位于 bits44:37。它是位图:某个位为 1 表示相应命令集支持能力,而不是一个可以直接写入 CC.CSS 的选择值。

三星 980 的 CAP.CSS=01h,bit 0 置位,结合其控制器类型表示支持 NVM Command Set。当前常规 NVM 路线选择 CC.CSS=000b,不能把能力位图的数值 1 直接复制为选择编码001b。

同样,图 4 中 CAP.AMS 位于 bits18:17,也是支持位图。本项目 CAP.AMS=1,表明支持 Weighted Round Robin with Urgent Priority Class;普通 Round Robin 是控制器必须支持的基础方式,没有在这个可选能力位图中单独占位。

因此起步方案仍可以选择 CC.AMS=000b使用普通轮询。不是因为 SSD 支持加权仲裁,就必须启用它。若选择加权方式,还要处理相关参数、队列优先级和系统调度目标。

CSS、AMS 说明“设备支持什么”,CC 中对应字段说明“Host 选择什么”。这两层值的编码需要分别按官方定义解释。

11. NSSRS及其他可选位,这一阶段怎样处理

三星 980 的 CAP.NSSRS=1,表示支持 NVM Subsystem Reset。它不能直接解释成“所有异常都可以通过该复位无损恢复”,也不能与 PCIe 链路复位或只清除 CC.EN 的操作混为一谈。

当前初始化参数选择只需要记录这项支持能力,具体复位作用范围、命令停止、未完成事务和恢复过程留到后续错误恢复章节。

其他可选能力也采用同样原则:对照实际 VS 和能力定义,确认系统是否实现相应路径后再使用。某个字段为零,可能只是可选功能不支持,不能因此判断 CAP 读取失败;未使用的能力也不需要为了“配置完整”全部开启。

12. 从本次CAP得到哪些起步参数

把前面的推导连接起来,可以得到当前设备的参数判断。

图 9:当前三星 980 能力值与 Host 起步参数的关系。队列深度选择、管理队列规则、页大小、Doorbell 地址、命令集和超时各自核对;这是参数解释,不是初始化完成或性能测试结果。

本项目起步设计采用较小的 Admin Queue、4 KiB 页和基础 NVM/普通轮询方式。它们的理由分别来自管理队列验证目标、页能力范围、命令集支持和调试复杂度,不能合并成一组“所有 SSD 通用常量”。

对 I/O 队列,深度需要在不超过 MQES 的前提下,结合内存、并发命令管理和数据面决定。之后还要通过管理命令创建队列,实际确认控制器接受了该配置。

如果只需要提出一个64项 I/O 队列的方案,可以先做以下核对:单队列项数不超过16384;SQ/CQ存储满足其项大小和连续性;页参数为4 KiB;队列地址处于SSD可达范围;Host有对应的命令和完成项管理。方案核对通过不代表队列已经创建,二者需要分别记录。

13. 两条数据路线如何使用同一组能力

对于 SSD 与 PS 内存交互路线,软件可以负责解析 CAP、选择参数、记录状态,PL 负责 PCIe 事务和相应内存通路。PS 侧需要处理 DMA 地址和缓存可见性,不能只凭普通内存指针满足控制器要求。

对于用户数据流与 PL DDR、SSD 交互路线,CAP 校验、队列页管理和等待状态要落到硬件控制面。页对齐、地址译码、计时位宽和异常分支同样必须满足约束。

这两条路线面对的是同一套 NVMe 控制器能力。采用 PL 不会让 SSD 的页大小范围、队列限制或 Doorbell 间距消失;采用 PS 也不会自动解决设备可达性和数据一致性。

BRAM、PS DDR 或 PL DDR 可以承担不同的存储角色。选择哪一种,取决于容量、带宽和地址映射;CAP 并没有规定“有DDR才允许建立队列”,也没有保证某个小缓冲就能支撑持续高速读写。

14. 参数校验应该怎样验证

这一章可以先验证解析器和参数检查,不需要真的提交读写命令。

场景应检查的结果
MQES=3FFFh得到16384项,而不是16383
MQES=FFFFh扩展后得到65536项,不溢出成零
I/O深度超过上限在创建队列前拒绝该参数
MPSMIN=MPSMAX=0,选择MPS=1拒绝8 KiB页配置
DSTRD=0/1同一Queue ID的Doorbell地址随间距正确变化
CQR=1且队列地址有空洞拒绝该内存布局
Admin深度超过4096按AQA规则拒绝,而不是依赖MQES
Ready等待计数使用32位原始250 MHz时钟识别30秒计数溢出风险
CAP.CSS支持NVM,CC.CSS选择不支持编码在使能控制器前报告不支持配置

有些检查属于设备能力,有些属于Host自身限制,错误记录中应写出实际原因。比如“请求深度超过MQES”和“DDR分配空间不足”都可能阻止创建队列,但修正方式不同。

上板时,可以记录完整 CAP、VS、解析字段、实际选择参数和校验结果。不要只输出“CAP正常”,否则移植到另一块 SSD 后,很难判断差异来自哪里。

15. 下一章进入Admin Queue内存布局

第 13 章解决“怎样可靠读取能力”,本章解决“能力对参数选择有什么约束”。接下来要把管理队列实际落到Host内存中:SQ/CQ存放在哪里,ASQ、ACQ保存什么地址,AQA怎样描述项数,SSD怎样通过PCIe访问这些位置。

下一章会重点介绍Admin Queue的存储与地址布局,再进入CC配置和CSTS.RDY等待过程。这样可以在写入CC.EN之前,先把队列内存和设备可达性说清楚。

第 08 章配套资源仍可从这里下载:FPGA 读取 NVMe SSD Vendor ID 实战工程。其工程内容以第 08 章验证目标为准,后续能力解析和队列设计按本系列章节逐层说明。

参考资料

  1. NVM Express,NVM Express Base Specification Revision 2.4,§3.1.4.1、Figure 36(PDF p.81~84):CAP;本章重点原文为p.82的MPSMIN/MPSMAX、CSS、NSSRS,p.83的DSTRD/TO,p.84的AMS/CQR/MQES。
  2. 同一规范,§3.1.4.3、Figure 41(PDF p.86~89):CC.MPS、CC.AMS、CC.CSS及配置条件;§3.1.4.8、Figure 44(PDF p.92):Admin Queue的连续性、AQA项数与零基编码。
  3. NVM Express,NVMe over PCIe Transport Specification Revision 1.4,§3.1.2、Figure 4(PDF p.9~10):Doorbell偏移及CAP.DSTRD参与计算的公式。
  4. NVM Express,NVM Command Set Specification Revision 1.3,与Base规范配套用于后续NVM I/O命令解释;控制器实际支持的规范版本和命令集仍需按VS与能力信息核对。
  5. NVM Express,NVM Express Base Specification Revision 2.4,§2.1、Figure 6/7(PDF p.48~49):基于内存的队列模型、Host 与控制器分工、SQ 命令与 CQ 完成项、Doorbell 和数据指针的工作关系。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询