MSI Howto中文版

1. 什么是MSI

MSI全称Message Signaled Interrupt。

当设备向一个特殊地址写入时,会向CPU产生一个中断,即也MSI中断。

MSI能力最初在PCI 2.2里定义,在PCI 3.0里被强化,使得每个中断都可以单独控制。

PCI 3.0还引入了MSI-X能力,相比MSI,每个设备可以支持更多的中断,并且可以独立配置。

设备可以同时支持MSI和MSI-X,但同一时刻只能使能其中一种。

2. 为什么使用MSI

与传统引脚中断相比,有三个方面的优势。

基于引脚的PCI中断经常在几个设备间共享,内核必须调用与该中断相关的每一个中断处理函数,降低了效率。MSI不是共享的,所以不存在这个问题。

当设备向内存写入数据,然后发起引脚中断时,有可能在CPU收到中断时,数据还未到达内存(在PCI-PCI桥后的设备更有可能如此)。为了保证数据已达内存,中断处理程序必须轮询产生该中断的设备的一个寄存器,PCI事务保序规则会确保所有数据到达内存后,寄存器才会返回值。

使用MSI时,产生中断的写不能越过数据写,因而避免了这个问题。当中断产生时,驱动可以确信所有数据已经到达内存。

PCI的每个功能设备只支持一个基于引脚的中断,驱动常常需要查询设备来确定发生的事件,降低了中断处理的效率。通过MSI,一个设备可以支持多个中断,这样可以为不同的使用不同的中断。比如:

1. 给不常发生的事件(如错误)指定独立的中断,这样驱动可以正常中断路径进行更有效的处理。

2. 给网卡的每个报文队列或者存储控制器的每个端口分配中断。

3. 如何使用MSI

PCI设备初始化为使用基于引脚的中断,设备驱动需要将设备配置为使用MSI或MSI-X。不是所有的设备可以完整支持MSI,下面有些API就直接返回失败,因此仍然使用基于引脚的中断。

3.1 内核提供MSI支持

内核需要配置CONFIG_PCI_MSI以支持MSI或者MSI-X,该配置是否可以配置受架构和其它一些配置的影响。

3.2 使用MSI

大部分工作在PCI层的驱动里完成,只需要请求PCI层为设备设置MSI能力即可。

3.2.1 pci_enable_msi

int pci_enable_msi(struct pci_dev *dev)

这个调用只给设备分配一个中断,不管设备支持多少个MSI中断。设备会从基于引脚中断模式切换为MSI模式。dev->irq会赋予一个新的代表MSI的编号。

在驱动需要在调用request_irq()之前调用这个接口。因为打开MSI中断的同时会禁用引脚中断IRQ,驱动因此不会收到旧的中断。

3.2.2 pci_enable_msi_block

int pci_enable_msi_block(struct pci_dev *dev, int count)

这个接口是pci_enable_msi的变种,它可以请求多个MSI中断。MSI规范要求中断必须以2的幂分配,最多为2^5(32)。

如果函数返回0,则表示成功分配了不少于驱动请求的中断数量(可能会大于请求数量)。该函数打开设备的MSI,并将中断组的最小编号赋给dev->irq,该设备的中断范围为dev->irq至dev->irq + count – 1。

如果函数返回负值,表示设备无法提供更多的中断,驱动不应试图再去请求。如果返回的是正值,这个值会小于count,表示目前最分配的最大中断数量。对这于两种情况,函数都不会更新irq值,设备也不会切换到MSI模式。

设备驱动必须要正确处理上述第二种情况。在中断数量不够的情况下,有的设备尚可工作,驱动就应再次调用pci_enable_msi_block()。不过由于一些限制,第二次调用未必也可以成功。

3.2.3 pci_disable_msi

void pci_disable_msi(struct pci_dev *dev)

该函数的功能是撤消pci_enable_msi()或pci_enable_msi_block()的工作。它恢复dev->irq为引脚中断号,释放此前分配的MSI。中断号之后有可能分配给其它设备,因此驱动不应保留dev->irq的值。

驱动必须调用free_irq()以释放之前request_irq()分配的中断号。否则会产生BUG_ON(),设备将继续保持MSI使能,并泄露中断向量。

3.3 使用MSI-X

MSI-X能力比MSI更为灵活,它支持2048个中断,每个中断都可以单独控制。要支持这种能力,驱动必须使用结构数组struct msix_entry。

struct msix_entry {
     u16 vector;     /* kernel uses to write alloc vector */
     u16 entry;     /* driver uses to specify entry */
}

这个定义允许设备以分散的方式使用中断(比如使用中断3和1027,只需分配两个数组元素)。驱动负责填充数组各元素的entry部分,以使内核为其分配中断。不能给多个entry赋予相同的编号。

