Read in English →

双显卡 Linux 桌面反复卡死:从 NVIDIA Xid 查到 BIOS 里的开关

一台 CachyOS + Niri 的双显卡主机,两天内卡死三次。系统其实还活着,出问题的是负责显示的那块 RTX 4060。这篇记录排查过程、两种不同的死法,以及走过的弯路。

LinuxNVIDIAPCIeBIOS排查记录

两天里,我的桌面卡死了三次:画面冻住,鼠标键盘全都没反应,Ctrl+Alt+F3 也切不到文字终端。每次都只能重启。

最后查下来,系统本身一直是好的,出问题的是负责显示的那块 RTX 4060。而且三次卡死是两种不同的故障,要在 BIOS 里分别处理。

机器配置

项目 配置
系统 CachyOS(Arch 系),内核 7.2.6
桌面 Niri(Wayland 合成器)+ Noctalia
主板 ASUS ROG STRIX Z690-A GAMING WIFI D4,BIOS 2103
显卡 1 RTX 2080 Ti,插在 CPU 直连的 x16 主插槽,只跑计算(ComfyUI)
显卡 2 RTX 4060,插在芯片组下的 x4 插槽,两台显示器都接在它上面
驱动 NVIDIA 开源内核模块 615.71.09

「显卡 2」那一行是关键,后面会讲到。

卡住不等于死机

第一反应容易是「死机了」,但先要分清两件事:

  • 显示卡住:画面不动,但系统进程都还在跑
  • 系统死机:内核本身卡住,什么都做不了

区分办法很简单:从另一台设备连过来,SSH 或者任何远程会话都行。第三次卡死时,我从另一台设备通过远程会话连到这台机器,命令照常能执行,内存还剩 47 GB,负载不到 1。也就是说系统没死,只是看不到画面。

这也解释了为什么 Ctrl+Alt+F3 没用。切换到文字终端,同样要靠那块显卡输出画面。显卡不响应,切换也就无从谈起。niri 的日志能看到它确实收到了切换请求(pausing session),但紧接着内核就开始刷:

[nvidia-drm] [GPU ID 0x00000800] Flip event timeout on head 0
[nvidia-drm] [GPU ID 0x00000800] Flip event timeout on head 1

所以这种情况下「按 Ctrl+Alt+F3 看能不能进终端」不是一个有效的判断方法,虽然这恰恰是我最先得到的建议。

翻日志:三次卡死,两种死法

journalctl -k -b -N 可以翻看前几次开机的内核日志。三次卡死如下:

时间 首个报错 类型
9/24 04:10 Xid 119:GSP 45 秒无响应,驱动随后重置显卡 PCIe 通信
9/24 21:06 mapping multiple BARs → Xid 31 → Xid 56 BAR1 窗口
9/25 00:00 PCIe CmpltTO → AER: device recovery failed → Xid 56 PCIe 通信

出错的都是 PCI:0000:08:00,也就是 4060。2080 Ti 一次都没有报过错。

死法一:BAR1 窗口太小

9/24 21:06 那次,最先出现的是这几行:

NVRM: dmaAllocMapping_GM107: can't alloc VA space for mapping.
resource sanity check: requesting [mem 0x402fd60000-0x403008ffff],
  which spans more than 0000:08:00.0 [mem 0x4020000000-0x402fffffff 64bit pref]
caller __nv_drm_gem_nvkms_map+0xb0/0x120 [nvidia_drm] mapping multiple BARs

BAR1 是 CPU 访问显存用的一段地址窗口。这里 4060 的 BAR1 是 0x4020000000-0x402fffffff,只有 256 MB。驱动要映射的那段地址越过了窗口末尾,映射失败。接着 Chrome 触发 Xid 31(显卡内存页错误),显示引擎报 Xid 56,驱动的看门狗报 GPU is probably locked,桌面就冻住了。

注意,当时显存只用了 1 GB 左右,不是显存不够,是窗口不够。

/sys/bus/pci/devices/0000:08:00.0/resource1_resize 显示这块 4060 的硬件支持最大 8 GB 的 BAR,只是 BIOS 里没开 Resizable BAR,所以只拿到了默认的 256 MB。

死法二:PCIe 请求超时

9/25 00:00 那次完全是另一回事,日志里没有任何 BAR 相关的报错:

pcieport 0000:00:1c.4: AER: Multiple Uncorrectable (Non-Fatal) error message received from 0000:08:00.0
nvidia 0000:08:00.0: PCIe Bus Error: severity=Uncorrectable (Non-Fatal), type=Transaction Layer
nvidia 0000:08:00.0:    [14] CmpltTO                (First)
nvidia 0000:08:00.0: AER: can't recover (no error_detected callback)
pcieport 0000:00:1c.4: AER: device recovery failed
NVRM: Xid (PCI:0000:08:00): 56, CMDre 00000005 00000240 ffffffff 00000007 00000000

CmpltTO 是 Completion Timeout:CPU 发给显卡的请求,一直等不到回应。内核的 PCIe 错误恢复机制(AER)试着救这块卡,但 nvidia 驱动没有实现对应的回调,恢复失败。从这一刻起显卡就相当于从总线上掉线了,只有重启能恢复。

9/24 04:10 那次是 Xid 119:驱动等显卡里的 GSP 处理器回应,45 秒都没等到。症状同样是「请求发出去了,回应一直不来」,我把它归到同一类。

为什么偏偏是 4060

看一下 PCIe 拓扑(lspci -tv):

