Intel710驱动代码分析-i40e_driver
  j12w6g2rqsge 2023年12月06日 23 0

由于研究学习的需要,要对intel XL710网卡的驱动代码进行分析,主要分析其VF的相关代码,整个代码量相当大,有数万行。当然我也是从头开始学,一点一点分析并记录在51cto的博客中,如果大家在阅读过程中发现有错误,请及时提出,另外我会专门开一个专栏,用来记录对每个函数的分析,有些可能会对每行代码进行分析。


代码在github上有共享链接在这:i40e 大家如有需要可自行下载。

那么今天就从i40e的驱动中i40e_driver的这个结构体出发,一点一点抽丝剥茧来看来分析。


首先一个设备的驱动程序,一般来说都有一个接口,因为一个硬件插入到主机当中,一定是要通过驱动来讲这个设备注册到系统里,通过初始化模块来注册,基本每个驱动都会包含这样一个结构体:

在驱动i40e_main.c函数中的大致18386行的位置。也可以搜索这个名字找到。

Intel710驱动代码分析-i40e_driver_probe

上图是710代码中的i40e驱动,其中包含了name、probe、 remove(移除设备)、shutdown(关闭设备) 等等还有一些是不同驱动的不同特性,这个结构体的主要作用就是用来想操作系统注册该设备。

我们在这段代码中主要关心两个一个是i40e_probe,这是个函数,用以对驱动中模块的初始化。

还有个是sriov_configure,sriov就是虚拟化,也就是vf。这个定义是由pcie标准中提出的。简单理解就是像操作系统中有虚拟机一样,给网卡设备也增加了类似虚拟机的功能,称之为VF,他们相互隔离,共用一个硬件设备。提高网卡的性能。

大概的介绍完毕了,我们来具体的看一看这个结构体:

首先

.name     = i40e_driver_name,

其中的name是驱动设备的名称

i40e_driver_name

我们可以点进去。是一个char类型的数组:

char i40e_driver_name[] = "i40e";

也就是驱动程序的名称:i40e。

紧接着第二个:

.id_table = i40e_pci_tbl,

id_table指的是PCI设备的ID表,指向i40e_pci_tbl,用于匹配驱动程序和PCI设备

详细内容如下:

static const struct pci_device_id i40e_pci_tbl[] = {
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_XL710), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QEMU), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_B), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_C), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_A), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_B), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_5G_BASE_T_BC), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_BC), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_SFP), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_B), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2_A), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_X710_N3000), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_XXV710_N3000), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_X722), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_X722), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_1G_BASE_T_X722), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_X722), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_I_X722), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_B), 0},
	{PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_SFP28), 0},
	/* required last entry */
	{0, }
};

第三个:设备的探针(探测函数)

.probe    = i40e_probe,

用于pci设备被发现时调用。

第四个:设备移除函数

.remove   = i40e_remove,

指向了i40e_remove函数,用于从操作系统中移除该驱动程序

其中有个宏:

#ifdef HAVE_CONFIG_HOTPLUG
	.remove   = __devexit_p(i40e_remove),
#else
	.remove   = i40e_remove,
#endif

该宏指的是是否支持热插拔,根据宏判断选择执行哪个移除函数。

第五个:关机函数

.shutdown = i40e_shutdown,

指向设备关机函数 i40e_shutdown,在系统关机时调用。

第六个:错误处理函数

.err_handler = &i40e_err_handler,

如果系统支持 PCI 错误恢复(PCI Error Recovery System),则指向错误处理函数 i40e_err_handler。

第七个:虚拟化配置

.sriov_configure = i40e_pci_sriov_configure,

如果系统支持 SR-IOV(Single Root I/O Virtualization),则指向 SR-IOV 配置函数 i40e_pci_sriov_configure。

其中还有个COFIG_PM,这个是电源管理

#ifdef CONFIG_PM
#ifdef USE_LEGACY_PM_SUPPORT
	.suspend  = i40e_legacy_suspend,
	.resume   = i40e_legacy_resume,
#else /* USE_LEGACY_PM_SUPPORT */
	.driver   = {
		.pm = &i40e_pm_ops,
	},
#endif /* !USE_LEGACY_PM_SUPPORT */
#endif /* CONFIG_PM */

如果系统支持电源管理(CONFIG_PM 定义),则指向电源管理操作结构 i40e_pm_ops。这是用于支持设备的挂起和恢复操作。

suspend 和 resume:如果系统不使用遗留的电源管理支持,而是使用新的 PM runtime 框架,那么会使用这两个回调函数。

最后有两个:

#ifdef HAVE_RHEL6_SRIOV_CONFIGURE
	.rh_reserved = &i40e_driver_rh,
#endif
#ifdef HAVE_RHEL7_PCI_DRIVER_RH
	.pci_driver_rh = &i40e_driver_rh,
#endif

rh_reserved、pci_driver_rh:这些属性可能与 Red Hat Enterprise Linux 特定的配置有关,用于指定一些特殊的配置或回调。这两个我们不作关系。

总体而言,这个结构体描述了 i40e 驱动程序的一些基本信息和操作回调函数,用于注册到 PCI 子系统中,方便后续驱动的执行。


这个结构体一般是用在以下这个函数中:

static int __init i40e_init_module(void)
{
	pr_info("%s: %s - version %s\n", i40e_driver_name,

		i40e_driver_string, i40e_driver_version_str);
	pr_info("%s: %s\n", i40e_driver_name, i40e_copyright);


	i40e_wq = alloc_workqueue("%s", 0, 0, i40e_driver_name);
	if (!i40e_wq) {
		pr_err("%s: Failed to create workqueue\n", i40e_driver_name);
		return -ENOMEM;
	}
#ifdef HAVE_RHEL7_PCI_DRIVER_RH
#endif
	i40e_dbg_init();
	return pci_register_driver(&i40e_driver);
}
module_init(i40e_init_module);

其中module_init是个linux内核函数,用来加载模块,加载的模块就是上面 i40e_init_module,这个函数实际意义就是要执行上面的那个结构体。通过调用pci_register_driver来执行。

那么以上就是i40e_driver的一些基本内容分析以及模块注册。

后续我会继续分析710这个驱动,当然主要是跟虚拟化VF有关的代码。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月06日 0

暂无评论

j12w6g2rqsge