编译Proxmox内核(暂时)解决IOMMU分组问题
因为仅仅使用PCIE_ACS_OVERRIDE依旧无法成功达成所需的IOMMU分组,故而选择直接编译PVE的内核,暂时解决IOMMU的分组问题。
背景 | Context
手上有一个闲置的ASUS B460M Prime主板,另外手上有两个NVME,还有空闲的GPU以及SATA Expansion card。于是想着组一个新的家用服务器,开始了新一轮的折腾。
硬件 | Hardware
ASUS B460M Prime是一个低端MATX主板,4内存插槽,1 PCIEx16,2 PCIEx1,两个M.2接口,单1GbE Realtek网卡,没有无线网卡(WIFI对于拿来做服务器反而不是任何缺点,有也基本上是浪费,没有的话,network接口还稍微简单清晰一点),6个板载SATA。
SATA Expansion card主要是当初图方便,没有从Ebay上面淘HBA卡,况且也算是契合PCIEx1的接口。PCIEx1的接口除了干这个,目前估计也没有什么更合适的用处了,前提是SATA Expansion card只接HDD。
麻烦就处在这两个SATA Expansion card所在的PCIEx1上面。
软件|Software
PVE 8.0,Linux内核版本6.2,这个内核实际上是有PVE自己的补丁的。本来是寄希望于新版本的Linux也许可以对PCIE_ACS_OVERRIDE有更好的支持,可惜没有如愿。
问题|Problem
在使用了 PCIE_ACS_OVERRIDE
argument的情况下,IOMMU分组里面,SATA Expansion card所在的两个PCIEx1接口,和板载的Ethernet接口在同一个分组。
现在大多数Promox启动应该都是用的systemd了,所以argument是加在 /etc/kernel/cmdline里面:
root=ZFS=rpool/ROOT/pve-1 boot=zfs quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction initcall_blacklist=sysfb_init
注意以上内容必须是一行。 pcie_acs_override=downstream,multifunction
这里应该会把能拆开的设备都拆开。而且理论上multifunction可能也是不需要的,这个flag其实会把GPU里面的声卡拆分出来。
对于之前的Gigabyte Z270P D3主板,单独加这个 downstream,multifunction
已经足够了。板上的所有PCIE插槽都会分配到各自的IOMMU Group里面。
- 通常来讲这样就足够了,而且对于CPU直连的设备,基本上可以确保能满足分组的要求了。对于GPU passthrough的情况,应该只需要这两个 flags。
对于GPU Passthrough,可以详见这篇:
但是对于ASUS B460M,使用如下script查看分组:
结构发现 Ethernet controller和两个PCIEx1插槽上面的SATA Expansion card依旧在同一个分组(IOMMU Group 9)里面。
当设备处于同一个分组的时候,如果将分组中的一个设备pass through到一个VM里面,实际会导致整个分组的设备都被pass through。结果就是,分配SATA Expansion card到TrueNAS,会导致PVE Host断网。
实际上 PCIE_ACS_OVERRIDE
也是发挥作用了。并不是所有芯片组上面的PCI设备都没有分组成功,比如第二个M.2设备实际上了分组成功了的。只是这个Ethernet controller和SATA Expansion cards,还有一个PCI Bridge设备,无法分组。
之所以说PCIE_ACS_OVERRIDE设定成功,可以验证如下
root@pve:~# dmesg | grep -e IOMMU
[ 0.000000] Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA
[ 0.179824] DMAR: IOMMU enabled
这个Warning基本就是ACS overrides已经在使用中的证据。
失败的尝试
尝试了如下方法,试图省略编译kernel需要,结果还是免不了需要修改kernel。
- 更新BIOS版本
原先的BIOS是1603,后来更新到最新的1620。更新之后确实需要重新在BIOS里面打开左右关于虚拟化的设置(比如vt-d之类的),IOMMU分组也要打开。但是最后系统内还是没有把三个设备分开。
- 使用
pcie_acs_override=id:nnnn:nnnn
,给定两个SATA Expansion Cards的vendor ID 和 product ID。
pcie_acs_override=downstream,multifunction,id:1b4b:9128,id:1b21:1064
结果是一样的。
解决|Solution
这个时候就只能重新编译Kernel了。因为ACS Overrides Patch虽然已经起作用了,但是其中的某些条件没有达成,所以依旧没有强制分组。