PCIE中断简介
PCIe有三种中断,分别为INTx中断,MSI中断,MSI-X中断,其中INTx是可选的(Legacy),MSI/MSI-X是必须实现的。
INTx:是开始PCI时期的产物,为了兼容PCI的INTA,INTB,INTC,INTD四个中断线而采用的一种中断机制。由于仅支持四个中断,且采用一个状态来控制,这种机制导致多中断场景软件处理复杂特别是有中断嵌套的场景(由于支持中断比较少,会有公用一个状态信号),比较多的PCIe设备都没有支持该特性。
MSI:message signal interrupt, 是PCI设备通过写一个特定消息到特定地址,从而触发一个CPU中断,最大支持32个中断。
MSI对比INTx 主要有以下几个优点:
1、中断独立,INTx4个中断公用一个状态信号,而MSI所有中断都是相互独立,软件处理方方便
2、MSI支持的中断数量更多,且不依赖IO,节省IO资源。
MSI-x:由于MSI中断存在仅支持32个中断,中断号必须要连续等限制,PCIe 3.0版本在MSI的基础上发展出了MSI-x,最大支持2048个中断,中断号可以不连续。
这些中断方式在驱动开发过程使用:
驱动开发中,大部分困难工作已经在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间广播中断。
上面pci_alloc_irq_vectors分配好的IRQ存放在dev->msi_list列表的msi_entry中,可以通过for_each_msi_entry遍历每个IRQ:
for_each_msi_entry(desc, dev){request_irq(desc->irq, handler, flags, name, dev)
}
MSI-x中断如何产生
下图是ARMv8架构下的主要经过的模块,主要流程如下
(1)HOST枚举到EP PF设备,配置MSI-x table
(2)EP设备通过读取vector table,获取到MSI-x中断对应的message address,构造一个TLP包,往message address地址里面写中断信息。
(3)PCIE RC收到包判断是个TLP写后,将写操作转到总线,并返回ACK
(4)GIC中的ITS检测到对应DDR有变化,则获取设备和中断信息后分发到经GIC分发到各个CPU核上。