MSI

  • 4. MSI驱动指南HOWTO
    • 4.1. 关于本指南
    • 4.2. 什么是 MSI?
    • 4.3. 为什么要使用 MSI?
    • 4.4. 如何使用 MSI
      • 4.4.1. 包括对 MSI 的内核支持
      • 4.4.2. 使用MSI
      • 4.4.3. 传统API
      • 4.4.4. 使用 MSI 时的注意事项
        • 4.4.4.1 自旋锁
      • 4.4.5. 如何判断设备上是否启用了 MSI/MSI-X
    • 4.5. MSI quirks
      • 4.5.1. 全局禁用 MSI
      • 4.5.2. 在网桥下禁用 MSI
      • 4.5.3. 在单个设备上禁用 MSI
      • 4.5.4. 查找设备上禁用 MSI 的原因

英文链接:The MSI Driver Guide HOWTO

4. MSI驱动指南HOWTO

作者
Tom L Nguyen; Martine Silbermann; Matthew Wilcox

版权
2003、2008 英特尔公司

4.1. 关于本指南

本指南介绍了消息信号中断Message Signaled Interrupts (MSIs) 的基础知识、使用 MSI 相对于传统中断机制的优势、如何更改驱动程序以使用 MSI 或 MSI-X 以及在设备不支持 MSI 时尝试的一些基本诊断。

4.2. 什么是 MSI?

Message Signaled Interrupt 是从设备写入特殊地址,导致 CPU 接收中断。

MSI 功能首先在PCI 2.2中指定,后来在PCI 3.0中得到增强,允许单独屏蔽每个中断。 PCI 3.0还引入了 MSI-X 功能。与 MSI 相比,它支持每个设备更多的中断,并允许独立配置中断。

设备可能同时支持 MSI 和 MSI-X,但一次只能启用一个。

4.3. 为什么要使用 MSI?

使用 MSI 比传统的基于引脚的中断具有优势的原因有三个。

  • 基于引脚的 PCI 中断通常在多个设备之间共享。为了支持这一点,内核必须调用与中断相关的每个中断处理程序,这会导致整个系统的性能下降。 MSI 从不共享,因此不会出现此问题。
  • 当设备将数据写入内存,然后引发基于引脚的中断时,中断可能会在所有数据到达内存之前到达(这在 PCI-PCI 桥后面的设备更可能发生)。为了确保所有数据都已到达内存,中断处理程序必须读取引发中断的设备上的寄存器。 PCI 事务排序规则要求所有数据在值可以从寄存器返回之前到达内存。使用 MSI 可以避免这个问题,因为产生中断的写入不能传递数据写入,所以在引发中断时,驱动程序知道所有数据都已到达内存。
  • PCI 设备的每个功能只能支持一个基于引脚的中断。通常,驱动程序必须查询设备以找出发生了什么事件,从而减慢常见情况的中断处理速度。使用 MSI,设备可以支持更多中断,允许每个中断专门用于不同的目的。一种可能的设计为不常见的条件(例如错误)提供了自己的中断,这允许驱动程序更有效地处理正常的中断处理路径。其他可能的设计包括为网卡中的每个数据包队列或存储控制器中的每个端口提供一个中断。

4.4. 如何使用 MSI

PCI 设备被初始化为使用基于引脚的中断。设备驱动程序必须将设备设置为使用 MSI 或 MSI-X。并非所有机器都正确支持 MSI,对于这些机器,下面描述的 API 将简单地失败,并且设备将继续使用基于引脚的中断。

4.4.1. 包括对 MSI 的内核支持

要支持 MSI 或 MSI-X,必须在构建内核时启用 CONFIG_PCI_MSI 选项。此选项仅在某些架构上可用,并且可能取决于还设置的其他一些选项。例如,在 x86 上,您还必须启用 X86_UP_APIC 或 SMP 才能看到 CONFIG_PCI_MSI 选项。

4.4.2. 使用MSI

大部分困难工作已经在PCI层为驱动完成了。驱动程序只需请求 PCI 层为此设备设置 MSI 功能。

  • 要自动使用 MSI 或 MSI-X 中断向量,请使用以下函数:
