驱动 | Linux | NVMe - 1. 概述
创始人
2024-05-25 14:30:36
0

本文主要参考2篇相关的解析 12linux 源码 3
此处推荐一个可以便捷查看 linux 源码的网站 bootlin 4

更新:2022 / 02 / 11


驱动 | Linux | NVMe - 1. 概述与nvme_core_init函数解析

  • NVMe 的前世今生
    • NVMe Command
    • PCI 总线
    • 从架构角度看 NVMe 驱动
    • NVMe 驱动的文件构成
  • NVMe Driver 工作原理
  • 参考链接


NVMe 的前世今生

NVMe 离不开 PCIeNVMe SSDPCIeendpointPCIex86 平台上一种流行的外设总线,由于其 Plug and Play 的特性,目前很多外设都通过 PCI BusHost 通信,甚至不少CPU 的集成外设都通过 PCI Bus 连接,如 APIC 等。

NVMe SSDPCIe 接口上使用新的标准协议 NVMe,由大厂 Intel 推出并交由 nvmexpress 组织推广,现在被全球大部分存储企业采纳。


NVMe Command

NVMe HostServer )和 NVMe ControllerSSD )通过 NVMe Command 进行信息交互。NVMe Spec 中定义了 NVMe Command 的格式,占用 64 字节。

NVMe Command 分为 Admin CommandIO Command 两大类,前者主要是用于配置,后者用于数据传输。

NVMe CommandHostSSD Controller 交流的基本单元,应用的 I/O 请求也要转化成NVMe Command

或许可以将 NVMe Command 理解为英语,host和SSD controller分别为韩国人和日本人,这两个 对象 需要通过英语统一语法来进行彼此的沟通和交流,Admin Command 是语法 负责语句的主谓宾结构,IO Command是单词 构成语句的具体使用词语。一句话需要语法组织语句结构和单词作为语句的填充。


PCI 总线

  1. 在操作系统启动时,BIOS 会枚举整个 PCI 的总线,之后将扫描到的设备通过 ACPI tables 传给操作系统。
  2. 当操作系统加载时,PCI Bus 驱动则会根据此信息读取各个 PCI 设备的 PCI Header Config 空间,从 class code 寄存器获得一个特征值。

class codePCI bus 用来选择哪个驱动加载设备的唯一根据。

NVMe Spec 定义的 class code010802hNVMe SSD 内部的 Controller PCIe Headerclass code 都会设置成010802h

所以,需要在驱动中指定 class code010802h,将 010802h 放入 pci_driver nvme_driverid_table,如下所示 5

static const struct pci_device_id nvme_id_table[] = {{ PCI_VDEVICE(INTEL, 0x0953),	/* Intel 750/P3500/P3600/P3700 */.driver_data = NVME_QUIRK_STRIPE_SIZE |NVME_QUIRK_DEALLOCATE_ZEROES, },......{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2005),.driver_data = NVME_QUIRK_SINGLE_VECTOR |NVME_QUIRK_128_BYTES_SQES |NVME_QUIRK_SHARED_TAGS |NVME_QUIRK_SKIP_CID_GEN |NVME_QUIRK_IDENTIFY_CNS },{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },{ 0, }
};
MODULE_DEVICE_TABLE(pci, nvme_id_table);

之后当 nvme_driver 注册到 PCI Bus 后,PCI Bus 就知道这个驱动是给 class code=010802h 的设备使用的。

nvme_driver 中有一个 probe 函数,nvme_probe(),这个函数才是真正加载设备的处理函数。


从架构角度看 NVMe 驱动

学习 Linux NVMe Driver之前,先看一下 DriverLinux 架构中的位置,如下图所示:

在这里插入图片描述
NVMe driverBlock Layer 之下,负责与 NVMe 设备交互。

为了紧跟时代的大趋势,现在的 NVMe driver 已经很强大了,也可以支持 NVMe over Fabric 相关设备,如下图所示:

在这里插入图片描述
不过,本文还是以 NVMe over PCIe 为主。


NVMe 驱动的文件构成

最新的代码位于 linux/drivers/nvme/ 6
其文件目录构成如下所示:

nvme ----

在分析一个 driver 时,最好先看这个 driver 相关的 kconfigMakefile 文件,了解其文件架构,再阅读相关的 source code

Kconfig 文件的作用是:

  1. 控制 make menuconfig 时,出现的配置选项;
  2. 根据用户配置界面的选择,将配置结果保存在 .config 配置文件(该文件将提供给 Makefile 使用,用以决定要编译的内核组件以及如何编译)

先看一下 linux/drivers/nvme/host/Kconfig 7 的内容(NVMeOF相关内容已省略,后续不再注明),如下所示:

# SPDX-License-Identifier: GPL-2.0-only
config NVME_COREtristateselect BLK_DEV_INTEGRITY_T10 if BLK_DEV_INTEGRITY
......

