首页 > 其他分享 >Intel710驱动代码分析-i40e_probe

Intel710驱动代码分析-i40e_probe

时间:2023-12-08 16:31:48浏览次数:35  
标签:Intel710 I40E VF probe i40e FLAG num pf SRIOV

前言

在710的这个专栏里,我上篇文章中主要分析了驱动代码中的注册函数以及注册所需的结构体,其中有很多内容,今天我们围绕i40e_probe这个探测函数进行分析,由于研究原因以及时间原因,对这个驱动代码的分析,还是紧紧围绕虚拟化这个部分来分析,也就是VF。

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


i40e_probe

该函数位于:i40e_main.c函数下,共计700多行。代码比较多其中包括了配置DCB,配置dma的高低地址,设置pci的链接,设置mac类型,初始化adminq(710自己定义的cmd命令函数),sw初始化,

配置SRIOV,配置二层VLAN等等等等,很多很多内容,我们主要关注就是配置SRIOV。


CONFIG_PCI_IOV

该函数中有关配置虚拟化的主要有以下两个部分:

两部分都是针对SR-IOV(Single Root I/O Virtualization)的支持

第一部分

#ifdef CONFIG_PCI_IOV
	/* prep for VF support */
	if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
	    (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
	    !test_bit(__I40E_BAD_EEPROM, pf->state)) {
		if (pci_num_vf(pdev))
			pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
#if !defined(HAVE_SRIOV_CONFIGURE) && !defined(HAVE_RHEL6_SRIOV_CONFIGURE)
		else if (pf->num_req_vfs)
			pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
#endif
	}
#endif
#ifdef CONFIG_PCI_IOV

这是一个条件编译的预处理指令,用于判断是否启用了 PCI SR-IOV 支持。如果在内核配置中启用了 PCI SR-IOV,那么该段代码将被编译,否则将被忽略。

	if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
	    (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
	    !test_bit(__I40E_BAD_EEPROM, pf->state))

件判断,检查是否满足启用 SR-IOV 的条件。具体条件包括:设备的标志中开启了 SR-IOV、开启了 MSI-X(Message Signaled Interrupts Extension),并且 EEPROM 中没有标记为坏的。

其中MSI-X也是PCIE标准中定义的中断类型,简单来说,pcie中定义了三种中断,分别为INTx中断,MSI中断,MSI-X中断,其中INTx是可选的,MSI/MSI-X是必须实现的。

MSI, message signal interrupt, 是PCI设备通过写一个特定消息到特定地址,从而触发一个CPU中断。MSI-X是对MSI中断的增强和扩展。(后续如果有机会或者有时间我会再开一个专栏分析pcie的标准,其实已经准备一部分了,只是因为时间关系,暂时可能没有时间去跟新PCIE这部分。)

	if (pci_num_vf(pdev))

调用 pci_num_vf 函数,检查 PCIe 设备是否支持虚拟函数(VF)。如果支持,将设备标志 I40E_FLAG_VEB_MODE_ENABLED 置位。VF 是 SR-IOV 的一部分,用于创建多个虚拟设备,使得多个虚拟机可以直接访问硬件资源。

其中标志位I40E_FLAG_VEB_MODE_ENABLED 就是个寄存器的位,如果该位使能,则表明开启了VEB。VEB是什么呢?

VEB(Virtual Ethernet Bridge,虚拟以太网交换机)是虚拟机与服务器网络接入层之间的一个新的网络层。解决的是同一服务器中不同虚拟机如何通过同一张物理网卡与外部网络进行通信,以及这些虚拟机之间如何互相通信的问题。

当然上面如果理解不了也没关系,不重要,我们继续进行我们的代码分析即可。

#if !defined(HAVE_SRIOV_CONFIGURE) && !defined(HAVE_RHEL6_SRIOV_CONFIGURE)

这是一个条件编译,当系统没有定义 HAVE_SRIOV_CONFIGURE 和 HAVE_RHEL6_SRIOV_CONFIGURE 时,执行下面的操作。

		else if (pf->num_req_vfs)
			pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;

如果系统不支持 HAVE_SRIOV_CONFIGURE 和 HAVE_RHEL6_SRIOV_CONFIGURE,则检查是否有请求的 VF 数量大于零。如果是,同样将设备标志 I40E_FLAG_VEB_MODE_ENABLED 置位。这里的 num_req_vfs 表示期望启用的 VF 的数量。