int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,unsigned int max_vecs, unsigned int flags);

它为 PCI 设备分配最多max_vecs个中断向量。它返回申请的vectors数量负数。如果设备对vectors的最小数量有要求,驱动程序可以传递一个min_vecs参数配置这个限制,如果它不能满足vectors的最小数量,PCI core 将返回 -ENOSPC

flags 参数用于指定设备和驱动程序可以使用哪种类型的中断(PCI_IRQ_LEGACY、PCI_IRQ_MSI、PCI_IRQ_MSIX)。一个方便的简写 (PCI_IRQ_ALL_TYPES) 也可用于请求任何可能的中断类型。如果设置了PCI_IRQ_AFFINITY标志,pci_alloc_irq_vectors()将在可用 CPU间广播中断。

  • 为了获取传递给request_irq()free_irq()的 Linux IRQ 编号以及vectors,请使用以下函数:
int pci_irq_vector(struct pci_dev *dev, unsigned int nr);
  • 在使用以下函数删除设备之前,应释放所有分配的资源:
void pci_free_irq_vectors(struct pci_dev *dev);

如果设备同时支持 MSI-X 和 MSI 功能,则此 API 将优先使用 MSI-X 而不是 MSI 。 MSI-X 支持 1 到 2048 之间的任意数量的中断。相比之下,MSI 被限制为最多 32 个中断(并且必须是 2 的幂)。此外,必须连续分配 MSI 中断向量,因此系统可能无法为 MSI 分配足够多的向量,因为它优先为 MSI-X 分配。在某些平台上,MSI 中断必须针对同一组 CPU,而 MSI-X 中断可以针对不同的 CPU。

如果设备既不支持 MSI-X 也不支持 MSI,它将回退到单个传统 IRQ 向量。

  • MSI或MSI-X中断的典型用法是分配尽可能多的向量,可能达到设备支持的限制。如果nvec大于设备支持的数量,它会自动设置为支持的限制,因此无需事先查询支持的向量数量:
nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_ALL_TYPES)
if (nvec < 0)goto out_err;
  • 如果驱动程序无法或不愿意处理可变数量的 MSI 中断,它可以申请指定数量的中断。通过将该数量作为min_vecsmax_vecs参数传递给pci_alloc_irq_vectors()函数:
nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_ALL_TYPES)
if (nvec < 0)goto out_err;
  • 上述请求类型中最臭名昭著的示例是为设备启用单一 MSI 模式。可以通过传递两个 1 作为“min_vecs”和“max_vecs”来完成:
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (ret < 0)goto out_err;
  • 某些设备可能不支持使用传统线路中断,在这种情况下,驱动程序可以指定只接受 MSI 或 MSI-X:
nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (nvec < 0)goto out_err;

4.4.3. 传统API

以下用于启用和禁用 MSI 或 MSI-X 中断的旧 API 不应在新代码中使用:

pci_enable_msi()              /* deprecated */
pci_disable_msi()             /* deprecated */
pci_enable_msix_range()       /* deprecated */
pci_enable_msix_exact()       /* deprecated */
pci_disable_msix()            /* deprecated */

此外,还有一些 API 可提供支持的 MSI 或 MSI-X 向量的数量:pci_msi_vec_count()pci_msix_vec_count()。一般来说,应该避免这些,而是​​让 pci_alloc_irq_vectors() 限制向量的数量。如果您对向量计数有一个合法的特殊用例,我们可能不得不重新考虑该决定并添加一个 pci_nr_irq_vectors() 帮助程序来透明地处理 MSI 和 MSI-X。

4.4.4. 使用 MSI 时的注意事项

4.4.4.1 自旋锁

大多数设备驱动程序都有一个每个设备的自旋锁,它在中断处理程序中被采用。对于基于引脚的中断或单个 MSI,没有必要禁用中断(Linux 保证不会重新进入相​​同的中断)。如果设备使用多个中断,则驱动程序必须在保持锁定时禁用中断。如果设备发送不同的中断,驱动程序将死锁尝试递归获取自旋锁。这种死锁可以通过使用 spin_lock_irqsave() 或 spin_lock_irq() 来避免,它们禁用本地中断并获取锁(参见不可靠的锁定指南)。