接着,再看一下 linux/drivers/nvme/host/Makefile 8 的内容,如下所示:

# SPDX-License-Identifier: GPL-2.0ccflags-y				+= -I$(src)obj-$(CONFIG_NVME_CORE)			+= nvme-core.o
obj-$(CONFIG_BLK_DEV_NVME)		+= nvme.o
obj-$(CONFIG_NVME_FABRICS)		+= nvme-fabrics.o
obj-$(CONFIG_NVME_RDMA)			+= nvme-rdma.o
obj-$(CONFIG_NVME_FC)			+= nvme-fc.o
obj-$(CONFIG_NVME_TCP)			+= nvme-tcp.o
obj-$(CONFIG_NVME_APPLE)		+= nvme-apple.o
......

KconfigMakefile 来看,了解 NVMe over PCIe 相关的知识点,我们主要关注 core.cpci.c 就好。


NVMe Driver 工作原理

core.c 找到程序入口 module_init(nvme_core_init);,如下所示:

static int __init nvme_core_init(void)
{int result = -ENOMEM;					......// 1. 注册字符设备 "nvme"result = alloc_chrdev_region(&nvme_ctrl_base_chr_devt, 0,NVME_MINORS, "nvme");if (result < 0)goto destroy_delete_wq;// 2. 新建一个nvme class,拥有者(Owner)是为THIS_MODULE//	  如果有Error发生,删除字符设备nvmenvme_class = class_create(THIS_MODULE, "nvme");      if (IS_ERR(nvme_class)) {result = PTR_ERR(nvme_class);goto unregister_chrdev;}nvme_class->dev_uevent = nvme_class_uevent;nvme_subsys_class = class_create(THIS_MODULE, "nvme-subsystem");if (IS_ERR(nvme_subsys_class)) {result = PTR_ERR(nvme_subsys_class);goto destroy_class;}result = alloc_chrdev_region(&nvme_ns_chr_devt, 0, NVME_MINORS,"nvme-generic");if (result < 0)goto destroy_subsys_class;nvme_ns_chr_class = class_create(THIS_MODULE, "nvme-generic");if (IS_ERR(nvme_ns_chr_class)) {result = PTR_ERR(nvme_ns_chr_class);goto unregister_generic_ns;}result = nvme_init_auth();if (result)goto destroy_ns_chr;return 0;

从上面来看,nvme_core_init 主要做了两件事:

  1. 调用 alloc_chrdev_region 9 函数,如下所示,注册一个名为 nvme 的字符设备。
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
{struct char_device_struct *cd;cd = __register_chrdev_region(0, baseminor, count, name);if (IS_ERR(cd))return PTR_ERR(cd);*dev = MKDEV(cd->major, cd->baseminor);return 0;
}
  1. 调用 class_create 函数 10,如下所示,动态创建设备的逻辑类,并完成部分字段的初始化,然后将其添加到内核中。创建的逻辑类位于 /sys/class/
#define class_create(owner, name)		\
({						\static struct lock_class_key __key;	\__class_create(owner, name, &__key);	\
})#endif	/* _DEVICE_CLASS_H_ */

在注册字符设备时,涉及到了设备号的知识点:

一个字符设备或者块设备都有一个主设备号( Major )和次设备号( Minor )。主设备号用来表示一个特定的驱动程序,次设备号用来表示使用该驱动程序的各个设备。比如,我们在 Linux 系统上挂了两块 NVMe SSD,那么主设备号就可以自动分配一个数字 (比如 8 ),次设备号分别为 12

例如,在 32 位机子中,设备号共 32 位,高 12 位表示主设备号,低 20 位表示次设备号。

有了上面已经注册的字符设备,我们就可以通过 openioctrlrelease 接口对其进行操作了。

nvme 字符设备的文件操作结构体 nvme_dev_fops 11 定义如下:

static const struct file_operations nvme_dev_fops = {.owner		= THIS_MODULE,.open		= nvme_dev_open,.release	= nvme_dev_release,.unlocked_ioctl	= nvme_dev_ioctl,.compat_ioctl	= compat_ptr_ioctl,.uring_cmd	= nvme_dev_uring_cmd,
};


参考链接


  1. Linux中nvme驱动详解 ↩︎

  2. Linux NVMe Driver学习笔记之1:概述与nvme_core_init函数解析 ↩︎

  3. linux ↩︎

  4. bootlin ↩︎

  5. linux/drivers/nvme/host/pci.c ↩︎

  6. linux/drivers/nvme/ ↩︎

  7. linux/drivers/nvme/host/Kconfig ↩︎

  8. linux/drivers/nvme/host/Makefile ↩︎

  9. linux/fs/char_dev.c ↩︎

  10. linux/include/linux/device.h ↩︎

  11. linux/drivers/nvme/host/core.c ↩︎

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...