3.3.1 pci_enable_msix

int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)

该函数向PCI子系统请求分配nvec个MSI中断。入参entries指向结构数组,元素个数不少于nvec。函数返回0表示调用成功,设备被切换至MSI-X中断模式,数组元素中的vector字段也被填充为中断号。驱动接下来为每个需要使用的vector调用request_irq()。

如果函数返回负值,则表示出错,驱动不应再从该设备申请分配MSI-X中断。如果返回的是正值,则表示最大可以分配的中断数。

该函数与pci_enable_msi()不同之处在于它不修改dev->irq,一旦MSI-X使能后,dev->irq这个中断号不会再产生中断。驱动需要记录已分配的MSI-X中断号,以保证后续的资源释放。

一般来说,驱动在设备初始化时调用一次该函数。

由于种种原因,内核有可能无法提供驱动所要求的中断数量,一个好的驱动应该能够处理可变数量的MSI-X中断。下面是一个例子:

static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
     while (nvec >= FOO_DRIVER_MINIMUM_NVEC)
     {
          rc = pci_enable_msix(adapter->pdev, adapter->msix_entries, nvec);
          if (rc > 0)
               nvec = rc;
          else
               return rc;
     }
     return -ENOSPC;
 
}

3.3.2 pci_disable_msix

void pci_disable_msix(struct pci_dev *dev)

这个函数的作用是撤销pci_enable_msix()的工作,它释放之前分配的MSI中断。同样,释放的中断号后续可能会分配给其它设备,驱动不应再记录使用这些中断号。

在调用这个函数之前,驱动必须调用free_irq()以释放request_irq()分配的中断号,否则会产生BUG_ON,设备将维持在MSI使能的状态,并泄漏中断向量。

3.3.3 MSI-X表

MSI-X能力指定了一个BAR及BAR内偏移量用于访问MSI-X表,这个地址由PCI子系统映射,驱动不应该直接访问。如果驱动想屏蔽或者开启一个中断,应该调用disable_irq()/enable_irq()。

3.4 处理同时支持MSI和MSI-X能力的设备

如果设备同时支持MSI和MSI-X,则可以运行在MSI模式或者MSI-X模式下,但不能同时运行,这是PCI规则的要求,因此PCI层也进行了限制。在MSI-X使能的情况下调用pci_enable_msi()或者在MSI使能的情况下调用pci_enable_msix()将产生错误。如果设备驱动在运行时希望在MSI和MSI-X之间切换,它必须先停止设备,然后将其切换为引脚中断模式,然后再通过pci_enable_msi()或pci_enable_msix()进入MSI或MSI-X模式。这种操作并不常见,在开发过程中用于调试/测试。

3.5 使用MSI的考虑

3.5.1 选择MSI-X和MSI

如果设备同时支持MSI-X和MSI能力,应优先考虑使用MSI-X。MSI-X支持1~2048间任意数量的中断,而MSI只支持32个中断(并且必须是2的冪)。MSI中断必须是连续分配的,系统不能像MSI-X那样分配这么多的中断向量。在某些平台上,MSI中断只能发送给一个CPU组,MSI-X中断可以发给不同的CPU。

3.5.2 spinlock

多数驱动为每个设备定义了一个spinlock,在中断处理函数中取锁,对于引脚中断或者单个MSI中断,不需要禁用中断(Linux保证同一个中断不会重入)。如果设备使用了多个中断,驱动在持锁期间必须禁用中断,否则在设备产生另一个中断时,驱动会递归取锁从而产生死锁。

有两个解决方法,一个是使用spin_lock_irqsave()或spin_lock_irq(),另一个是在request_irq()调用时指定IRQF_DISABLED,内核会在禁用中断的环境下完成整个中断处理过程。

如果MSI中断处理程序不在整个过程中持锁,使用第一种方法是最好的。如果想避免在中断禁用/使能状态间切换,则选择第二种方法。

3.6 如何得知设备的MSI/MSI-X已经使能

使用lspci -v。有些设备会显示"MSI"、"Message Signaled Interrupts"或者"MSI-X"能力,使能的会在前面显示+,禁用的会显示"-"。

4. MSI quirks

一些PCI芯片或设备不支持MSI,PCI子系统提供了三种方法禁用MSI:

1. 全局禁用

2. 禁用特定桥之下的所有设备

3. 禁用某个设备

4.1 全局禁用

有些host芯片不能正确支持MSI,如果厂家在ACPI FADT表中明确了,Linux会自动禁用MSI。有些单板没有在这个表包含这样的信息,需要自己检测,这些都列在drivers/pci/quriks.c中的quirk_disable_all_msi()中了。

如果单板在MSI支持上有问题,可以在内核命令参数里加上pci=nomsi以禁用所有设备的MSI。

