
1. SDIO -110 错误的本质与系统定位调 WiFi 模块的时候如果你在内核日志里翻到-110这个返回值基本意味着 SDIO 总线上的某一次命令或者数据传输已经超过内核规定的等待上限被强制判定为超时了。这个错误码在不同子系统里有不同含义而在 Linux 的 MMC/SDIO 子系统里-110对应的是-ETIMEDOUT也就是等待对方回应等了规定时间还没等到。WiFi 类模块走 SDIO 接口的非常多从常见的 SDIO WiFi 芯片到各种模组只要以 SDIO 方式挂到 SoC 的 SDMMC 控制器上就有机会撞见这个报错。我写这篇东西是想把 sdio -110 从日志表象一直扒到硬件和驱动的根子上因为大多数遇到这个错的人第一反应是去改 wifi 驱动源码结果改了半天发现根本没碰对地方。这篇文章适合几类人看正在做嵌入式 WiFi 移植的驱动工程师、调试 SDIO 外设的硬件工程师、以及跑 Linux 板子时被mmc0: timeout刷屏的同学。我会把 SDIO 报错的常见几个阶段拆开讲告诉你每一类 -110 分别指向什么病灶再给一套从软件到硬件的排查路径尽量让你能直接抄着用。先说结论-110从来不是一个孤立的错误它几乎总是成串出现的而且报出来的位置往往不是真正的故障点。真正要做的是看它在哪个命令上超的时、超时前后还输出了什么再顺着信号链一路往上摸。2. 从枚举到传数据搞清 -110 卡在哪一环2.1 SDIO 通信的完整链路长什么样要定位 -110得先知道一次 SDIO 交互到底经过了哪些环节。SDIO 是建立在 SD 总线基础上的物理上就是那几根线CLK、CMD、DAT0~DAT3四线模式或者只用DAT0一线模式。SoC 这一侧是 SDMMC host controller负责产生时钟、发送命令、搬运数据模块那一侧是 SDIO device负责响应。中间没有握手协议里的重传机制一次命令发出去等应答等不到就是等不到硬件控制器到点就报超时。命令层面分成两类CMD52用于读写单个字节的寄存器CMD53用于块读写WiFi 模块传数据主要靠CMD53。枚举阶段会依次发CMD5询问 IO 能力、CMD3分配相对地址 RCA、CMD7选中卡、CMD52去配置功能寄存器然后启用中断、初始化 WiFi 固件最后进入数据收发。每个节点都可能超时但含义完全不同。内存和总线这一侧同样关键。SoC 侧的数据通常走 DMADMA 要正确配置描述符和地址对齐时钟则由分频器从 PLL 分出来max-frequency决定上限。任何一环没对齐命令就会石沉大海最后以 -110 的形式爆出来。2.2 不同阶段的 -110 指向不同的病灶枚举阶段的 -110比如mmc0: error -110 whilst initialising SDIO card或者mmc_sdio_init_card里的超时问题多半在物理层最底层供电没稳住、时钟太乱、上拉电阻缺失、复位时序不对或者模块压根没上电。这个阶段驱动还没跑起来软件参数基本没机会使坏先怀疑硬件绝对不亏。固件下载阶段的 -110典型的是CMD53 write timeout刷屏模块已经枚举成功了但往它里面灌固件或者写配置的时候卡住。这种情况我遇到最多的是两个原因一是 SDIO 时钟频率给高了模块在低电压或者长走线下跑不到那么快二是供电在突发大电流下塌下去模块瞬间掉线命令自然没响应。运行阶段的零星 -110跑了几个小时才偶尔冒一条往往是信号完整性或者电源管理的问题。比如runtime PM把模块挂起了但你还在发数据或者时钟在省电模式被关掉还没恢复又或者走线串扰在高温下变严重。这类最难缠得靠长时间压测加示波器组合拳去抓。3. 硬件层排查供电、时钟与信号完整性3.1 供电能力直接决定能不能跑圆SDIO WiFi 模块有个很坑的特点平均电流看起来不大但发射瞬间的峰值电流能到几百毫安。文档标称的典型值常常是工作电流 80mA这种但你真按这个去选 LDO一发包就翻车。我建议按峰值留够余量起码给到模块数据手册里瞬态电流的两倍。排查的时候用万用表静态量是量不出问题的得上示波器而且探头要带足够带宽接在模块的供电脚上最好用短地线。看两样东西纹波和跌落。发射瞬间电压掉超过 5% 就要警惕如果掉到模块的最低工作电压以下SDIO 通信必然出问题。常见补救手段有换更大电流的 LDO、把走线加粗缩短、在模块电源脚旁边补一个 10uF 加 0.1uF 的组合电容靠近引脚放别嫌占地方。注意很多人习惯只焊一个 0.1uF 靠近模块这在静态下没问题但对付瞬态电流远远不够一定要有大电容兜底。还有一种隐蔽故障是上电时序。有些模块要求 IO 电压先于核心电压建立或者反过来如果电源轨同时上电导致 IO 域有异常电平模块可能直接进入一个半死不活的状态枚举就读不到报 -110。检查模块手册的 power sequence 章节用示波器同时抓几路电源看时序对不对。3.2 时钟频率和信号质量是重灾区SDIO 时钟是从 SoC 的 PLL 分频出来的max-frequency设成 50MHz实际波形不一定真的干净。我一般先从降频验证做起把设备树里的频率砍到 25MHz甚至降到 400kHz 这个枚举标准频率看 -110 还出不出。如果降频后一切正常那基本可以锁定是信号完整性或模块速率能力的问题。波形怎么看示波器抓CLK和CMD、DAT0重点看几个指标上升沿是不是太慢太慢会导致采样点错过、有没有过冲和振铃过冲会误触发或损伤 IO、占空比是不是接近 50%。如果时钟线走得太长、没有做好阻抗控制或者旁边有高速信号在干扰波形会很脏。改善办法包括缩短走线、时钟线两边包地、必要时串联一个小电阻做匹配。实操心得我遇到过一批板子时钟线和其他高速信号并排走了很长一段常温下勉强能跑一到夏天高温就零星报 -110后来把时钟线改道、加了串阻就稳了。信号完整性问题最喜欢在温度和电压的边界上露头。3.3 上拉电阻和走线那些容易忽略的细节SDIO 的CMD和DAT线本质上需要上拉。规范里要求这些线在空闲时保持高电平靠的就是上拉电阻。有些 SoC 内部带上拉有些必须外部加如果漏了总线空闲电平飘忽命令刚发出去就被干扰成别的电平模块没法解析自然超时。典型取值在 10k 到 50k 之间具体看总线的负载和速率高速模式下往往要更小一点保证边沿。走线上还有几个坑DAT几根线最好等长别一根长一根短否则四线模式下各个位的到达时间差太大采样错位CLK尽量远离易干扰的线模块和 SoC 之间的地要连好不能出现地电位差否则整个参考电平都在漂。这些在快速打样阶段很容易被忽略但恰恰是 -110 的常客。4. 软件与驱动层的定位手法4.1 设备树里的关键参数怎么配Linux 平台下 SDIO WiFi 能不能稳设备树配置占了很大比重。几个必看的节点参数bus-width决定用几线WiFi 用的模块大多数是四线写错成一线要么跑不快要么报错max-frequency是上限前面说了调它是最好的验证手段cap-sdio-irq表示支持 SDIO 中断non-removable表示模块是焊死的告诉内核别去做插拔检测keep-power-in-suspend关系到休眠时供电是否保持如果模块休眠后被断电唤醒时又没重新枚举就会报超时。sdmmc1 { status okay; bus-width 4; max-frequency 50000000; cap-sdio-irq; non-removable; keep-power-in-suspend; no-1-8-v; /* 如果模块 IO 只支持 3.3V 就加上 */ broken-cd; /* 无插拔检测引脚时用轮询 */ };no-1-8-v这个参数坑过不少人。有些 SoC 会尝试把信号电平切到 1.8V 来跑高速模式但你的模块 IO 只支持 3.3V一切换通信立刻乱套表现为各种 -110。如果模块明确不支持 1.8V 信号就把这个属性加上禁止内核切换电压域。反过来如果模块要求 1.8V 而你电路没做电压切换同样会出问题。4.2 用 debugfs 和动态调试把线索挖出来内核提供了一堆现成的观测点别上来就改代码。/sys/kernel/debug/mmc0/下面有几个文件特别有用ios能看到当前实际协商出来的时钟频率、总线宽度、时序模式这是判断我配的和实际跑的是否一致的第一手资料err_stats能看各类错误的计数。如果ios里显示的时钟和你设备树配的差很远说明协商过程本身就有问题先解决这个。打开 MMC 子系统的动态调试能拿到更细的日志echo file mmc*.c p /sys/kernel/debug/dynamic_debug/control echo file sdio*.c p /sys/kernel/debug/dynamic_debug/control打开之后再触发一次故障日志里会明确告诉你哪个命令超时、超时前的交互序列是什么。这个方法我强烈推荐因为它能把某处超时细化到第几步的哪个命令超时排查效率直接翻倍。4.3 降频和分步验证是最省钱的办法我最常用的一招二分法降频。先从标称频率往下砍一半不行再砍一半直到降到 400kHz 这个枚举频率。如果 400kHz 下枚举和基本通信都稳定那模块和 SoC 的连通性没问题问题在速率相关的部分——可能是走线、匹配也可能是模块对高时钟的容忍度。这时候再慢慢往上加找到能稳定工作的临界点往往离故障点就很近了。另一个思路是拆分阶段验证。只做枚举不做数据传输看会不会报错枚举过了只写固件看会不会超固件过了再跑数据收发。把链路一段段隔开哪一段开始报 -110病灶就锁定在那一段涉及的硬件和配置上。别一上来就整体压测那样只会得到一堆互相干扰的信息。5. 常见问题速查与实战避坑清单5.1 一张表对着症状找原因报错场景最可能的原因优先验证手段枚举阶段就 -110供电异常、复位时序、模块未上电示波器量供电和复位脚CMD53 写固件超时时钟过高、供电瞬态跌落降频验证 测峰值电压运行中零星 -110信号完整性、电源管理挂起冲突长时压测 关 runtime PM特定板子必现、其他正常走线、上拉、接地差异对比两块板的总线波形高温或低压下复现器件裕量不足环境箱加温/降压复现切 1.8V 后报错电压域不匹配设备树加 no-1-8-v这张表是我这些年踩坑攒下来的对照着看能省很多瞎试的时间。注意一点很多情况是几个原因叠加的比如供电本身就临界再叠上时钟偏高单看哪个都不算致命凑一起就必现 -110。5.2 几个我真心建议大家记住的坑第一个坑不要迷信模块文档的电流标称值。那些典型工作电流是给选型估算用的不是给你设计电源用的。真正决定成败的是瞬态特性一定要看模块手册里的峰值电流或者干脆自己上示波器抓。第二个坑降频和加余量永远比死磕高频划算。有些项目非要跑 50MHz为了那点速率折腾几周其实降到 40MHz 稳定性就上一个大台阶实际吞吐未必差多少。WiFi 的瓶颈经常不在 SDIO 时钟而在射频和协议栈。第三个坑-110 出现的位置经常是假象。日志说某个命令超时不代表那个命令有问题可能是前一步的副作用比如电源刚被切、时钟刚切换、模块刚复位。看日志要连着上下文一起看别只盯报错那一行。第四个坑改驱动之前先确认硬件和配置。我见过太多人一看到 -110 就去改驱动里的超时时间把超时从默认的几百毫秒改成几秒。这治标不治本只是把报错延后真到了生产环境还是会翻车。超时时间适当加长可以做临时验证但不能当解决方案。提醒如果加长超时后错误消失了恰恰说明链路里有慢或丢的问题而不是没问题一定要继续往下查。第五个坑同一块板子在别人机器上好的在你这里不行先比电源和时钟。不同批次、不同环境温度、不同负载都会改变裕量。做 WiFi SDIO 移植最好手里有一台能看眼图的示波器能省下大量试错成本。6. 把问题收敛我的实际排查顺序真正上手排查 sdio -110我习惯按固定顺序走一遍这样不容易漏。第一步看日志定位阶段确认是枚举、固件下载还是运行时超时这一步决定了后面往哪个方向使劲。第二步量供电静态加瞬态都看尤其是发射相关的瞬间跌落。第三步降频验证快速判断是速率相关还是连通性相关。第四步看波形主要盯时钟质量和总线空闲电平。第五步查设备树和电压域配置确认参数和模块能力匹配。第六步才是动驱动而且优先用动态调试看细节而不是直接改代码。这个顺序的逻辑是由外到内、由廉价到昂贵。量电和降频几乎不花钱改驱动最费时间还容易引入新问题。多数 -110 在第三步之前就能定位个七七八八剩下的细活才交给波形和内核调试。我个人在几个项目里最大的体会是SDIO -110 里纯软件问题占的比例远没有大家想象的高供电和信号完整性才是大头。尤其是那些偶发高温才出某块板子才出的 -110几乎都能在电源和走线上找到答案。所以下次再看到这个错误先别急着怀疑驱动拿起探头量一量往往比盯着代码看一天管用。