T33-Linux 3.10 下 USB 4G 模组软重启后连接失败的 RX URB 回收修复
适用范围
本文适用于 T32 平台、Linux kernel 3.10 与 EC801 USB 4G 网卡模组组合中出现的断开及重连异常。典型触发条件是模组工作期间执行软重启。其他内核版本或 USB 网卡驱动的断开流程可能不同,应先核对接收队列和 URB 回收实现,再决定是否采用相同方案。
问题现象
模组正常接入后,系统能够创建 usb0 网卡并完成网络通信。执行软重启时,网卡连接可能无法恢复。异常发生后,旧的 usb0 节点在断开阶段未被完整删除;模组重新启动并再次接入后,网卡也不能正常重建。这个特征表明故障发生在 USB 网卡断开和资源释放阶段,而不是单纯的拨号失败或网络参数错误。
原因分析
模组软重启会触发 USB 设备断开。此时,网卡驱动的 rxq 接收队列中可能仍有尚未处理完的 skb。驱动对相应 URB 执行 unlink 后,URB 状态变为 -131,即 ECONNRESET。在发生问题的 Linux kernel 3.10 USB 驱动实现中,该状态下的 URB 未能顺利完成后续终止和回收,kill URB 流程因等待事件不能结束。
由于 RX URB 回收被阻塞,USB 网卡的终止流程无法继续完成,usb0 节点及相关资源也不能彻底释放。模组再次接入时,旧连接遗留的状态影响网卡重建,最终表现为软重启后概率性连接失败。因此,排查重点应放在断开阶段的 rxq 和 RX URB 回收链路,而不能只观察模组重新枚举后的网络状态。
修复方法
1. 检查 USB 网卡驱动中是否存在为解决此问题而修改 urb done 路径的代码。如有此类改动,先回退该方向的修改,避免在完成回调中继续绕行处理。
2. 在驱动中定位 usbnet_terminate_urbs,确认该函数对 dev->rxq 执行 unlink_urbs 的方式。
3. 将 dev->rxq 的 URB unlink 调整为同步处理,使处于 -131(ECONNRESET) 状态的 RX URB 能够在设备断开期间完成终止和回收,不再长期阻塞于等待事件。
4. 重新编译并部署修改后的内核或驱动,随后执行模组软重启测试。具体代码写法应与当前分支的函数接口、USB 休眠唤醒逻辑及资源释放顺序保持一致,不宜直接套用其他分支的实现。
如果暂时无法更新驱动,可在软重启模组前先执行:
sh
ifconfig usb0 down
该命令会主动关闭网卡接口,可作为临时规避措施。它能够避免原故障再次出现,但不能替代对 RX URB 回收链路的修复。
验证方法与结果
驱动修改后,应反复执行模组软重启,并检查以下完整链路:旧的 usb0 节点能够正常删除;RX URB 回收不再持续阻塞;模组重新接入后能够重新创建 usb0;网络通信能够恢复;持续业务负载下不再出现相同故障。
实际连续运行验证中,一套设备在修改后持续运行 3 天未出现异常,另一套设备持续运行一晚未出现异常。采用临时规避方式时,在模组重启前执行 ifconfig usb0 down,原连接失败现象也未再次出现。这些结果支持故障与 RX URB 回收阻塞有关,并支持在 usbnet_terminate_urbs 中同步处理 dev->rxq 的修复方向。由于现有记录未包含完整的软重启次数和更大规模的长期统计,部署到长期运行环境时仍应结合实际业务负载扩大循环重启和并发设备测试。
注意事项
同步回收 dev->rxq 中的 RX URB 是针对根因的处理方式,重启前关闭 usb0 仅用于临时规避,两者不能混为一谈。修改范围应聚焦于 USB 网卡接收队列的终止与回收逻辑,不应把缺少独立验证的外围驱动调整列为必要步骤。移植到不同内核或驱动分支时,还应核对断开处理、休眠唤醒和 URB 生命周期管理,防止同步化调整破坏原有资源释放顺序。验证过程中建议保留 USB 断开、URB 终止、网卡节点删除和重新枚举日志,以确认故障确实消失在回收阶段,而不是被上层网络重试暂时掩盖。
