c - 如何正确禁用 PCIe 设备?
问题描述
我正在 linux 中为 Xilinx UltrascaleMPSoC FPGA 部件上实现的 PCIe 端点编写设备驱动程序。我已经正确实现了删除功能。我使用适配器将我的设备连接到我的电脑,打开设备,启用其端点,然后打开电脑,一切正常。但是,当我尝试使用 rmmod 命令卸载驱动程序模块时,进程挂起。
我浏览了 Linux 文档和 pci_disable_device()文档,它说
请注意,直到 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 时,我得到打印,直到“ disable_device() 完成”并且终端挂起。此外,我检查了文件:/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 没有打印出来。并且进程挂起:(
请帮忙
解决方案
如果没有更多关于您在驱动程序上真正使用的信息,很难回答。
但是,我会尽力给你一个答案。
这是否意味着,我的驱动程序必须等到 linux 中的所有其他 pcie 驱动程序调用 pci_disable_device() ,然后设备才会被禁用?
不,这会变得不切实际并且不是很模块化。
看来您正在释放 DMA 页面。你是如何分配它们的?您是否使用一致分配?看看这里,看看如何正确使用 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 驱动程序的更多信息,请查看此处的文档。它提供了很多信息。
推荐阅读
- ruby-on-rails - 输入批量数据时,使用 HABTM 关联创建新记录很慢
- javascript - 尝试将转译的 js 文件导入我的应用程序时,为什么会收到 $ isnotafunction 和 window.renderDashboardisnotafunction 的错误?
- sql - 在 Oracle 中按问题分组?
- api - 类型'String'不是get方法颤动中类型'Null'的子类型
- c# - JWT不记名令牌授权不起作用asp net core web api
- javascript - 为什么我无法获取 Firebase 存储文件的下载 URL?
- java - 如何完全删除/禁用 Web 浏览器上的 Spring Boot 徽标?
- excel - 选择文件夹中的前一个文件并将其复制到新文件中
- javascript - Web 服务 JSON 表示/编辑
- jenkins - Jenkins 代理 pod 无法在 kubernetes 上运行