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

时间:2016-04-22 10:05:58

标签: linux linux-device-driver interrupt dma pci

目前正致力于PCI设备驱动程序。设备编程如下:
当DMA传输完成时,设备向MSI数据“001”二进制发送MSI中断。

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

在维基百科中,它说:

  

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

Q1:所以在我的情况下,small amount of interrupt-describing data是从pci设备发送到PC的"001"

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

err = pci_enable_msi(my_pci_dev);  
err = request_irq(my_pci_dev->irq, irq_handler, 0, "PCI_FPGA_CARD", NULL);  

并且irq_handler的定义如下:

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

Q2:使用上面的3个核心函数,我们如何获得消息"001"
问题3: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);

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);

3个问题~~ thx求助。

1 个答案:

答案 0 :(得分:0)

最新答案。希望它仍然有帮助。

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, ...);

对于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, ...);