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的中断向量。它返回分配的向量数量或一个负的错误。
如果设备对最小数量的向量有要求,驱动程序可以传递一个min_vecs参数,设置为这个限制,
如果PCI核不能满足最小数量的向量,将返回-ENOSPC。
flags参数用来指定设备和驱动程序可以使用哪种类型的中断(PCI_IRQ_INTX, PCI_IRQ_MSI,
PCI_IRQ_MSIX)。一个方便的短语(PCI_IRQ_ALL_TYPES)也可以用来要求任何可能的中断类型。
如果PCI_IRQ_AFFINITY标志被设置,pci_alloc_irq_vectors()将把中断分散到可用的CPU上。
要获得传递给require_irq()和free_irq()的Linux IRQ号码和向量,请使用以下函数:
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_vecs“和“max_vecs“参数传递给pci_alloc_irq_vectors()函数。:
ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_ALL_TYPES);
if (ret < 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;