4.2 禁用特定桥之下的所有设备

有些PCI桥不能在总线间正确地传递MSI,这种情况必须禁用该桥之下所有设备的MSI。

有些桥允许通过配置空间的某些位来使能MSI。在可能的情况下,Linux会尽量打开host芯片的MSI支持。如果某个桥片Linux并不识别,而你确定它可以使用MSI,可以通过下面的命令打开MSI支持。

echo 1 > /sys/bus/pci/devices/$bridge/msi_bus

$bridge是桥的PCI地址(比如0000:00:0e.0)。

要禁用MSI,使用echo 0即可。

4.3 禁用某个设备

如果某些设备已知在MSI实现上有问题,一般是在设备驱动里处理,如果有必要,也可以在quirk里处理。

4.4 设备MSI被禁用的原因查找

除上述情况外,还有很多原因会导致一个设备的MSI没有使能,第一步应该仔细检查dmesg,看MSI有没有使能,还要检查CONFIG_PCI_MSI配置有没有打开。

通过lspci -t可以查看设备之上的桥,读取/sys/bus/pci/devices/*/msi_bus看MSI是否使能了。

检查设备驱动是否支持MSI,比如是否调用了pci_enable_msi(), pci_enable_msix()或者pci_enable_msi_block()等等。

<think>我们正在处理关于"PF1MSI-Xenabled"的配置或故障排除问题。PF可能代表PhysicalFunction(物理功能),这是SR-IOV(单根I/O虚拟化)技术中的概念。MSI-X是一种中断机制,用于提高设备的中断处理效率。首先,我们需要明确用户的问题是关于配置还是故障排除。由于问题中提到了"configurationortroubleshooting",我们将涵盖这两方面。###背景知识-**SR-IOV**:允许一个物理设备(例如网卡)被虚拟化为多个虚拟设备(VF),每个VF可以直接分配给虚拟机,从而绕过Hypervisor的数据转发,提高性能。-**PF**:物理功能,具有完全控制和管理VF的能力。-**MSI-X**:MessageSignaledInterruptseXtended,是一种高级中断机制,支持更多的中断向量,可以降低中断延迟,提高多核系统的性能。###配置PF1MSI-X启用1.**检查硬件和驱动支持**:-确保硬件支持SR-IOV和MSI-X。-检查驱动是否加载并支持MSI-X。例如,对于Intel网卡,驱动可能是`igb`或`ixgbe`。2.**启用SR-IOV**:-在BIOS/UEFI中启用SR-IOV支持。-在操作系统中启用SR-IOV,并设置VF的数量。例如:```bashecho8>/sys/class/net/eth0/device/sriov_numvfs```-注意:在启用VF之前,需要确保PF处于活动状态。3.**检查并启用MSI-X**:-使用`lspci-vvv`命令查看PF的中断设置。例如,对于设备`0000:01:00.0`:```bashlspci-vvv-s0000:01:00.0|grepMSI-X```输出中应显示`MSI-X:Enable+`,表示MSI-X已启用。-如果未启用,可能需要通过驱动模块参数启用。例如,对于`ixgbe`驱动,可以在加载驱动时设置参数:```bashmodprobeixgbeenable_msix=1```或者,在模块配置文件中设置(如`/etc/modprobe.d/ixgbe.conf`):```optionsixgbeenable_msix=1```4.**验证配置**:-启用后,再次使用`lspci-vvv`确认MSI-X状态。-检查系统日志(`dmesg`)是否有相关错误信息。###故障排除1.**MSI-X无法启用**:-**原因**:硬件不支持、驱动问题、BIOS设置问题等。-**解决**:-确认硬件支持MSI-X(查看产品手册)。-更新驱动到最新版本。-检查BIOS中是否禁用了MSI-X(有些BIOS有相关设置)。2.**中断分配失败**:-当系统中断向量不足时,MSI-X可能无法分配足够的中断向量。-检查系统中断使用情况:`cat/proc/interrupts`-增加内核启动参数`pci=nomsi`(不推荐,因为这会禁用MSI/MSI-X)或`pci=noaer`(禁用高级错误报告)可能不是直接解决方案。更合适的方法是增加可用中断向量数量(通过内核参数`nr_irqs`)或优化中断分配(例如,使用IRQ平衡服务)。3.**性能问题**:-如果启用MSI-X后性能未提升,可能是中断负载不均衡。-尝试调整中断亲和性,将中断绑定到特定CPU核心:```bashecho<cpu_mask>>/proc/irq/<irq_num>/smp_affinity```-使用`irqbalance`服务自动平衡中断。4.**虚拟化环境中的问题**:-在虚拟机中使用VF时,确保Hypervisor(如KVM)正确配置了中断重映射(IntelVT-d或AMD-Vi)以避免中断重映射错误。-检查IOMMU是否启用(在BIOS和内核中)。内核启动参数应包含`intel_iommu=on`(Intel)或`amd_iommu=on`(AMD)。-如果出现中断重映射错误,可能需要更新BIOS或内核。###注意事项-修改配置前备份重要文件。-不同硬件和驱动可能有不同的配置方式,请参考具体文档。###引用在Linux内核文档中,有关MSI-X和SR-IOV的详细信息可以参考[^1]。§§相关问题§§1.如何检查系统中的设备是否支持MSI-X?2.在虚拟化环境中如何正确配置SR-IOV?3.如何解决启用MSI-X后出现的中断风暴问题?4.如何调整中断亲和性以提高网络性能?[^1]:Linuxkerneldocumentation:[PCIMSI](https://www.kernel.org/doc/html/latest/PCI/msi-howto.html)</think>### PF 1 MSI-X 启用配置与故障排除 #### **基本概念** - **PF (Physical Function)**:SR-IOV(单根I/O虚拟化)技术中的物理功能实体,可直接控制硬件资源。 - **MSI-X (Message Signaled Interrupts eXtended)**:一种高级中断机制,支持多向量中断,可减少CPU开销并提升性能[^1]。 - **PF 1 MSI-X Enabled**:指为第一个物理功能启用MSI-X中断模式,常见于网卡、GPU等硬件。 --- ### **一、配置步骤** #### 1. **检查硬件支持** ```bash lspci -vvv -s <PF_PCI地址> | grep -i "MSI-X" ``` - 输出中需包含 `MSI-X: Enable+` 和 `Capabilities: [b0] MSI-X`,确认硬件支持[^2]。 #### 2. **启用MSI-X** - **Linux 系统**: ```bash # 查看当前中断模式 grep -H ".*" /sys/class/net/<PF接口名>/device/irq_mode # 启用MSI-X (需驱动支持) echo "msix" > /sys/class/net/<PF接口名>/device/irq_mode ``` - **Windows 系统**: - 设备管理器 → 网卡属性 → "高级"选项卡 → 设置 `Interrupt Moderation` 为 `MSI-X`。 #### 3. **SR-IOV与VF关联** ```bash # 启用SR-IOV echo <VF数量> > /sys/class/net/<PF接口名>/device/sriov_numvfs # 验证VF中断模式 lspci -vvv -s <VF_PCI地址> | grep MSI-X ``` #### 4. **驱动参数调整(以Intel网卡为例)** ```bash # 加载驱动时强制启用MSI-X modprobe ixgbe enable_msix=1 # 或修改模块参数 echo "options ixgbe enable_msix=1" > /etc/modprobe.d/ixgbe.conf ``` --- ### **二、故障排除** #### 1. **MSI-X无法启用** - **症状**:`lspci` 显示 `MSI-X: Enable-`。 - **解决方案**: - 更新驱动和固件:`ethtool -i <PF接口名>` 检查驱动版本。 - BIOS设置:启用 `SR-IOV`、`VT-d`、`IOMMU`。 - 内核参数:添加 `pci=nomsi,msix` 或 `intel_iommu=on`。 #### 2. **中断风暴(High CPU Usage)** - **原因**:MSI-X向量配置不当。 - **解决**: ```bash # 调整中断亲和性 echo <CPU掩码> > /proc/irq/<IRQ编号>/smp_affinity # 例:绑定到CPU0-3 echo 0f > /proc/irq/123/smp_affinity ``` #### 3. **VF无法继承MSI-X** - **症状**:VF中断模式仍为 `MSI` 或 `Legacy`。 - **解决**: - 确认PF已启用MSI-X。 - 检查Hypervisor设置(如KVM需启用 `vfio-pci` 驱动)。 #### 4. **性能未提升** - **优化方向**: - 验证中断向量数量:`cat /proc/interrupts | grep <PF接口名>`。 - 调整队列数量: ```bash ethtool -L <PF接口名> combined <队列数> ``` --- ### **三、验证方法** 1. **中断状态**: ```bash cat /proc/interrupts | grep "MSI-X" ``` 2. **性能测试**: ```bash # 网络吞吐量测试 iperf3 -c <目标IP> -t 30 ``` 3. **诊断工具**: - `ethtool -S <PF接口名>` 查看 `msix_` 前缀的计数器。 - `perf top` 监控中断处理函数开销。 --- ### **注意事项** - **虚拟化环境**:需在Hypervisor和Guest OS同时配置MSI-X。 - **安全**:启用 `IOMMU` 防止DMA攻击。 - **兼容性**:旧版内核(<4.8)可能需手动打补丁[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值