【问题标题】:How to properly disable a PCIe device?如何正确禁用 PCIe 设备?
【发布时间】:2019-10-08 07:41:47
【问题描述】:

我正在 Linux 中为在 Xilinx UltrascaleMPSoC FPGA 部件上实现的 PCIe 端点编写设备驱动程序。我已经正确实现了删除功能。我使用适配器将我的设备连接到我的电脑,打开设备,启用其端点,然后打开电脑,一切正常。但是,当我尝试使用 rmmod 命令卸载驱动程序模块时,进程挂起。

我浏览了 Linux 文档和 pci_disable_device() documentation,它说

请注意,直到 pci_enable_device() 的所有调用者都调用了 pci_disable_device(),我们才真正禁用设备。

这是否意味着,我的驱动程序必须等到 linux 中的所有其他 pcie 驱动程序调用 pci_disable_device() 之后才会禁用设备?我真的很怀疑这一点:(

我尝试使用 modprobe -r 并使用“lsmod”列出了模块使用计数。 lsmod 将使用计数显示为“0”。但是我仍然无法卸载模块:(我还添加了打印语句。

void remove(struct pci_dev pdev)
{
    pci_unmap_single(pdev, privdata->dma_mem,
    PAGE_SIZE * (1 << memorder),
    PCI_DMA_FROMDEVICE);
    printk(KERN_INFO"unmap_single() complete\n");
    free_pages ((unsigned long) privdata->mem, memorder);
    printk(KERN_INFO"free_pages() complete\n");
    free_irq(pdev->irq, privdata);
    printk(KERN_INFO"free_irq() complete\n");
    pci_disable_msi(pdev);
    printk(KERN_INFO"MSI disable complete\n");
    pci_clear_master(pdev); /* Nobody seems to do this */
    printk(KERN_INFO"clear_master() complete\n");
    pci_iounmap(pdev, privdata->registers);
    printk(KERN_INFO"iounmap() complete\n");
    pci_disable_device(pdev);
    printk(KERN_INFO"disable_device() complete\n");
    pci_release_regions(pdev);
    printk(KERN_INFO"release_regions() complete\n");
}

预期:设备必须被禁用。我无法得出结论。当我在另一个终端中执行 dmesg 时,我得到打印 till "disable_device() complete" 并且终端挂起。此外,我检查了文件:/proc/iomem 和/proc/interrupts-> 当我卸载模块时,我的设备的相应条目在我的两个文件中都被删除了!我只完成了 pci_disable_device() 的执行,进程挂起。

注意:只有 rmmod 进程挂起,我不能使用当前终端,但我可以打开另一个终端,做所有事情。

最后,当重新启动时,系统再次挂起,每次,我都通过按住电源按钮 10-15 秒来强制重启。 检查这个reboot_hang

为什么 pci_release_regions() 挂起我的系统,即使 lsmod 显示我的模块使用计数为“0”。

在此先感谢 :) 另外,我应该在上面的代码中交换pci_disable_device()pci_release_regions() 方法吗? -> 我也试过这个,但后来我得到打印直到 release_regions() 完成,但 disable_device complete 没有打印。并且进程挂起:(

请帮忙

【问题讨论】:

  • 您是否调试过它挂在哪里/为什么挂起?你检查过其他司机是怎么做的吗?我建议您在 LKML 中提出此类问题,这是适合此问题的论坛。

标签: c linux-kernel linux-device-driver pci-e


【解决方案1】:

如果没有更多关于您在驱动程序上真正使用的信息,很难回答。

但是,我会尽力给你一个答案。

这是否意味着,我的驱动程序必须等到 linux 中的所有其他 pcie 驱动程序调用 pci_disable_device() 之后才会禁用设备?

不,这会变得不切实际并且不是很模块化。

您似乎正在释放 DMA 页面。你是如何分配它们的?您是否使用一致分配?看看here,看看如何正确使用DMA。

对于其余部分,您可以尝试在 clear_master 之前移动发布区域吗?示例:

pci_disable_msi(pdev);
ioummap(ADDRESS);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);

有关如何编写 PCI 驱动程序的更多信息,请查看文档here。它提供了很多信息。

【讨论】:

  • 感谢您的快速回答。我正在使用流式 DMA 映射。我在 probe() 方法中做了一个 pci_map_single()。我尝试了将 pci_clear_master() 放在发布区域之后的上述方法。现在,我得到打印,直到 clear_master() 完成。现在,只有 pci_disable_device() 不会被打印。另外,我发现这个链接 LINUX KERNEL driver 在处理映射寄存器后挂起/冻结 - >它说拥有该寄存器的硬件模块要么断电,要么没有计时。真的吗?有什么想法吗?
猜你喜欢
  • 2017-03-13
  • 2013-10-31
  • 2020-01-24
  • 2020-08-21
  • 1970-01-01
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多