Photo by Esther Ní Dhonnacha / Unsplash

编译Proxmox内核(暂时)解决IOMMU分组问题

Self Hosted 自托管 Aug 20, 2023 ~

因为仅仅使用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,可以详见这篇:

Proxmox 7.4 GPU Passthrough 显卡直通
近期AI题材火爆,看着家里一堆闲置吃灰的显卡,想想也应该让他们起来干活了,于是想起来组建一个新的PVE服务器,把显卡用上。又因为显卡虚拟化的支持目前应该还是不太稳定的状态(想来老黄是不可能给消费级显卡官方虚拟化的能力的),而且即使服务器端驱动搞定了,License的问题应该还是会成为绊脚石,所以还是选择了更为稳妥的直通方案。计划是直通显卡给一个Ubuntu server,然后在其上通过Docker部署一些简单的应用。

但是对于ASUS B460M,使用如下script查看分组:

#!/bin/bash
for d in $(find /sys/kernel/iommu_groups/ -type l | sort -n -k5 -t/); do
        n=${d#*/iommu_groups/*}; n=${n%%/*}
        printf 'IOMMU Group %s ' "$n"
        lspci -nns "${d##*/}"
done;

查看分组的shell 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虽然已经起作用了,但是其中的某些条件没有达成,所以依旧没有强制分组。

标签