那么以上就是第一部分,总体而言就是通过一系列的判断,如果都满足要求,就将寄存器中veb 模式的位置1,表示启用veb启用虚拟化vf。


第二部分

#ifdef CONFIG_PCI_IOV
	/* prep for VF support */
	if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
	    (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
	    !test_bit(__I40E_BAD_EEPROM, pf->state)) {
		/* disable link interrupts for VFs */
		val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM);
		val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
		wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val);
		i40e_flush(hw);
		/* allocate memory for VFs mac list backup */
		val = max_t(int, pci_num_vf(pdev), pf->num_req_vfs);
		if (val) {
			u32 index;

			pf->mac_list = kcalloc(val,
					       sizeof(struct list_head),
					       GFP_KERNEL);
			if (!pf->mac_list)
				goto err_vsis;
			for (index = 0; index < val; index++)
				INIT_LIST_HEAD(&pf->mac_list[index]);
		}

		if (pci_num_vf(pdev)) {
			dev_info(&pdev->dev,
				 "Active VFs found, allocating resources.\n");
			err = i40e_alloc_vfs(pf, pci_num_vf(pdev));
			if (err)
				dev_info(&pdev->dev,
					 "Error %d allocating resources for existing VFs\n",
					 err);
#if !defined(HAVE_SRIOV_CONFIGURE) && !defined(HAVE_RHEL6_SRIOV_CONFIGURE)
		} else if (pf->num_req_vfs) {
			err = i40e_alloc_vfs(pf, pf->num_req_vfs);
			if (err) {
				pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
				dev_info(&pdev->dev,
					 "failed to alloc vfs: %d\n", err);
			}
#endif /* HAVE_SRIOV_CONFIGURE */
		}
	}
#endif /* CONFIG_PCI_IOV */

先判断是否有宏CONFIG_PCI_IOV,有的话就继续执行下面的代码:


这部分跟我们上面分析第一部分的开头是一样的,不再过多赘述。

	if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
	    (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
	    !test_bit(__I40E_BAD_EEPROM, pf->state)) {

接下来:

		val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM);
		val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
		wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val);
		i40e_flush(hw);

通过读取和修改寄存器的方式,禁用 VF 的链路中断。这是因为 VF 是虚拟设备,不需要链路状态的中断。然后调用函数i40e_flush(hw)刷新硬件。

		val = max_t(int, pci_num_vf(pdev), pf->num_req_vfs);
		if (val) {
			u32 index;

			pf->mac_list = kcalloc(val,
					       sizeof(struct list_head),
					       GFP_KERNEL);
			if (!pf->mac_list)
				goto err_vsis;
			for (index = 0; index < val; index++)
				INIT_LIST_HEAD(&pf->mac_list[index]);
		}