4.4.5. 如何判断设备上是否启用了 MSI/MSI-X

使用“lspci -v”(以 root 身份)可能会显示一些具有“MSI”、“消息信号中断”或“MSI-X”功能的设备。这些功能中的每一个都有一个“Enable”标志,后跟“+”(启用)或“-”(禁用)。

4.5. MSI quirks

已知有几个 PCI 芯片组或设备不支持 MSI。 PCI 堆栈提供了三种禁用 MSI 的方法:

  • 全局的
  • 在特定网桥后面的所有设备上
  • 在单个设备上

4.5.1. 全局禁用 MSI

一些主机芯片组根本无法正确支持 MSI。如果幸运的话,制造商知道这一点,并在 ACPI FADT 表中指出了这一点。在这种情况下,Linux 会自动禁用 MSI。有些板子没有在表中包含这些信息,所以我们必须自己检测它们。这些的完整列表可以在 drivers/pci/quirks.c 中的 quirk_disable_all_msi() 函数附近找到。

如果您的主板存在 MSI 问题,您可以在内核命令行上传递 pci=nomsi 以禁用所有设备上的 MSI。将问题报告给 linux-pci@vger.kernel.org 将符合您的最佳利益,包括完整的“lspci -v”,以便我们可以将怪癖添加到内核中。

4.5.2. 在网桥下禁用 MSI

某些 PCI 桥无法在总线之间正确路由 MSI。在这种情况下,必须在网桥后面的所有设备上禁用 MSI。

某些网桥允许您通过更改其 PCI 配置空间中的某些位来启用 MSI(尤其是 Hypertransport 芯片组,例如 nVidia nForce 和 Serverworks HT2000)。与主机芯片组一样,Linux 大多了解它们,并在可能的情况下自动启用 MSI。如果您有一个 Linux 未知的网桥,您可以使用您知道的任何方法在配置空间中启用 MSI,然后通过执行以下操作在该网桥上启用 MSI:

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

其中 $bridge 是您启用的网桥的 PCI 地址(例如 0000:00:0e.0)。

要禁用 MSI,请回显 0 而不是 1。更改此值时应谨慎,因为它可能会中断此桥下所有设备的中断处理。

再次,请通知 linux-pci@vger.kernel.org 任何需要特殊处理的网桥。

4.5.3. 在单个设备上禁用 MSI

已知某些设备具有错误的 MSI 实现。通常这是在单独的设备驱动程序中处理的,但有时有必要用一个怪癖来处理它。某些驱动程序可以选择禁用 MSI。虽然这对驱动程序作者来说是一种方便的解决方法,但它不是一个好的做法,不应该被模仿。

4.5.4. 查找设备上禁用 MSI 的原因

从以上三个部分中,您可以看到可能无法为给定设备启用 MSI 的原因有很多。您的第一步应该是仔细检查您的 dmesg 以确定您的机器是否启用了 MSI。您还应该检查您的 .config 以确保您已启用 CONFIG_PCI_MSI。

