ROCK 4D 级联 PCIe Switch 下 MSI 耗尽导致网络卡死的排查
说明
在 ROCK 4D 上接入 Radxa Dual 2.5G Router HAT、ASM1182E 扩展板、两块 RTL8125、MT7922 和 NVMe 后,系统冷启动可以正常工作。但只要启用 MT7922 的 5 GHz AP,运行一段时间后 LAN 会出现严重丢包,SSH 逐渐卡顿,最后近似失联。重启后网络暂时恢复,重新开启无线发射后又会复现。
最初怀疑过 mt76、hostapd 和 MT7922 固件,但实际故障点不在无线驱动本身。完整 PCIe 拓扑耗尽了 RK3576 主机仅有的 32 个 MSI vector,导致两块 RTL8125 和 MT7922 都退回 legacy INTx。AP 开始发射后,中断负载增加,暴露了级联 Switch 下 INTx 路径的问题,最终使 r8169 的发送完成处理中断无法及时到达。
本文使用的修复保存在我的 GitHub 仓库 ovo-ukiyo/openwrt 的 rock-4d-aic8800-router-hat 分支中。MSI 修改、mt76 回移植和阶段性验证记录均拆成独立 commit,本文重点说明 MSI 资源耗尽这一条主线。
故障现象
设备刚启动时,网页、SSH 和有线转发都正常。启用 MT7922 AP 后,网络延迟开始升高,随后出现大量丢包。故障后可以看到类似日志:
1 | r8169 0000:0b:00.0 eth1: NETDEV WATCHDOG: transmit queue 0 timed out |
这条日志说明 r8169 的发送队列长时间没有完成,并不直接说明 RTL8125 芯片损坏。检查 MT7922 日志时,也没有在故障点出现对应的 MCU timeout。
两个现象对定位很重要:
- MT7922 不启用 AP 时,系统可以长时间保持可用;
- AP 开始工作后,最终报错的是有线网卡发送队列。
这更像是多个 PCIe 设备之间共享的底层资源出了问题,而不是单个无线配置错误。
先排除 hostapd 和常见 mt76 问题
排查期间先将精简的 wpad 组件换成完整 hostapd:
1 | apk add hostapd-any |
系统实际安装的是 2025.08.26 版本的 hostapd 包。随后还单独回移植了几项 mt76 PCIe AER、复位和锁处理修复。这些修改能够减少驱动已知问题,但都没有改变本次故障模式。AP 启动后,LAN 仍会在相近条件下失效。
这部分尝试也保留在独立的 mt76 稳定性回移植 commit:c64075d 中。它与后面的 PCIe MSI 补丁分开,原因是两者解决的层次不同:mt76 补丁处理无线驱动自身的错误恢复和并发问题,MSI 补丁处理上游 PCIe Host 的中断资源分配。
这一步说明继续调整 hostapd 参数或反复重载 MT7922 只能绕开触发时机,不能处理根因。
检查网卡使用的中断
两块 RTL8125 的 PCIe 路径分别为:
1 | /sys/devices/platform/soc/22000000.pcie/pci0000:00/0000:00:00.0/ |
两块网卡都由 r8169 驱动:
1 | 0b:00.0 Ethernet controller [10ec:8125] |
但 /proc/interrupts 中只有一条共享中断:
1 | 34: ... INTx 2 Edge eth1, eth2 |
进一步查看 PCI capability,可以看到 RTL8125 支持 MSI-X,MT7922 也支持 MSI,但修复前都处于 Enable-。MT7922 使用另一条 legacy INTx。也就是说,这些设备具备消息中断能力,却没有得到可用的 MSI vector。
32 个 MSI vector 如何被耗尽
RK3576 使用 DesignWare PCIe Host,这个控制器在当前平台上提供 32 个 MSI vector。完整链路中有 ASM2806 和 ASM1182E 两级 ASMedia Switch,以及 NVMe、无线和两块有线网卡。
修复前的分配大致为:
1 | RK3576 PCIe MSI domain:共 32 个 vector |
Root Port 的服务消息布局要求一个按 16 对齐的 MSI block。随后,ASM2806 和 ASM1182E 的八个下游端口各自为 PCIe bandwidth notification 服务申请一个 MSI。当前系统并没有实际使用该带宽通知服务,但这些 port service device 仍占用了 vector。最后 NVMe 获得余下的八个。
RTL8125 和 MT7922 的驱动加载得更晚,此时 MSI domain 已经没有空闲项,只能退回 legacy INTx。
因此,MT7922 并不是“占用了太多 MSI”。正好相反,发生故障时它根本没有分配到 MSI。无线 AP 只是触发条件:Beacon、管理帧和 DMA completion 带来持续中断负载,使级联 PCIe Switch 后的 legacy INTx 路径变得繁忙,丢失或延迟的有线网卡完成中断最终让 r8169 TX ring 停住。
这也解释了系统刚开机时看起来正常的原因。无线未发射时,中断压力较低,INTx 路径的问题不容易显现;AP 正常工作一段时间后才会逐渐卡顿。
保留 MSI vector
在这套拓扑中,ASMedia 下游端口申请的 bandwidth notification service 没有驱动使用。处理方式是在 drivers/pci/pcie/portdrv.c 中,不为 ASMedia downstream port 创建该服务,同时保留 Root Port 原有处理:
1 | -if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || |
OpenWrt 中的补丁路径为:
1 | target/linux/rockchip/patches-6.12/999-pcie-asmedia-preserve-msi-vectors.patch |
完整修改可以直接查看:
Linux 的 PCIe port driver 会根据每个桥端口声明的 capability 创建 PME、AER、DPC、hotplug 和 bandwidth notification 等服务设备。服务设备需要通过中断接收端口事件。在本机的 ASMedia 下游端口上,bandwidth notification capability 虽然存在,却没有对应的实际服务消费者,仍然会提前占用一个稀缺的 MSI vector。补丁只阻止这类无消费者的服务设备被创建,让 vector 留给网卡和无线设备。
这项修改只跳过 ASMedia 下游端口的带宽通知 service device,不关闭整个 PCIe port service,也没有改动 PCIe 枚举、bus number 分配、链路训练和之前配置的 FPC POWER_EN。Root Port 的 PME 和 AER 服务仍然保留。
八个下游端口不再各占一个 vector 后,正好释放出八个 MSI vector,足够关键网络设备使用。
冷启动后的中断分配
重新编译内核并彻底冷启动后,中断分配变为:
1 | RTL8125 eth1 PCI-MSI/MSI-X IRQ 81 |
通过下面的命令可以检查设备 capability 和实际中断:
1 | lspci -vv -s 0b:00.0 |
两块 RTL8125 的 MSI-X 变为 Enable+,MT7922 的 MSI 也变为 Enable+,不再出现两个有线接口共享一条 edge-triggered INTx 的情况。
验证结果
MT7922 配置为信道 36、HE80 的 5 GHz AP。验证分为两次:第一次手动启动 AP,第二次正常重启并让 AP 自动启动。
每次启动后都确认:
phy*-ap0处于UP,LOWER_UP;- 无线接口有实际发送流量;
- MT7922 使用 PCI-MSI;
- 两块 RTL8125 使用 MSI-X;
- 两组独立的 150 次 LAN ping 均为 0% 丢包;
- 最大延迟约为 1 至 2 ms;
- 超过原先约 140 秒的典型故障时间后,没有出现
NETDEV WATCHDOG、TX queue timeout、mt76 reset 或 MCU timeout。
排查期间为了保持路由器可访问,曾增加 MT7922 延迟启动和重新绑定脚本。确认 MSI 分配修复后,这些脚本已经从固件和设备中删除:
1 | /etc/init.d/mt7922-rebind |
这些脚本会在启动阶段主动解绑无线设备,只改变故障出现的时间。保留它们反而会增加启动流程的不确定性。源码中的清理记录见 移除 MT7922 延迟重绑方案的 commit:ae09b20。
小结
本次网络卡死的根因是 PCIe MSI 资源耗尽,不是 MT7922 单独失控,也不是 hostapd 配置错误。MT7922 AP 开始发射后增加了中断压力,使 RTL8125 和无线设备退回 legacy INTx 所带来的问题稳定复现。
排查这类问题时,除了查看报错设备的驱动日志,还应检查所有 PCIe Endpoint 的 MSI/MSI-X 是否实际启用,并结合完整拓扑统计上游控制器的 vector 数量。设备显示 MSI-X: Enable- 不一定是驱动主动禁用了 MSI,也可能是上游 MSI domain 已经被先探测的桥和设备耗尽。
当前补丁已经解决这套硬件上的确定性故障,但它仍是针对 ASMedia Switch 行为的策略修改。正式提交 Linux 或 OpenWrt 上游前,需要进行更长时间的无线客户端吞吐和多网口压力测试,并由 PCI 子系统维护者确认跳过 bandwidth notification service 的适用范围。





