MSI 中断在 Linux 驱动程序中如何工作?

Con*_* Li 6 linux interrupt linux-device-driver dma pci

目前正在研究 PCI 设备驱动程序。设备的编程如下:
当 DMA 传输完成时,设备向 PC 发送 MSI 中断,其中包含 MSI 数据“001”二进制。

现在我正在为这个 pci 设备编写一个驱动程序,对于 MSI 部分,我有一些问题。

在维基百科中,它说:

MSI允许设备将少量中断描述数据写入特殊的内存映射I/O地址,然后芯片组将相应的中断传递给处理器。

Q1:那么就我而言,是small amount of interrupt-describing data"001"pci 设备发送到 PC 的吗?

在我的驱动程序代码中,MSI irq 的注册方式如下:

err = pci_enable_msi(my_pci_dev);  
err = request_irq(my_pci_dev->irq, irq_handler, 0, "PCI_FPGA_CARD", NULL);  
Run Code Online (Sandbox Code Playgroud)

irq_handler定义如下:

static irqreturn_t irq_handler(int irq, void *dev_id)  
{  
  printk(KERN_INFO "(irq_handler):  Called\n");  
  return IRQ_HANDLED;
}  
Run Code Online (Sandbox Code Playgroud)

Q2:有了上面的3个内核函数,我们如何获取消息呢"001"
Q3: PCI 设备最多支持 8 个 MSI 矢量,因此要使用所有这 8 个矢量,我应该使用下面的代码,否则都不正确:

err = pci_enable_msi_block(my_pci_dev,8);
err = request_irq(my_pci_dev->irq, irq_handler, 0, "PCI_FPGA_CARD", NULL);
Run Code Online (Sandbox Code Playgroud)

或者

err = pci_enable_msi(my_pci_dev);
err = request_irq(my_pci_dev->irq, irq_handler_0, 0, "PCI_FPGA_CARD", NULL);
err = request_irq(my_pci_dev->irq, irq_handler_1, 0, "PCI_FPGA_CARD", NULL);
err = request_irq(my_pci_dev->irq, irq_handler_2, 0, "PCI_FPGA_CARD", NULL);
err = request_irq(my_pci_dev->irq, irq_handler_3, 0, "PCI_FPGA_CARD", NULL);
err = request_irq(my_pci_dev->irq, irq_handler_4, 0, "PCI_FPGA_CARD", NULL);
err = request_irq(my_pci_dev->irq, irq_handler_5, 0, "PCI_FPGA_CARD", NULL);
err = request_irq(my_pci_dev->irq, irq_handler_6, 0, "PCI_FPGA_CARD", NULL);
err = request_irq(my_pci_dev->irq, irq_handler_7, 0, "PCI_FPGA_CARD", NULL);
Run Code Online (Sandbox Code Playgroud)

3个问题~~谢谢你的帮助。

lqu*_*lqu 8

迟到的答复。希望它仍然有帮助。

A1:是的。MSI 是从设备到 CPU 的已发布内存写入。TLP 的目标是 CPU 分配的 MSI 地址,有效负载是 MSI DATA,在本例中为“001”。地址和数据(偏移量)组合起来定义了一个唯一的中断向量。因此,使用不同的“数据”,您可以拥有多个中断和处理程序。

A2:通常你不需要它。以下来自维基百科。

对 MSI 的一个常见误解是它允许设备将数据发送到处理器作为中断的一部分。芯片组使用作为内存写入事务的一部分发送的数据来确定在哪个处理器上触发哪个中断;该数据不可用于设备向中断处理程序传达附加信息。

如果您仍然好奇,请检查 MSI 功能的 MSI DATA 寄存器。它可能包含“001”,但我尚未验证。无论如何,这个“001”不应该与 ISR 相关。

A3:您应该注册多个处理程序。通过 MSI,您可以拥有连续的向量,并且 MSI-X 为每个中断向量提供一个包含单独地址和数据的表。

对于 MSI:

request_irq(my_pci_dev->irq, irq_handler_0, ...);
request_irq(my_pci_dev->irq + 1, irq_handler_1, ...);
request_irq(my_pci_dev->irq + 2, irq_handler_2, ...);
Run Code Online (Sandbox Code Playgroud)

对于 MSI-X:

request_irq(my_pci_dev->pMsixEntries[0].vector, irq_handler_0, ...);
request_irq(my_pci_dev->pMsixEntries[1].vector, irq_handler_1, ...);
request_irq(my_pci_dev->pMsixEntries[2].vector, irq_handler_2, ...);
Run Code Online (Sandbox Code Playgroud)