初始化和配置
初始化和配置NVMe-PCIe SSD涉及以下数据结构和环境:
-
PCI设备标识信息:PCIe总线上的设备会被识别和配置,主机会读取设备的供应商ID、设备ID、类别码等信息,以确认设备类型和特性。
-
NVMe命名空间(Namespace):NVMe SSD可以划分为多个命名空间,每个命名空间对应一个逻辑存储区域。主机需要识别并配置哪些命名空间可供使用。
-
PCI配置空间:主机通过读取和写入NVMe-PCIe SSD的PCI配置空间寄存器来获取设备的配置信息和状态,如设备ID、供应商ID、BARs(Base Address Registers)等。
-
命令队列和队列门铃:主机为NVMe-PCIe SSD配置命令队列和队列门铃。命令队列是主机与NVMe控制器交换NVMe命令的缓冲区,队列门铃用于通知NVMe控制器有新的命令待处理。
-
内存分配:主机需要为NVMe-PCIe SSD分配适当的内存资源,用于存储命令队列、数据缓冲区以及用于管理和传输数据的其他数据结构。
-
中断处理:主机需要配置中断处理机制,以便在NVMe-PCIe SSD操作完成时接收中断信号。这样可以通知主机操作的状态、结果或错误信息。
-
块大小和页大小:主机和NVMe-PCIe SSD之间需要协商并配置适当的块大小和页大小,以确保数据传输的一致性和兼容性。
-
驱动程序和固件:主机操作系统需要正确加载和配置与NVMe-PCIe SSD交互的驱动程序。同时,NVMe-PCIe SSD的固件也需要适当的配置和升级,以确保设备的正常运行和功能支持。
通过正确的初始化和配置,主机和NVMe-PCIe SSD之间可以建立有效的通信和数据交换。这些数据结构和环境的配置确保了系统能够正常使用NVMe-PCIe SSD并发挥其高性能和低延迟的优势。
下面是一个简化的示例,说明了初始化和配置NVMe-PCIe SSD的流程:
-
PCI设备标识信息:
- 供应商ID:设备ID:类别码
- 例:供应商ID:0x1234,设备ID:0xABCD,类别码:0x0108
-
NVMe命名空间(Namespace):
- 可能存在多个命名空间,每个命名空间对应不同的存储区域。
- 例:命名空间1:容量100GB,命名空间2:容量200GB
-
PCI配置空间:
- 读取PCIe配置空间寄存器获取设备信息。
- 例:设备ID:0xABCD,供应商ID:0x1234,BAR0:0x12345678
-
命令队列和队列门铃:
- 配置主机中的命令队列和队列门铃,分配内存资源。
- 例:命令队列大小:64个条目,队列门铃地址:0xAABBCCDD
-
内存分配:
- 主机分配内存资源,用于存储命令队列和数据缓冲区。
- 例:命令队列内存地址:0x80000000,数据缓冲区地址:0x90000000
-
中断处理:
- 配置主机中断处理机制,以接收NVMe-PCIe SSD的中断信号。
- 例:中断号:5,中断处理程序:0xABCDEF01
-
块大小和页大小:
- 主机和NVMe-PCIe SSD协商并配置适当的块大小和页大小。
- 例:块大小:4KB,页大小:8KB
-
驱动程序和固件:
- 主机加载适当的NVMe驱动程序,与NVMe-PCIe SSD交互。
- NVMe-PCIe SSD固件配置和升级,以确保设备的正常运行。
这些示例说明了在初始化和配置NVMe-PCIe SSD过程中所涉及的一些关键数据结构和环境。
NVMe控制器识别
NVMe控制器的识别过程涉及以下步骤:
-
PCI设备枚举:在系统启动期间,主机会对PCIe总线上的设备进行枚举。它会扫描每个PCIe插槽,识别插入的设备。
-
PCI配置空间访问:当主机识别到NVMe-PCIe SSD设备后,它会通过访问设备的PCI配置空间来获取设备的配置信息和状态。PCI配置空间包含一组寄存器,描述设备的特性和资源需求。
-
Vendor ID和Device ID匹配:主机通过读取设备的Vendor ID(供应商ID)和Device ID(设备ID),与预定义的ID列表进行匹配。这样可以确定设备是否是一个NVMe SSD。
-
配置寄存器读取:主机读取设备的配置寄存器,以获取更详细的设备信息。这些寄存器包括Class Code(类别码)、Subsystem Vendor ID(子系统供应商ID)、Subsystem ID(子系统ID)等。
-
BAR(Base Address Register)解析:主机读取设备的BARs寄存器,确定设备的基址信息。其中,BAR0通常包含NVMe控制器的内存映射I/O(MMIO)地址。
-
NVMe命名空间发现:主机通过NVMe控制器的命名空间信息,确定设备上存在的NVMe命名空间数量和容量。
-
驱动程序加载和绑定:主机加载适当的NVMe驱动程序,并与识别到的NVMe控制器进行绑定。这样,主机操作系统就可以与NVMe控制器进行通信和交互。
通过上述过程,主机能够识别和确定NVMe控制器的位置、特性和功能。这是初始化和配置NVMe-PCIe SSD的重要一步,为后续的NVMe命令交换和数据传输建立了基础。
Controller Properties寄存器
在NVMe规范中,Controller Properties寄存器空间是用于配置和管理NVMe控制器属性的一组寄存器。下面是Controller Properties寄存器空间的初始化流程的一般步骤:
-
识别NVMe控制器:系统首先要识别和确定所连接的NVMe控制器,通过PCIe总线上的设备枚举和PCI配置空间的访问来实现。
-
获取Controller Capabilities寄存器:通过访问NVMe控制器的Controller Capabilities寄存器,获取控制器的功能和属性信息。这个寄存器包含了控制器支持的特性和能力,如命名空间数量、队列深度、电源管理等。
-
初始化Controller Configuration寄存器:根据系统需求和控制器的能力,配置Controller Configuration寄存器。这个寄存器包含控制器的配置选项,如中断向量分配、命名空间选择等。可以通过写入相应的值来设置所需的属性。
-
分配和初始化命令队列:根据控制器的队列深度能力,分配适当大小的命令队列内存区域。然后,初始化命令队列寄存器,设置命令队列的基址和大小。
-
分配和初始化Doorbell寄存器:为每个命令队列分配相应的Doorbell寄存器。Doorbell寄存器用于通知控制器有新的命令待处理。需要设置Doorbell寄存器的基址和大小。
-
分配和初始化中断向量:如果系统支持中断模式,需要分配适当数量的中断向量并进行初始化。每个命令队列可以分配一个独立的中断向量。
-
配置Memory Buffer寄存器:Memory Buffer寄存器用于配置主机和NVMe控制器之间的数据传输缓冲区。可以设置Memory Buffer的基址和大小。
-
其他Controller Properties寄存器的配置:根据需要,可以配置其他Controller Properties寄存器,如Power State、Error Log、Interrupt Coalescing等,以满足特定的系统要求。
以上流程是一个一般的初始化过程示例,具体的初始化流程可能因NVMe控制器和系统的不同而有所差异。根据NVMe规范和设备厂商的要求,进行相应的寄存器初始化和配置,以确保NVMe控制器的正确运行和功能支持。
Controller Properties寄存器和AQA,ASQ,ACQ 寄存器之间的关联
Controller Properties寄存器和AQA(Admin Queue Attributes)、ASQ(Admin Submission Queue)、ACQ(Admin Completion Queue)寄存器之间存在关联。它们共同用于管理和配置NVMe控制器的管理队列。
-
AQA(Admin Queue Attributes)寄存器:AQA寄存器包含了管理队列的属性信息,其中的字段描述了管理队列的大小、基址和其他属性。AQA寄存器通常在控制器初始化过程中进行配置,用于指定管理队列的基址和大小。
-
ASQ(Admin Submission Queue)和ACQ(Admin Completion Queue)寄存器:ASQ和ACQ寄存器分别指定管理队列的提交队列和完成队列的基址。它们存储了相应队列的物理地址。这些队列用于主机与NVMe控制器之间的管理命令和响应的交换。
-
AQA寄存器与ASQ、ACQ寄存器之间的关系:AQA寄存器中的ASQS(Admin Submission Queue Size)字段定义了提交队列的大小,即队列中可存放的命令数目。同时,AQA寄存器中的ACQS(Admin Completion Queue Size)字段定义了完成队列的大小,即队列中可存放的完成条目数目。ASQ和ACQ寄存器通过AQA寄存器中的ASQB(Admin Submission Queue Base Address)和ACQB(Admin Completion Queue Base Address)字段来获取队列的基址。
通过配置AQA寄存器,可以确定管理队列的大小和基址。ASQ和ACQ寄存器则用于获取提交队列和完成队列的基址。这些寄存器协同工作,确保主机能够与NVMe控制器正确交互,并进行管理命令的提交和接收响应。
需要注意的是,除了AQA、ASQ和ACQ寄存器,还有其他与管理队列相关的寄存器,如ASQ Tail Pointer、ASQ Head Pointer、ACQ Tail Pointer、ACQ Head Pointer等,用于管理队列的操作和状态跟踪。这些寄存器共同构成了管理队列的框架,实现了主机和NVMe控制器之间的管理通信。
管理队列框架
管理队列是用于主机与NVMe控制器之间进行管理命令和响应交换的一种机制。它是NVMe规范定义的一部分,为控制器配置和管理提供了统一的接口。管理队列的框架包括以下关键组成部分:
-
Admin Submission Queue (ASQ):ASQ是管理命令的提交队列。主机将管理命令放入ASQ中,并通过提交队列的Doorbell寄存器来通知控制器有新的命令待处理。
-
Admin Completion Queue (ACQ):ACQ是管理命令的完成队列。控制器将处理完的管理命令结果放入ACQ中,并使用完成队列的Doorbell寄存器通知主机有新的结果可用。
-
Admin Queue Attributes (AQA):AQA寄存器包含了管理队列的属性信息,如队列的大小和基址。主机在初始化过程中配置AQA寄存器,以确定ASQ和ACQ的大小和位置。
-
Doorbell寄存器:ASQ和ACQ都有关联的Doorbell寄存器,用于通知控制器或主机有新的命令或结果待处理。当主机往ASQ写入命令或往ACQ写入结果后,通过写入Doorbell寄存器,触发控制器或主机处理相应的队列。
-
Submission Queue Entry (SQE):SQE是管理命令的提交队列条目,包含了管理命令的各个字段,如命令类型、命名空间ID、数据缓冲区等。
-
Completion Queue Entry (CQE):CQE是管理命令的完成队列条目,包含了管理命令执行结果的各个字段,如状态码、命令标识符等。
通过管理队列的框架,主机可以通过ASQ将管理命令提交给NVMe控制器,控制器处理命令后将结果放入ACQ,然后主机通过读取ACQ获取结果。这样实现了主机与控制器之间的管理通信和命令处理。
需要注意的是,管理队列的框架是NVMe规范定义的通用机制,具体的实现可能会因厂商、驱动程序或操作系统的不同而有所差异。但总体上,管理队列提供了一种可靠且高效的方式,用于配置和管理NVMe控制器的各种属性和功能。
PCS里面的Header Class code
在PCIe协议中,PCS(Physical Coding Sublayer)是用于处理物理层编码和解码的子层。Header Class code(头部类别码)是PCIe设备的配置空间中的一个字段,用于标识设备的类别和功能。
在PCIe设备的配置空间中,Header Class code位于Configuration Header的Class Code字段,占据8个位(3个字节),包含了Class、Subclass和Programming Interface三个子字段。
具体的格式如下:
- Class:占据8个位,用于标识设备的类别,例如存储控制器、网络控制器、图形控制器等。
- Subclass:占据8个位,用于细分设备类别,例如存储控制器中的SATA控制器、NVMe控制器等。
- Programming Interface:占据8个位,用于标识设备的具体功能和接口。
通过读取Header Class code字段,系统可以了解到PCIe设备的类别和功能。这对于操作系统和设备驱动程序的正确识别和配置非常重要,因为不同的设备类别和功能可能需要特定的驱动程序和设置。
举个例子,如果一个PCIe设备的Header Class code字段为0x010802,则可以解读为:
- Class:0x01,表示存储控制器。
- Subclass:0x08,表示NVMe控制器。
- Programming Interface:0x02,表示具体的接口或功能。
这样的Header Class code可以帮助操作系统和驱动程序识别该设备为NVMe控制器,并为其提供相应的支持和配置。
Memory-based Transport Controller Initialization
在执行相关的NVMe传输绑定规范中定义的特定传输的控制器初始化步骤之后,主机应按照以下顺序执行以下操作来初始化控制器以开始执行命令:
- 主机等待控制器通过将CSTS.RDY设置为0来指示任何先前的复位已完成。
- 主机通过将Admin Queue属性(AQA)、Admin Submission Queue基地址(ASQ)和Admin Completion Queue基地址(ACQ)设置为适当的值来配置Admin队列。
- 主机通过检查CAP.CSS的状态并相应地初始化CC.CSS来确定支持的I/O命令集,具体如下:
a. 如果CAP.CSS的第7位设置为1,则CC.CSS字段应设置为111b;
b. 如果CAP.CSS的第6位设置为1,则CC.CSS字段应设置为110b;
c. 如果CAP.CSS的第6位清除为0且第0位设置为1,则CC.CSS字段应设置为000b。 - 应配置控制器设置,具体包括:
a. 在CC.AMS中选择仲裁机制;
b. 在CC.MPS中初始化内存页大小。 - 主机通过将CC.EN设置为1来启用控制器。
- 主机等待控制器指示控制器已准备好处理命令。当CSTS.RDY设置为1时,控制器已准备好处理命令。
- 主机通过发出指定Identify控制器数据结构(即CNS为01h)的Identify命令来确定控制器的配置。
- 主机根据以下方式确定任何I/O命令集的特定配置信息:
a. 如果CAP.CSS的第6位设置为1,则主机执行以下操作:
i. 使用指定的Identify I/O命令集数据结构(CNS为1Ch)发出Identify命令;
ii. 使用指定的I/O命令集配置文件特征标识符(FID为19h)和所要启用的I/O命令集组合的索引(参考Figure 289)发出Set Features命令。
b. 对于每个已启用的I/O命令集(注意:如果CC.CSS字段设置为000b,则启用了NVM命令集):
i. 使用指定的I/O命令集特定活动命名空间ID列表(CNS为07h)和该I/O命令集的适当命令集标识符(CSI)值发出Identify命令;
ii. 对于返回的每个NSID:
1. 如果已启用的I/O命令集是NVM命令集或基于NVM命令集的I/O命令集(例如,分区命令集),则使用指定的Identify命名空间数据结构(CNS为00h)发出Identify命令;
2. 使用每个以下数据结构发出Identify命令(参考Figure 274):I/O命令集特定的Identify命名空间数据结构、I/O命令集特定的Identify控制器数据结构和I/O命令集独立的Identify命名空间数据结构。 - 如果控制器实现了I/O队列,则主机应使用带有队列数量特性标识符的Set Features命令来确定支持的I/O提交队列和I/O完成队列的数量。确定了I/O队列的数量后,应配置NVMe传输特定的中断寄存器(例如,MSI和/或MSI-X寄存器)。
- 如果控制器实现了I/O队列,则主机应根据系统配置所需的数量和控制器支持的数量分配适当数量的I/O完成队列。使用Create I/O Completion Queue命令分配I/O完成队列。
- 如果控制器实现了I/O队列,则主机应根据系统配置所需的数量和控制器支持的数量分配适当数量的I/O提交队列。使用Create I/O Submission Queue命令分配I/O提交队列。
- 为了启用可选事件的异步通知,主机应使用指定要启用的事件的Set Features命令。为了启用事件的异步通知,主机应提交适当数量的Asynchronous Event Request命令。此步骤可以在控制器信号控制器已准备好(即CSTS.RDY设置为1)之后的任何时刻执行。
执行完这些步骤后,控制器将准备好处理主机发出的Admin或I/O命令。
在退出D3电源状态时,应遵循上述初始化步骤。
参考:NVME SPEC : NVM-Express-Base-Specification-2.0c-2022.10.04-Ratified.pdf(3.5.1)