背景
最近写一个PCIe驱动,正常probe、remove,也正常通过iomem操作bar空间,也能通过DPU正常来DMA HOST的内存,但是却遇到了网卡上DMA无法DMA HOST的内存。何因?
根因
最后查出来是因为在PCIe驱动中初始化没有设置pcie设备pdev的pci_set_master
pci_set_master干什么?
先看说明
pci_set_master(pdev); 函数在Linux内核中用于将PCI设备设置为主设备(Bus Master)。主要作用:
- **启用DMA:**pci_set_master() 通过在PCI_COMMAND寄存器中设置总线主控位(Bus Master bit)来启用DMA。可以让设备直接与内存进行数据传输,而不需要CPU的介入
- 总线事务控制:当设备被设置为主设备时,它可以控制总线上的其他设备,并发起总线事务。=
如果不调用 pci_set_master(pdev);,PCI设备可能无法作为总线主控进行DMA操作,可能无法控制总线上的其他事务,这可能会影响到设备的功能性和效率。因此,在PCI设备驱动程序中,通常需要调用此函数以确保设备能够充分利用DMA和总线主控的能力。
再看代码
可以看到这里做了两个动作,一个是对PCIe配置空间配置了COMMAND使能master,另一个是bios进行了设置。
/**
* pci_set_master - enables bus-mastering for device dev
* @dev: the PCI device to enable
*
* Enables bus-mastering on the device and calls pcibios_set_master()
* to do the needed arch specific settings.
*/
void pci_set_master(struct pci_dev *dev)
{
__pci_set_master(dev, true);
pcibios_set_master(dev);
}
static void __pci_set_master(struct pci_dev *dev, bool enable)
{
u16 old_cmd, cmd;
pci_read_config_word(