然后,“lspci -t”给出设备上方的网桥列表。读取 /sys/bus/pci/devices/*/msi_bus 将告诉您 MSI 是启用 (1) 还是禁用 (0)。如果在属于 PCI 根和设备之间的桥的任何 msi_bus 文件中找到 0,则禁用 MSI。

检查设备驱动程序以查看它是否支持 MSI 也是值得的。例如,它可能包含对带有PCI_IRQ_MSI 或 PCI_IRQ_MSIX标志的pci_alloc_irq_vectors() 的调用

MSI驱动指南HOWTO相关推荐

  1. com口驱动_Ubuntu 安装Nvidia显卡驱动指南

    该文档适用于: Ubuntu 14/16/18 三个版本. Nvidia显卡驱动适用于: RTX2080TI/RTX2080/RTX2070/GTX1080TI/GTX1080/GTX1070以及更低 ...

  2. 三、Amlogic A311D 音频驱动指南

    1.概述 本章描述如何添加声卡,调试声卡以及通路等. 2.音频开发指南 一个声卡包含 cpu_dai, codec_dai, 以及 dai_link 组成,分别对应 cpu dai 的 dirver, ...

  3. 三、MT8168 MIPI DSI LCD驱动指南

    1.简介 MTK 8168平台 LCD驱动分为两部分:LK和KERNEL.常规的做法都是先点LK部分.当然也可以先点kernel部分,但是要注意,开机初始化不会跑kernel的LCD,需要修改代码. ...

  4. 二、MT8168 KeyPad驱动指南

    1.KeyPad工具和文件 1.1 DCT Tool vendor/mediatek/proprietary/scripts/dct/DrvGen.exe 1.2 DWS File vendor/me ...

  5. Linux网络设备驱动结构概述

    2019独角兽企业重金招聘Python工程师标准>>> 网络设备驱动相比字符型设备的驱动要复杂一些,除了总体上驱动的框架有一些相似外,有很多地方都是不同,但网络设备驱动有一个很大的特 ...

  6. 如何写一个树莓派的驱动来控制GPIO LED

    一直以来,物联网开发者面对新的硬件都是一件头痛的事情.有些时候明明有现成的驱动,我们却没法直接利用.公司的PM/领导一句话下来,整套系统就要从新来,说明书一看就是一天,重复的软硬联调,日复一日的造轮子 ...

  7. 富芮坤FR8008A 串口驱动之TDS检测芯片BA012

    1. TDS检测芯片简介 BA012 双通道水质总溶解性固体(TDS) 和水温检测的专用芯片. 内部集成高精密振荡电路.模数转换电路和浮点运算单元.采用专利电导率-TDS 转换算法和温度校正算法, 快 ...

  8. 刘东戈教授|追本溯源—2B3D是CSCO推荐具有重要意义的MSI检测位点

    导读:近几年,MSI在指南共识中的推荐地位不断上升,MSI检测结果在指导免疫治疗上有很强的特异性.因此,获取更准确的MSI状态与患者获益息息相关,有研究表明不同位点在中国人群中MSI检出率不同,指南推 ...

  9. 五、MT8168 音频驱动之SPEAKER

    1.简介 本章主要讲解MT8168平台的内部SPEAKER驱动配置.分为HP接法和LINE OUT接法. 2.驱动指南 2.1 外部AMP 接到HP 2.1.1 DTS设置 sound: sound ...

最新文章

  1. c 语言set用法,使用
  2. Python心得--如何提高代码质量
  3. centos 6推荐使用epel源
  4. JS window对象的top、parent、opener含义介绍 以及防止网页被嵌入框架的代码
  5. 我的小作品(烂笔头)
  6. 存储过程双层循环_mysql嵌套存储过程实现循环嵌套
  7. centos php 错误日志,centos系统下错误日志保存在哪里
  8. 子矩阵(NOIP2014 普及组第四题)
  9. Docker学习总结(14)——从代码到上线, 云端Docker化持续交付实践
  10. 物理安全是指保护计算机,计算机网络 物理安全
  11. 机器学习的gridSearchCV调参
  12. 51单片机三种烧录的方法介绍
  13. 大白菜U盘启动盘手动去除捆绑第三方赞助软件
  14. SpringBoot集成editormd实现发表和查阅功能
  15. delphi android 蓝牙,Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)
  16. 一个用在手机上的简单js拖拽效果
  17. 电脑wifi显示连接上了但是没有网络是怎么回事,手机wifi网络正常,已解决
  18. Java自定义模板设计
  19. 常用电平标准(TTL、CMOS、LVTTL、LVCMOS、ECL、PECL、LVPECL、RS232)
  20. 瞎想-电信IPTV如何做到真高清真4K直播

热门文章

  1. 《信号与系统》自然/受迫响应、零输入/零状态响应及系统初始状态
  2. nmn是真的还是假的,如何鉴别高质量的nmn,方法一览
  3. 超详细测试项目——Web电商项目测试点整理.....
  4. Android | WIFI Direct -1 Basic knowledge
  5. MacOS配置go环境
  6. 关于actor模型的优缺点分析(1)
  7. uni-app 第三方授权登录
  8. 思科认证和华为认证交换机环路的产生原因和解决方法-ielab实验室
  9. 106句激励自我的话
  10. 前端基础_像素的处理