为 VF 的 MAC 地址列表备份分配内存。根据 VF 的数量(val),使用 kcalloc 分配一个数组,每个元素是一个 struct list_head。这个数组被用于保存 VF 的 MAC 地址列表。

		if (pci_num_vf(pdev))  {
			dev_info(&pdev->dev,
				 "Active VFs found, allocating resources.\n");
			err = i40e_alloc_vfs(pf, pci_num_vf(pdev));
			if (err)
				dev_info(&pdev->dev,
					 "Error %d allocating resources for existing VFs\n",
					 err);

检查 PCIe 设备是否支持 VF。如果支持,则输出调试信息,表示发现了活动的 VF,然后调用 i40e_alloc_vfs 分配 VF 的资源。

#if !defined(HAVE_SRIOV_CONFIGURE) && !defined(HAVE_RHEL6_SRIOV_CONFIGURE)
		} else if (pf->num_req_vfs) {
			err = i40e_alloc_vfs(pf, pf->num_req_vfs);
			if (err) {
				pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
				dev_info(&pdev->dev,
					 "failed to alloc vfs: %d\n", err);
			}

如果系统不支持 HAVE_SRIOV_CONFIGURE 和 HAVE_RHEL6_SRIOV_CONFIGURE,检查是否有请求的 VF 数量大于零。如果是,调用 i40e_alloc_vfs 分配 VF 的资源。

		pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;

如果分配 VF 的资源失败,清除设备该标志位 ,表示禁用SRIOV。

最后附上该函数中有关sriov的执行流程图:

Intel710驱动代码分析-i40e_probe_Intel710

标签:Intel710,I40E,VF,probe,i40e,FLAG,num,pf,SRIOV
From: https://blog.51cto.com/u_16160587/8740148

相关文章

  • 使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题
    版本Linux6.5背景在学习cgroupv2的时候,想给子cgroup开启cpu控制器结果失败了:#查看可以开启哪些控制器root@ubuntu-vm:/sys/fs/cgroup#catcgroup.controllerscpusetcpuiomemoryhugetlbpidsrdmamisc#上面看到,是支持cpu控制器的,通过下面命令查看目前子cgroup开启......
  • Intel710驱动代码分析-i40e_driver
    由于研究学习的需要,要对intelXL710网卡的驱动代码进行分析,主要分析其VF的相关代码,整个代码量相当大,有数万行。当然我也是从头开始学,一点一点分析并记录在51cto的博客中,如果大家在阅读过程中发现有错误,请及时提出,另外我会专门开一个专栏,用来记录对每个函数的分析,有些可能会对每行......
  • kprobes源码走读
    粗略看了下kernel/kprobes.c下的register_kprobe方法。逻辑:调用kprobe_addr方法来根据symbol或者addr+offset来获取需要劫持的地址,symbol和addr不能同时设置,symbol是利用kprobe_lookup_name->kallsyms_lookup_name来查找内核中的符号地址。检查这个kprobe是否重注册了?......
  • probe函数
    驱动注册的probe函数probe(探测)函数在设备驱动注册最后收尾工作,当设备的device和其对应的driver在总线上完成配对之后,系统就调用 platform设备的probe函数完成驱动注册最后工作。资源、 中断调用函数以及其他相关工作。下面是probe被调用的一些程序流程。从driver_register看......
  • android ebpf之uprobe原理和检测方法
    uprobe通过内核层对用户层进程的指定地址的原指令copy到其他位置,然后写入指定类型中断指令,然后内核中设置对应的中断处理程序,中断处理程序中执行uprobe设置的回调过滤函数,然后设置单步执行copy的原指令后恢复寄存器状态继续执行。ida查看被uprobehook的函数头部,指令被修改为了中断......
  • DNS_PROBE_STARTED 错误分析
    这种错误通常是由于DNS(DomainNameSystem,域名系统)解析问题引起的。在本文中,我将详细解释DNS_PROBE_STARTED错误的含义,并提供一些可能的原因和解决方法。一、DNS_PROBE_STARTED错误的含义当您在Chrome浏览器中访问网页时,浏览器会首先尝试将网站域名(如www.example.com)解析为对应的IP......
  • DNS_PROBE_FINISHED_BAD_CONFIG 错误分析
    常见错误电脑上能够正常使用微信电脑版访问网络,但在Chrome浏览器里无法打开任何网页,出现了DNS_PROBE_FINISHED_BAD_CONFIG的提示。这种错误通常是由于DNS(DomainNameSystem,域名系统)配置错误引起的。在本文中,我将详细解释DNS_PROBE_FINISHED_BAD_CONFIG错误的含义,并提供一些......
  • ffprobe获取视频信息,编码转换,设置关键帧间隔等操作
    查看关键帧间隔ffprobe-select_streamsv-show_entriespacket=pts_time,duration_time,flags-ofcsv=p=0test.mp4输出格式由packet=pts_time,duration_time,flags指定,pts_time指帧的时间戳,duration_time指帧播放时长,它等于1/framerate秒,flag指帧标志,K_表示关键帧。视频流......
  • Go每日一库之137:easeprobe(探活工具)
    服务探活在现实场景中应用广泛,比如:服务发现、服务负载均衡、服务调度、服务状态监控等。然而,“探活”往往是作为一个功能模块或者组件集成在各个平台系统中。本次要介绍的easeprobe是一款轻量级的,可独立运行的探活工具,利用easeprobe,无需其他系统支持,就可以对多种类型的服务/中间件......
  • Kubesphere安装DevOps时Jenkins报Readiness probe failed
    1.问题安装Kubesphere官方文档,启用DevOps组件,然后等待安装完后,发现devops-jenkins-xxxx-xxxx的pod一直起不来,describe一下,发现报错:Readinessprobefailed:Get"http://10.244.36.83:8080/login":dialtcp10.244.36.83:8080:connect:connectionrefused2.解决这种情......