
1. 蓝牙灰掉的那一刻症状与根因分析1.1 我遇到的现象去年帮朋友折腾一台搭载联发科MT7922无线网卡的笔记本原装系统是Windows 10后来因为开发需要改装了Ubuntu 20.04。系统装好之后WiFi一切正常5GHz频段跑满千兆宽带没问题但蓝牙就像断了气一样——右上角系统设置里的蓝牙开关直接是灰色的点都点不动。用rfkill list查看蓝牙显示Soft blocked: no说明软阻塞没开启可它就是死活不工作。如果你也遇到类似情况先别急着怀疑网卡坏了。MT7922这颗网卡在Linux下的表现跟内核版本和固件版本强相关Windows下能用说明硬件本身没毛病问题几乎都出在驱动和固件层面。这篇文章就把我整个排查和解决的过程完整记录下来包括每一步操作背后的原因以及最后踩过的几个坑希望能省掉你几天的折腾时间。1.2 为什么偏偏是Ubuntu 20.04 MT7922出问题先说清楚MT7922这颗芯片的来历。MT7922是联发科2022年面向中高端笔记本推出的WiFi 6E无线网卡支持蓝牙5.2经常跟AMD锐龙平台的笔记本配套出货比如华硕天选系列、拯救者部分型号、还有一些轻薄本都会用到它。它在Windows下表现确实不错但到了Linux这边事情就棘手了。Ubuntu 20.04 LTS首发于2020年4月默认内核是5.4。而MT7922的蓝牙驱动是随内核5.14之后才逐渐完善的5.15版本才算有可用的主线和固件支持。也就是说出厂状态的Ubuntu 20.04内核根本认不出MT7922的蓝牙设备驱动代码压根就不存在蓝牙当然起不来。而且不止驱动还有一层的固件文件firmware也缺——MT7922的蓝牙部分需要专门的补丁文件才能完成初始化这个固件在Ubuntu 20.04默认的linux-firmware包里也没有。一个冷知识是MT7922这类M.2无线网卡虽然插在PCIe接口上但蓝牙功能的通信通道走的是USB总线。所以排查的时候要在lsusb里找设备光看lspci只能看到无线网卡本体容易误判。这个点后面展开说。2. 动手前的排查清单先确认问题出在哪一层2.1 第一步确认你的网卡确实是MT7922排查任何驱动问题第一步都是弄清硬件型号千万别凭感觉。查看无线网卡型号用这个命令lspci -nnk | grep -i network如果是MT7922通常显示类似这样03:00.0 Network controller [0280]: MEDIATEK Corp. MT7922 802.11ax PCI Express Wireless Network Adapter有的设备名称会更具体比如MT7922 Wi-Fi 6E BT5.2。只要厂商是MEDIATEK基本就能确认是联发科这一系。接着看蓝牙在USB总线上的枚举情况lsusb | grep -i mediatek正常情况下会有一条类似MediaTek Inc. Wireless_Device的记录这就是MT7922的蓝牙控制器在USB层面挂出来的设备。如果lsusb里什么都看不到说明蓝牙压根没有被系统识别硬件枚举层就挂了如果能看到但rfkill list显示蓝牙还在说明驱动加载了但没完成初始化。这两条线索决定了后续排查方向的侧重。2.2 第二步记录内核版本、模块状态和阻塞情况接下来把系统的三个关键状态全部打印出来这些信息是后面做判断的依据uname -r lsmod | grep -i bluetooth rfkill listuname -r告诉你当前内核版本。如果显示的是5.4.0-x-generic那恭喜你基本坐实了根因——内核太老蓝牙驱动缺失。如果显示5.15.0-x-generic或更高说明你已经换了HWE内核问题可能集中在固件层面。lsmod检查蓝牙相关的内核模块btusb、bluetooth是否加载成功。如果加载了用dmesg看内核日志里有没有蓝牙控制器的初始化报错如果没加载可能是模块被Secure Boot拦截了也可能是设备枚举失败。rfkill list输出里如果有Soft blocked: yes或Hard blocked: yes那又是另一条线路的排查方向。2.3 第三步用日志锁定真实报错日志是整个排查过程里最会说话的线索MT7922蓝牙驱动失败时内核日志里的报错非常有特征性。执行sudo dmesg | grep -i bluetooth sudo dmesg | grep -i mt7922常见报错有这几种firmware file mediatek/mt7922/mt7922_bt_patch.bin not found——固件文件缺失这是最常见的情况Ubuntu 20.04自带的linux-firmware不包含MT7922蓝牙固件。Direct firmware load ... failed with error -2——同样是固件加载失败-2对应ENOENT文件不存在。hci0: command 0xfc55 tx timeout——固件加载到一半执行超时跟固件版本不匹配或内核蓝牙栈太老都有关系。bluetooth hci0: firmware request failed——固件请求流程被中断通常是权限、文件路径或签名校验问题。我那次排查时dmesg输出直接就是Direct firmware load for mediatek/mt7922/mt7922_bt_patch.bin failed with error -2非常干脆就是固件缺位。这也把问题范围缩小到了两步要么升级内核拿到驱动要么补齐固件文件或者两个一起做。3. 从软到硬四条路线逐步解决3.1 方案一升级HWE内核最简单的首选方案Ubuntu 20.04提供了一个官方支持的“硬件使能”更新包叫HWE全称Hardware Enablement。升级到HWE栈就能把内核换成5.15版本里面已经有MT7922蓝牙驱动的基础支持。这是最省事、也最“官方”的路线。sudo apt update sudo apt install --install-recommends linux-generic-hwe-20.04 sudo reboot装完后切到新内核验证uname -r需要注意HWE内核是给桌面版Ubuntu 20.04用户准备的服务器版用的HWE内核包名不同linux-generic-hwe-20.04-server。笔记本场景基本走桌面这条命令就行。另外升级内核不是“桃换符”就能解决一切即使内核到了5.15我实测时蓝牙还是没起来——因为固件文件还是缺的。所以这个方案只是铺垫别指望一步到位。3.2 方案二手动安装更新的主线内核备选如果你用的是Ubuntu 20.04.5之前的老版本或者HWE更新因网络原因一直失败还可以手动上更新的主线内核。Ubuntu官方维护了一个mainline内核仓库提供各版本候选内核的deb安装包下载地址在kernel.ubuntu.com的mainline目录下。选择内核时有几个讲究MT7922蓝牙最稳的版本是5.17~6.1这个区间太新的mainline内核有概率引入回归太旧的跟HWE没区别。比如我后来重装系统时直接装了5.19.x的官方包蓝牙和WiFi都正常工作。下载对应架构的四个deb文件linux-headers、linux-headers-generic、linux-image、linux-modules然后统一安装sudo dpkg -i linux-*.deb安装后重启在GRUB菜单里确认选到新内核。我建议不到万不得已别用mainline内核跑生产环境毕竟没有Ubuntu的安全补丁跟踪但排障阶段拿它验证驱动是否正常很合适——如果mainline内核下蓝牙好了说明确实是原内核太老后续要么等HWE更新要么平滑迁移到新内核。3.3 方案三补齐MT7922固件文件决定性一步这一步决定了90%的成败。MT7922的蓝牙固件不在内核里而是存放在文件系统的/lib/firmware/mediatek/mt7922/目录下内核在驱动初始化时会主动去读取。Ubuntu 20.04自带的老版本linux-firmware包里没有MT7922的蓝牙固件所以必须手动补齐。先看目录里现在有什么ls -la /lib/firmware/mediatek/mt7922/如果提示目录不存在或里面只有WiFi相关的.bin文件比如mt7922_rom_patch.bin、mt7922_fw.bin那就是蓝牙固件缺了。需要补的文件是mt7922_bt_patch.bin蓝牙补丁mt7922_bt_firmware.bin蓝牙主固件怎么获取最稳妥的方式是从Linux内核官方固件仓库拉取。先装gitsudo apt install git cd /tmp git clone https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git然后只拷贝MT7922蓝牙相关的固件别整包覆盖——整包覆盖容易破坏其他设备的固件兼容性不推荐sudo mkdir -p /lib/firmware/mediatek/mt7922 sudo cp /tmp/linux-firmware/mediatek/mt7922/*.bin /lib/firmware/mediatek/mt7922/ sudo cp /tmp/linux-firmware/mediatek/mt7922_bt_patch.bin /lib/firmware/mediatek/ 2/dev/null sudo cp /tmp/linux-firmware/mediatek/mt7922_bt_firmware.bin /lib/firmware/mediatek/ 2/dev/null注意固件文件有两个存放处mediatek/mt7922/子目录和mediatek/根目录。不同内核版本对路径的查找方式略有差异5.15以前的内核倾向于在mediatek/mt7922/找5.15及以后的版本有些固件引用会直接落到mediatek/下。既然已经动了手两边都放一份不影响使用。拷贝完成之后重启或sudo modprobe -r btusb sudo modprobe btusb重新加载模块再执行rfkill list和dmesg | grep -i bluetooth确认蓝牙是否被正确枚举。3.4 方案四检查rfkill阻塞和蓝牙服务状态内核和固件都就位之后蓝牙依然可能因为被软件或硬件开关“软禁”而无法开启。这一步是用来排查剩余问题的手段千万别跳过。rfkill list systemctl status bluetooth sudo systemctl enable bluetooth sudo systemctl start bluetoothrfkill list里如果看到蓝牙的Soft blocked: yes执行rfkill unblock bluetooth解锁如果Hard blocked: yes那说明硬件层面的开关被物理切断了笔记本的飞行模式组合键通常是FnF2或FnF12或侧边物理开关要检查确认一下。systemctl status bluetooth是查看蓝牙守护进程如果状态不是active (running)先尝试手动启动。我之前遇到过一次系统休眠唤醒后蓝牙服务自己挂掉的情况systemctl restart bluetooth就恢复正常了不用重新开机。4. 实操记录我的完整修复链路4.1 一步步做完的效果我当时按照上面四条路线实际操作顺序是这样的先升级HWE内核到5.15重启后uname -r确认已切换到新内核但蓝牙依然灰掉。用dmesg看日志出现mediatek/mt7922/mt7922_bt_patch.bin not found。从linux-firmware仓库拉取固件将mt7922_bt_patch.bin和mt7922_bt_firmware.bin分别放到/lib/firmware/mediatek/mt7922/和/lib/firmware/mediatek/。执行sudo modprobe -r btusb; sudo modprobe btusb重载蓝牙驱动。这时候神奇的事情发生了rfkill list里蓝牙那条变成Soft blocked: no且不再是blocked状态右上角设置里的蓝牙开关从灰色变成了可点击。点开之后能扫描到附近的蓝牙音箱和手机连接延迟和稳定性都在可接受范围内。4.2 参数选择的逻辑为什么先升级内核而不是先补固件有人可能会问既然是固件缺失为什么不直接补固件非要走升级内核这一步因为MT7922蓝牙驱动的工作机制是“内核驱动 固件协作”内核负责通过btusb模块与蓝牙控制器通信固件负责控制器内部的逻辑运行。如果内核版本太老、驱动代码本身不支持MT7922就算你把固件文件放对了路径内核也不会去读它——根本没有对应的驱动去发起固件加载请求。反过来如果内核够新但固件缺失驱动加载到一半就会因为找不到固件而中止初始化。所以两条腿都得走路先升级内核保证驱动存在再补固件保证初始化能完成。换成人话就好比内核是操作系统派发任务的调度员固件是设备自己的操作手册。你没有调度员手册再厚也没人看只有调度员没有手册指挥到一半就得卡壳。4.3 用btmon验证蓝牙HCI层状态进阶操作如果图形界面的蓝牙开关已经能点开但连设备时不时掉线、配对提示失败可以用btmon监控蓝牙HCI层的通信数据。这个工具在bluez包里安装后这样跑sudo apt install bluez sudo btmon 然后正常去系统设置里扫描、配对、连接btmon的输出会实时显示Host和Controller之间的HCI命令与事件包。如果配对时看到Authentication Failed或者Pin Code Missing通常是蓝牙协议栈版本太老可以考虑升级bluez到5.65以上版本Ubuntu 20.04默认的bluez 5.53确实偏老。如果看到大量HCI Event: Command Timeout则是固件与驱动配合出了问题回到固件更新那条线继续排查。5. 踩坑记录与常见问题速查5.1 我踩过的几个坑希望你一次避开坑一Secure Boot拦截导致模块加载失败。很多预装Windows的笔记本开启UEFI安全启动模式Linux内核模块如果没签名会被拒之门外。我那次就是卡在这里——HWE内核装好了但lsmod | grep btusb输出为空任何蓝牙相关模块都没加载。查dmesg看到Lockdown: secure boot is enabled的提示。解决办法是进BIOS禁用Secure Boot或者给模块签名操作复杂但能保住安全启动。日产笔记本用户强烈建议直接关掉Secure Boot别在这个上纠结开发机场景不存在安全性敏感需求。坑二把WiFi固件当成蓝牙固件反复拷贝。MT7922的WiFi和蓝牙固件都叫mt7922_*.bin但WiFi固件放在/lib/firmware/mediatek/下蓝牙固件放在/lib/firmware/mediatek/mt7922/下。我第一次从网上找到的教程误导人把WiFi固件塞进了蓝牙目录里结果压根不起作用还混淆了排查方向。核对文件是否拉对最直接的办法是对照linux-firmware仓库里的目录结构别凭文件名瞎猜。坑三电源管理导致休眠唤醒后蓝牙消失。有个坑是笔记本合盖休眠后重新打开蓝牙直接在系统里消失lsusb里也看不到了。这个问题跟PCIe/ASPM电源管理策略有关试过给grub加上pcie_aspmoff参数可缓解一部分情况。不过这属于进阶玩法建议先动了基础驱动和固件确认稳定后再去调整电源管理不要一开始就用这个参数。坑四升级内核后没重建initramfs导致固件加载异常。用dpkg装HWE内核包时会自动触发initramfs重建一般不用手动干预。但我遇到过手动删除了老内核后initramfs里的固件索引没更新的情况导致明明文件在磁盘上内核却报“找不到固件”。执行一次sudo update-initramfs -u重建一下即可解决。5.2 常见问题速查表症状可能原因解决动作蓝牙开关灰色rfkill list无蓝牙项内核版本过老蓝牙驱动未加载升级HWE内核或装mainline新内核dmesg报firmware file mt7922_bt_patch.bin not found固件缺失从linux-firmware仓库拷贝固件到指定目录lsmod无btusb/bluetooth模块Secure Boot拦截或模块加载失败BIOS关闭Secure Boot检查UEFI设置rfkill list显示Hard blocked: yes硬件开关处于关闭状态检查笔记本飞行模式组合键、侧边物理开关蓝牙能搜到设备但连接总失败bluez版本太老或HCI层异常升级bluez到5.65sudo btmon查看HCI报错休眠唤醒后蓝牙消失电源管理策略问题试pcie_aspmoff休眠前先关蓝牙再开配对时提示Authentication Failed固件版本不匹配更新固件到最新版本或降级内核试兼容版本5.3 如果以上全试了还是不行这是给最坏情况准备的预案别放弃治疗。第一确认网卡是不是真的MT7922或者是不是MT7922AM.2接口有多个变体。有些打着“MT7922”旗号的网卡实际是RZ616AMD版的MT7921变体两者固件路径、设备ID都有差异错套驱动方案自然会失败。第二去主板或笔记本厂商官网看看有没有BIOS更新。我见过一台机器在旧版BIOS下蓝牙设备枚举不稳定更新BIOS后一切正常。这个操作的风险和收益自己权衡但确实是很多所谓“网卡坏了”的隐藏真相——BIOS里USB/PCIe资源分配不合理新设备枚举不稳定。第三实在不行就换网卡。MT7922在Linux下的支持情况虽然一直在进步但对比Intel AX210这种老牌Linux友好网卡还有差距。如果机器是M.2接口且BIOS没有白名单限制直接换AX210或AX211插上基本免驱就能用。我后来在另一台机器上就是这么干的省掉的折腾时间远超一张网卡的价格。6. 最后分享一点实际体验折腾完成之后我给朋友那台笔记本留了张便签如果以后升级内核或更新系统后蓝牙又出问题第一件事不是怪网卡而是把/lib/firmware/mediatek/mt7922/目录里的固件文件跟linux-firmware仓库对照一遍大概率是升级过程把老固件覆盖或者路径变了。这个习惯帮我后面又修好了三台同型号设备每次都是固件缺失或内核更新的连锁反应。整体体验下来MT7922在Linux下的方案就是三句话内核版本够新固件放对路径Secure Boot别开。把这三板斧用好Ubuntu 20.04下用MT7922蓝牙日常连鼠标键盘音箱稳定性和延迟都完全够用。当然如果你对Linux生态的“省心”要求高于硬件性能换Intel网卡是另一个性价比很高的选择驱动包袱轻太多了。