-[0000:00]-+-01.0-[01]----00.0  RTX 2080 Ti      ← CPU 直连 x16
           ...
           +-1c.1-[06]----00.0  ASMedia SATA 控制器
           +-1c.3-[07]----00.0  Intel I225-V 网卡
           +-1c.4-[08]--+-00.0  RTX 4060         ← 芯片组下的 x4

两个插槽的路径完全不同:

  • 2080 Ti:CPU → 插槽,线路短,中间没有别的芯片
  • 4060:CPU → DMI 总线 → Z690 芯片组 → 插槽,路程更长,和 SATA 控制器、网卡在同一个芯片组下面

我一开始以为是 x4 带宽不够,这是另一个误判。两台 1080p 显示器对带宽的需求很小,x4 绰绰有余。而且带宽不够的症状是卡顿、掉帧,不会让显卡直接从总线上消失。

真正的问题是链路稳不稳。PCIe 有一套省电机制叫 ASPM:空闲时让链路进入低功耗状态,有数据要传时再唤醒。每次唤醒,链路两端都要重新协商。信号余量小的链路在这一步偶尔会失败,失败的表现正是请求超时。

这一点我没法直接证明:日志只记录了超时,没有记录超时前链路处于什么状态。但 ASPM 是这条链路上最常见的不稳定来源,也是最容易排除的一个。

修复:BIOS 里的两个开关

主板是 ASUS 的,按 Del 进 BIOS,F7 切到高级模式:

设置 对应的死法 位置(ASUS Z690,不同版本名称可能略有差异)
Above 4G Decoding + Resizable BAR 设为 Enabled 死法一 Advanced → PCI Subsystem Settings
ASPM 相关选项设为 Disabled 死法二 Advanced → Platform Misc Configuration,以及 PCH / DMI 的 ASPM 选项

验证

改完重启后,先看 BAR1:

nvidia-smi -q -i 1 | grep -A1 "BAR1 Memory Usage"
BAR1 Memory Usage
    Total                             : 8192 MiB

内核日志里的地址范围也变了:

# 改之前
pci 0000:08:00.0: BAR 1 [mem 0x4020000000-0x402fffffff 64bit pref]   # 256 MB
# 改之后
pci 0000:08:00.0: BAR 1 [mem 0x4000000000-0x41ffffffff 64bit pref]   # 8 GB

ASPM 要看 PCIe 链路控制寄存器,需要 root:

sudo lspci -vvs 00:1c.4 | grep LnkCtl:
sudo lspci -vvs 08:00.0 | grep LnkCtl:

链路两端(芯片组的根端口和显卡)都要看。我这台改完之后两端都是:

LnkCtl:	ASPM Disabled; RCB 64 bytes, LnkDisable- CommClk+

这里有个坑:内核开机日志里有一行 ACPI FADT declares the system doesn't support PCIe ASPM,看起来像是「ASPM 已关闭」的证据。其实我这台机器在改 BIOS 之前的每次开机都有这一行。它只表示内核不去管 ASPM、完全交给 BIOS,并不说明 BIOS 把它关了。我一开始就拿它当了证据,后来翻旧日志才发现不对。

另外,nvidia-smi 显示 4060 空闲时链路在 Gen1,这是驱动自己的降速省电,和 ASPM 是两回事。一有负载就会升回去。

走过的弯路

整理一下这次排查中判断错的地方:

  1. 以为是 x4 带宽不够。实际是链路可靠性问题,带宽只会影响快慢,不会让设备掉线。
  2. 建议用 Ctrl+Alt+F3 判断死没死机。显卡本身掉线时,切换终端同样要靠它,这个方法在这种场景下无效。真正有效的是从另一台设备远程连进来。
  3. 拿 FADT 那行日志证明 ASPM 已关。改 BIOS 之前的日志里也有这一行,不能当证据。
  4. 把三次卡死当成一个问题。其实是两种故障:BAR1 窗口太小,和 PCIe 请求超时。只修其中一个,另一个还会继续出现。

还没结论的地方

  • 改完 BIOS 后目前已经连续运行 8 个多小时没有再卡,但还要多观察几天。
  • 00:00 那次卡死的前几个小时,芯片组下另一个设备(04:00.0,一块 Realtek 主控的 NVMe,系统里没有识别出它的磁盘)也报过一次 non-fatal AER 错误。只出现过一次,没有造成影响,但它也在芯片组那一侧。如果以后频繁出现,可能说明芯片组这一路的信号质量整体偏弱。
  • 如果还会卡,下一步依次是:升级 BIOS(2103 是 2022 年的版本)→ 对调两块卡的插槽,让负责显示的 4060 用 CPU 直连插槽 → 或者把显示器改接到 2080 Ti。

速查

下次桌面再卡,按这个顺序查:

# 1. 从另一台设备连上来,确认系统还活着
uptime; free -h

# 2. 本次开机的显卡和 PCIe 报错
journalctl -k -b | grep -E "Xid|AER|CmpltTO|multiple BARs|Flip event timeout"

# 3. 上一次开机(已经重启过的话)
journalctl -k -b -1 | grep -E "Xid|AER|CmpltTO|multiple BARs"

# 4. 两块卡分别接在哪、链路状态
lspci -tv
nvidia-smi --query-gpu=index,pci.bus_id,name,display_active,pcie.link.gen.current,pcie.link.width.current --format=csv

看到 mapping multiple BARs,是 BAR1 窗口的问题;看到 CmpltTO 或 device recovery failed,是 PCIe 链路的问题。