首页 > 解决方案 > 从 MSI 能力结构中读取地址

问题描述

是否可以找到与特定中断关联的 MSI 能力结构的位置?具体来说,我需要知道写入时触发该中断的 PCI 地址。

可以使用 pci_alloc_irq_vectors(9) 函数轻松初始化 MSI 中断,但这只是提供了 irq 编号并且没有对能力结构的引用。

作为参考,本文档中描述了能力结构:https ://pcisig.com/sites/default/files/specification_documents/msi-x_ecn.pdf

标签: driverspci

解决方案


听起来您希望能够自己编写该值并生成中断。这并不是 MSI 的真正工作方式(尽管它仍然可能)。使用 MSI(或 MSI-X),您基本上是在对 PCI 设备进行编程,使用它应该生成数据写入的地址和要在生成中断时写入的数据值。

AFAIK 不能保证您可以通过写入地址自己触发相同的中断。尽管如此,通常在 MSI 中给出的地址是由中断控制器(通常实现为 PCI 设备本身)控制的地址空间内的一个位置,并且数据值告诉中断控制器要触发哪个中断。所以很可能,您可以将相同的值写入相同的物理内存地址,从而生成相同的中断。

在任何情况下,假设您知道哪个 PCI 设备正在生成中断,您可以找到 MSI 功能结构,因此您可以读回它的编程内容。这很简单。

PCI 功能(因设备而异)被组织成设备配置空间内的链表。列表的开头始终由设备配置空间内偏移 0x34 处的字节给出。该字节值为您提供了第一个能力数据结构空间内的偏移量。

每个能力由一个一字节的能力类型 ID 组成,后跟一个一字节的“下一个能力”指针,然后是特定于该能力的可变长度数据。因此,从偏移量 0x34 开始,您可以跳过这些功能。

要在任何 linux 机器上看到这一点,您可以运行lspci. 给它一个-v标志(可以重复以获得越来越多的细节)给你一个配置空间的注释视图。您还可以添加-xxxx以获取配置空间的完整十六进制转储,因此您可以自己遵循功能链。(顺便说一句,您需要运行它sudo以获取所有功能详细信息。)

内核中有一些接口可以为您执行此操作:您可以使用它pci_find_capability来查找所需功能的偏移量。pci_read_config_byte当然,您也可以通过从偏移量 0x34 开始并遵循列表来找到自己的功能。

找到 MSI 功能后,您就可以根据上面引用的文档解释其内容。您将使用pci_read_config_byte(/ word/ dword) 访问能力数据结构的各个部分。


推荐阅读