你费了好大劲把一张显卡直通给虚拟机,宿主机层面一切正常,虚拟机也认到了这张卡。可客户机里的驱动就是不认它,报"这不是一个 PCIe 设备"。你翻驱动日志、换驱动版本,都无济于事——问题其实在直通配置本身。
现象
客户机里,显卡驱动探测失败,报类似:
This device is not a PCIe device
或者驱动加载时报"探测失败 / 设备类型不符"。你在宿主机上确认过直通配置、也确认过客户机里 lspci 能看到这张卡,可就是跑不起来。
根因
原因在于直通设备的"总线类型"没有被显式声明。
显卡在物理上、在现代机器上,是挂在 PCIe 总线上的(PCI Express)。PCIe 相对老式的传统 PCI 总线,在枚举方式、配置空间、能力结构上都有区别。驱动在探测一个设备时,会根据它被枚举出来的总线类型来决定走哪条代码路径:
- 如果客户机把它枚举成 PCIe 设备,驱动就按 PCIe 的方式初始化(找到对应的 capability、按 PCIe 的时序和寄存器访问);
- 如果客户机把它枚举成传统 PCI 设备,驱动就少了 PCIe 那套前提,于是判断"这不是 PCIe 设备",探测中止。
默认情况下,某些直通配置不会带 PCIe 标志,客户机就把这张卡枚举成了传统 PCI 设备——于是驱动不认。
解决
在直通配置里显式加上 PCIe 标志。
在 Proxmox VE 里,这体现在虚拟机的配置项上。直通 PCI 设备时,对应的配置大致形如:
hostpci0: 0000:01:00,pcie=1
关键就是那个 pcie=1——它告诉平台"把这个设备以 PCIe 的方式暴露给客户机",客户机就会按 PCIe 枚举它,驱动自然认。
如果是用命令行的方式:
qm set <VMID> -hostpci0 0000:01:00.0,pcie=1
设置完关闭并重新启动虚拟机(PCI 设备的枚举发生在启动时,热改往往不生效):
qm stop <VMID>
qm start <VMID>
进客户机验证:
lspci -vv -s <设备地址> | grep -i "express\|capabilities"
如果能看到 PCI Express 相关的 capability(而不是只有传统 PCI 的结构),说明这次是以 PCIe 暴露的,驱动应该就能正常探测了。
延伸与预防
这条坑的教训可以浓缩成一句:直通设备的"总线类型"要显式声明,别指望平台替你猜对。
直通(passthrough)这个动作,本质是"把物理设备以某种方式重新呈现给客户机"。这个"重新呈现"涉及很多细节:总线类型(PCI 还是 PCIe)、是否暴露 ROM-BAR、MSI/MSI-X 中断怎么走、分组(IOMMU group)是否干净。任何一项没配对,都可能表现为"驱动不认""设备不可用"这类现象。
所以排查直通问题时,别一上来就怀疑驱动或硬件,先确认"设备是以什么形式呈现给客户机的":
# 宿主机:确认设备挂在 PCIe 上、IOMMU 分组情况
lspci -vv -s <设备地址> | grep -i "express"
find /sys/kernel/iommu_groups/ -maxdepth 2 -type l | head
# 客户机:确认它看到的是不是 PCIe
lspci -vv
预防上,建议把直通配置当成一套"清单"来对待:总线类型、中断方式、是否需要分离 ROM、IOMMU 分组是否独立,逐项确认。很多"直通玄学"其实就是某一项清单没打勾。把这份清单固定下来,下次再配直通就能一次到位。