我这里有Linux 4.4(我曾经在一个旧的内核上工作,它以同样的方式失败),带有一个PCIe连接的FPGA设备和一个驱动程序,它们都是我自己设计的。这些在正常条件下工作得很好,但现在我尝试让它们在热插拔条件下工作。这不是真正的硬件热插拔,我一直在尝试的是设备 sysfs 目录中常见的
echo 1 >remove
以及之后的 echo 1 >/sys/bus/pci/rescan
。
设备重新出现后,我的驱动程序的初始化调用
pci_enable_device()
在记录时失败:
otscan 0000:02:00.0: can't enable device: BAR 0 [mem 0xf7e01000-0xf7e013ff] not claimed
otscan 0000:02:00.0: can't enable device: BAR 1 [mem 0xf7e00000-0xf7e00fff] not claimed
otscan 0000:02:00.0: can't enable device: BAR 2 [mem 0xf0200000-0xf020ffff 64bit pref] not claimed
(通常它会在第一个无人认领的资源之后停止,但我已将其修改为继续并确认实际上所有 BAR 都无人认领。)
“未声明”在这里意味着
struct resource
存在但没有父级,据我所知,这是由于 request_resource()
从未被调用过。我不认为这是一个驱动程序问题,因为初始化例程在由于无法启用设备而中止之前没有做很多事情。
这留下了 FPGA(具有硬 IP PCIe 内核的 Altera Cyclone V)以及我可能在那里做错的事情,例如以某种方式错误处理总线重置。通过 sysfs 重新插入该计算机中的其他 PCIe 设备即可工作。
我已经研究了一段时间,但仍然没有弄清楚为什么我的设备被 Linux 区别对待。我的设备的哪些可能属性可以让 Linux 决定不在我设备的 BAR 上调用
request_resource()
?
看来我找到原因了。我在 PCIe 核心配置中将类代码保留为
0
(这是无效的),当设备在启动时存在时,它可以正常工作。输入一个合理的值(在我的例子中,0x40000
表示多媒体视频设备,0xff0000
表示“未注册设备”也有效)也使其可以在热插拔上工作。
Linux 似乎仅部分处理具有
0
类代码的设备。
问题似乎是 FPGA 的 PCIe 核心的 PCIe 配置空间中的类定义不正确。确保 CLASS REGISTER 的高字节不是 0
我们在查看 dmesg 时遇到了类似的问题: “无法启用设备:BAR 0 ... ...未声明” 其次是 “pci_enable_device 失败”
确实是类代码设置不正确。我建议设置
0x058000
,它对应于内存控制器。
对于有类似问题的人来说,请参与进来。此错误也可能是由于设备树 (.dtsi) 不正确导致
我遇到了同样的问题。
can't enable device: BAR 0 [mem 0x839000000000-0x8390000fffff 64bit] not claimed
我的解决方案是将内存范围添加到linux设备树dtsi中。内存范围需要在设备树中可用。如果不是,您可能会收到同样的错误。您可以从
cat /proc/iomem
中阅读。
你可以使用这个操作,它对我有用。
vi /ets/default/grub
并更改此行以禁用 i801_smbus 功能。
GRUB_CMDLINE_LINUX_DEFAULT="i2c-i801.disable_features=0x10 安静启动"