:從設(shè)備枚舉到休眠喚醒)
上周我接到一個(gè)挺典型的移植需求把AIC8800DC這顆WiFi6模組接到一塊新的ARM主板上走SDIO接口。按我之前做MT7668、RTL8822等SDIO WiFi的慣性思維以為無非是改改設(shè)備樹、把驅(qū)動編進(jìn)去結(jié)果第一輪就熄了火——內(nèi)核日志里SDIO卡根本沒枚舉出來網(wǎng)卡節(jié)點(diǎn)更是影都沒有。斷斷續(xù)續(xù)排了三天把上電時(shí)序、固件路徑、OOB中斷、休眠喚醒整個(gè)鏈路翻了個(gè)底朝天。這篇文章不打算講AIC8800DC怎么開箱即用而是把從設(shè)備識別到休眠喚醒的完整排錯(cuò)過程一條條擺出來給接下來要碰AIC8800DC或者其他SDIO WiFi6方案的朋友做個(gè)參考。文中涉及的排錯(cuò)思路和調(diào)試手段大部分也適用于其他SDIO WiFi模組。你如果是第一次搞這類移植建議把第四節(jié)設(shè)備樹配置和第六節(jié)休眠喚醒部分多讀兩遍那兩個(gè)位置是坑最密集的地方。1. 為什么是AIC8800DC選型邏輯與移植前的準(zhǔn)備清單1.1 這顆WiFi6模組到底什么水平AIC8800DC屬于AIC8800系列里非常典型的WiFi6方案雙頻并發(fā)是它的基礎(chǔ)盤2.4GHz和5GHz都支持802.11a/b/g/n/ac/ax全協(xié)議棧覆蓋。對比wifi4和wifi5WiFi6帶來的最直觀提升不在峰值速率而在高密度環(huán)境下的排隊(duì)效率和功耗控制。OFDMA允許一次傳輸同時(shí)服務(wù)多個(gè)終端TWT機(jī)制則讓終端可以在約定時(shí)間窗內(nèi)打瞌睡這兩點(diǎn)對嵌入式設(shè)備的意義遠(yuǎn)大于紙面上的PHY速率。這顆模組的目標(biāo)市場很明顯帶屏設(shè)備、智能家居網(wǎng)關(guān)、工業(yè)手持終端、輕量級平板。它不跟QCA6390、MT7921那類旗艦芯片爭性能但在成本和功耗敏感的項(xiàng)目里把WiFi6跑滿基本夠用。1.2 SDIO接口在這個(gè)方案里的權(quán)重SDIO之所以一直是嵌入式WiFi的主流選擇原因很樸素幾乎所有SoC都自帶MMC控制器不用額外掛USB Hub或者PCIe SwitchBOM成本省下來很大一塊。AIC8800DC的SDIO接口可以跑到4線SDR104理論上能給WiFi鏈路提供一個(gè)還算寬裕的管道。但要注意SDIO這個(gè)管道的實(shí)際有效帶寬并不等于總線時(shí)鐘頻率。SDR104模式下120MHz的時(shí)鐘單次傳輸還要經(jīng)過SDIO命令頭、CRC校驗(yàn)、中斷輪詢等開銷實(shí)際能穩(wěn)定支撐的TCP吞吐一般也就是兩三百M(fèi)bps的水平。所以如果你項(xiàng)目里有必須跑滿500Mbps以上的大流量場景SDIO方案要提前想清楚如果只是1080P視頻流、語音、物聯(lián)網(wǎng)數(shù)據(jù)上報(bào)SDIO完全夠用。1.3 移植前必須摸清的軟件素材正式動手改代碼之前我建議先把下面這幾樣?xùn)|西備齊并核對過否則排錯(cuò)時(shí)會陷入“不知道是哪一層出了問題”的泥潭。素材內(nèi)容用途原理圖SDIO四線、CLK、CMD、復(fù)位、供電、中斷GPIO確認(rèn)硬件連接排查枚舉失敗官方BSP驅(qū)動一般是drivers/net/wireless/aic8800整套源碼提供probe、suspend/resume等基礎(chǔ)代碼固件倉庫fw.bin、配置bin等文件確認(rèn)固件與驅(qū)動版本的一致性內(nèi)核版本與config當(dāng)前內(nèi)核的defconfig、menuconfig設(shè)置確認(rèn)cfg80211/mac80211、MMC子系統(tǒng)配置廠商調(diào)試工具能讀寄存器、發(fā)私有命令的小工具休眠喚醒、RF校準(zhǔn)、吞吐測試都靠它這里插一句我踩過的坑固件和驅(qū)動必須來自同一個(gè)軟件發(fā)布包。AIC8800的固件和驅(qū)動版本之間常有隱含的協(xié)議依賴混搭輕則功能異常重則probe直接失敗。所以拿到BSP之后先看git log或者版本號確認(rèn)內(nèi)核補(bǔ)丁、驅(qū)動、固件三者是否匹配。2. SDIO設(shè)備識別階段枚舉失敗時(shí)最先懷疑什么2.1 硬件上電時(shí)序卡都沒識別時(shí)先查什么SDIO設(shè)備識別失敗第一反應(yīng)不要直接改軟件。維修師傅都知道“先量電壓再動烙鐵”驅(qū)動移植也一個(gè)道理。AIC8800DC這類模組上電是有嚴(yán)格時(shí)序要求的主電源和IO電源要先穩(wěn)定然后復(fù)位腳釋放模組內(nèi)部開始加載BootROM之后才會響應(yīng)SDIO的命令。如果復(fù)位釋放太早卡還在死機(jī)狀態(tài)MMC控制器發(fā)CMD5/CMD3得不到回應(yīng)日志里就是下不了臺。用示波器量三個(gè)點(diǎn)主電源VDD、IO電源VDDIO、復(fù)位腳RST_n。正常波形應(yīng)該是VDD先起來等電源穩(wěn)定以后RST_n再拉高拉高到第一次SDIO命令之間通常有毫秒級延時(shí)。如果你發(fā)現(xiàn)復(fù)位跟電源同時(shí)跳變或者電源還有紋波的時(shí)候復(fù)位就已經(jīng)釋放了那枚舉失敗屬于典型硬件時(shí)序問題。2.2 設(shè)備樹節(jié)點(diǎn)配到什么程度才算到位確認(rèn)硬件之后設(shè)備樹是你第一個(gè)需要較真的軟件層。絕大多數(shù)SDIO WiFi在設(shè)備樹上不需要像USB那樣寫一堆子節(jié)點(diǎn)但幾個(gè)關(guān)鍵屬性必須正確。我常用的模板是sdhci1 { status okay; bus-width 4; max-frequency 100000000; sd-uhs-sdr104; non-removable; cap-sdio-irq; keep-power-in-suspend; pinctrl-names default; pinctrl-0 sdio_pins; vmmc-supply wifi_pwr; vqmmc-supply wifi_io_pwr; };逐個(gè)解釋這幾個(gè)屬性的作用bus-width 4SDIO四線模式。如果只配了1-bit后面吞吐會非常難看max-frequency建議第一版先設(shè)在50MHz~100MHz別一上來就頂?shù)絊DR104的200MHz。很多枚舉失敗其實(shí)是時(shí)鐘跑太快信號 integrity 跟不上non-removable告訴MMC核心這是一顆貼片WiFi不是可插拔SD卡別做熱插拔檢測cap-sdio-irq允許使用SDIO的in-band中斷機(jī)制keep-power-in-suspend休眠時(shí)不要切斷電源這一條對WiFi喚醒場景幾乎是必配后面會展開講vmmc-supply/vqmmc-supply如果模組供電是由PMIC的LDO/DCDC控制的這兩個(gè)節(jié)點(diǎn)要配好否則MMC核心在枚舉時(shí)會按電源域去開關(guān)電導(dǎo)致模組根本沒電。如果你用的平臺在SDIO控制器上還掛了mmc-pwrseq一般是控制復(fù)位和使能腳的小電路也要確認(rèn)pwrseq的復(fù)位時(shí)序別和模組要求的打架。我在一個(gè)項(xiàng)目里就碰過pwrseq把復(fù)位腳默認(rèn)拉低結(jié)果每次枚舉都超時(shí)最后去掉pwrseq直接由GPIO控復(fù)位才解決。2.3 內(nèi)核日志里那幾行報(bào)錯(cuò)每一行都在說什么枚舉階段的內(nèi)核日志很有規(guī)律我把我見過的幾類典型報(bào)錯(cuò)整理成一張表日志中的錯(cuò)誤含義優(yōu)先排查方向mmc1: error -110 whilst initialising SDIO card超時(shí)卡沒響應(yīng)主機(jī)命令上電時(shí)序、復(fù)位信號、CLK頻率過高mmc1: error -84 whilst initialising SDIO cardCRC錯(cuò)誤命令/數(shù)據(jù)線信號質(zhì)量差SDIO走線過長、電平不匹配、缺少上拉mmc1: card claims to support SDIO but has no SDIO functionsCIS讀取失敗固件沒正確加載BootROM、模塊損壞mmc1: new high speed SDIO card at address 0001枚舉成功這是好日志繼續(xù)排查驅(qū)動probe其中-110出現(xiàn)頻率最高。遇到它先查硬件時(shí)序和時(shí)鐘頻率別急著懷疑驅(qū)動代碼。還有一類隱蔽問題SDIO卡枚舉成功后MMC核心會發(fā)現(xiàn)多個(gè)function比如function 0是控制通道function 1是WiFi數(shù)據(jù)通道甚至還有function 2調(diào)試通道。如果你的內(nèi)核開啟了CONFIG_MMC_DEBUG會看到類似new SDIO function 2這樣的日志。如果系統(tǒng)只識別到function 0沒有后續(xù)的function多半是卡內(nèi)固件和應(yīng)用處理器之間的握手沒完成重點(diǎn)查模組有沒有真正跑到正常固件狀態(tài)。2.4 枚舉問題快速定位清單真到了現(xiàn)場按下面這個(gè)順序排查比自己瞎翻日志效率高不少量電源和復(fù)位時(shí)序用示波器確認(rèn)上電順序是否符合規(guī)格書檢查MMC控制器時(shí)鐘查看clk_summary確認(rèn)SDIO CLK已經(jīng)開啟降低總線頻率把max-frequency降到50MHz再試一次確認(rèn)供電節(jié)點(diǎn)vmmc/vqmmc或者GPIO控制的regulator有沒有被正確拉起抓CMD線波形用邏輯分析儀看CMD波形確認(rèn)主機(jī)到底有沒有發(fā)出CMD0/CMD5打開MMC調(diào)試開啟CONFIG_MMC_DEBUG后dmesg里能看到每次命令交互的返回值能精確定位是卡不響應(yīng)還是響應(yīng)了但CRC校驗(yàn)失敗。3. 驅(qū)動加載階段的坑固件、中斷與DMA3.1 驅(qū)動源碼與內(nèi)核版本的組合關(guān)系A(chǔ)IC8800的驅(qū)動源碼位置很標(biāo)準(zhǔn)一般在drivers/net/wireless/aic8800/下面編譯開關(guān)多半是CONFIG_AIC8800。但不同內(nèi)核版本對WiFi驅(qū)動的接口變化很大特別是cfg80211和mac80211的API隔一個(gè)內(nèi)核大版本就可能改函數(shù)簽名。我做過一個(gè)不嚴(yán)謹(jǐn)?shù)珜?shí)用的判斷如果官方BSP提供的內(nèi)核補(bǔ)丁是針對5.10的而你項(xiàng)目用的是6.1那大概率要自己動一些代碼才能編過。這個(gè)時(shí)候別硬剛先把驅(qū)動源碼里的compat目錄或者老版本適配代碼看清楚很多廠商會自帶老內(nèi)核兼容層實(shí)在沒有再考慮用backport方案。另外cfg80211、mac80211、rfkill這幾個(gè)內(nèi)核配置必須打開不然驅(qū)動編過了insmod也會報(bào)一堆undef symbol。檢查內(nèi)核配置時(shí)順手看下CONFIG_CFG80211_WEXT這個(gè)舊無線擴(kuò)展接口部分工具鏈還依賴它。3.2 固件加載路徑與版本匹配SDIO設(shè)備識別成功之后驅(qū)動probe接下來的動作就是把固件灌進(jìn)模組。這一階段最常見的報(bào)錯(cuò)是類似aic8800: failed to request firmware: fw.bin或者aic8800: fw download timeout先說第一個(gè)failed to request firmware基本就是找不到文件。AIC8800的固件一般會放在/lib/firmware/aic8800/或者/vendor/firmware/下具體路徑由驅(qū)動里的宏或者Kconfig決定。我在調(diào)試時(shí)可沒少干這種事# 快速確認(rèn)固件到底在哪、加載沒加載成功 find / -name *.bin -path *aic* 2/dev/null # 確認(rèn)load_firmware的時(shí)候驅(qū)動申請的是哪個(gè)文件 mount -t tracefs none /sys/kernel/tracing echo firmware:* /sys/kernel/tracing/set_event echo 1 /sys/kernel/tracing/tracing_on cat /sys/kernel/tracing/trace再說第二個(gè)fw download timeout比找不到文件隱蔽得多。常見原因有兩個(gè)一是驅(qū)動和固件版本不匹配固件在等待一個(gè)驅(qū)動永遠(yuǎn)不會發(fā)的握手命令二是SDIO傳輸速率太高固件下載過程中數(shù)據(jù)出錯(cuò)一直重傳直到超時(shí)。碰到后一種把max-frequency降半檔再試一般立竿見影。還有個(gè)別平臺會遇到DMA問題導(dǎo)致固件下載卡死。SDIO主機(jī)控制器如果支持ADMA要把dma-coherent這一屬性加進(jìn)設(shè)備樹節(jié)點(diǎn)如果驅(qū)動和MMC控制器之間有cache一致性處理不到位大塊數(shù)據(jù)搬運(yùn)就會偶發(fā)錯(cuò)誤。排查方式是看錯(cuò)誤出現(xiàn)時(shí)DMA的error中斷有沒有被觸發(fā)打開CONFIG_MMC_DEBUG和CONFIG_DMA_API_DEBUG能輔助判斷。3.3 OOB中斷與in-band中斷的選擇SDIO WiFi的中斷機(jī)制有個(gè)很容易被忽略的坑默認(rèn)的SDIO中斷是通過總線上的DAT1信號以in-band方式上報(bào)的。這種方式的優(yōu)點(diǎn)是省一根GPIO缺點(diǎn)是只要系統(tǒng)進(jìn)入suspendSDIO時(shí)鐘被停掉in-band中斷就完全失效了——因?yàn)橹鳈C(jī)根本沒時(shí)鐘采樣DAT1上的中斷電平。所以做WiFi喚醒場景必須改用OOB中斷Out-Of-Band。簡單說就是模組的WiFi喚醒引腳單獨(dú)接到SoC的一個(gè)普通GPIO上不走SDIO數(shù)據(jù)線這樣即使SDIO總線時(shí)鐘停止GPIO中斷照樣能把SoC從休眠里拉起來。設(shè)備樹里如果是platform driver來承載這個(gè)WiFi節(jié)點(diǎn)可以大致這樣描述sdhci1 { status okay; ... wifi: wifi1 { compatible aic8800; reg 0x1; interrupt-parent gpio1; interrupts 15 IRQ_TYPE_LEVEL_LOW; wakeup-source; }; };但不同BSP對SDIO子節(jié)點(diǎn)的寫法差異很大有的平臺驅(qū)動是從MMC子系統(tǒng)中讀取of_node再解析interrupts有的則是把這顆WiFi注冊成一個(gè)mfd子設(shè)備。你在移植時(shí)不要照抄要看清楚驅(qū)動源碼里到底調(diào)用了哪個(gè)API去獲取中斷號。OOB中斷還有一個(gè)細(xì)節(jié)觸發(fā)方式是IRQ_TYPE_LEVEL_LOW還是IRQ_TYPE_EDGE_FALLING。我在WiFi模組上遇到過edge觸發(fā)丟中斷的情況因?yàn)閱拘岩_被拉低后如果系統(tǒng)響應(yīng)慢等中斷控制器enable的時(shí)候電平已經(jīng)恢復(fù)高電平跳變沿已經(jīng)過去了。用level觸發(fā)能避免這個(gè)問題代價(jià)是喚醒后必須由驅(qū)動主動清掉中斷狀態(tài)否則會一直誤觸發(fā)。3.4 DMA緩沖與內(nèi)存分配問題SDIO WiFi本質(zhì)上是個(gè)高吞吐設(shè)備驅(qū)動里會頻繁申請DMA緩沖區(qū)。AIC8800這類方案通常會在probe階段設(shè)置DMA掩碼比如dma_set_mask_and_coherent(pdev-dev, DMA_BIT_MASK(32))。如果你用的是64位平臺這里沒設(shè)好的話dma_alloc_coherent返回的地址可能落在非DMA可達(dá)區(qū)域?qū)е聰?shù)據(jù)傳輸錯(cuò)誤。另一個(gè)問題和MMC子系統(tǒng)的blksz有關(guān)。SDIO的block size如果配置不當(dāng)會嚴(yán)重影響吞吐。驅(qū)動里一般會有類似sdio_set_block_size(func, 512)的調(diào)用強(qiáng)行把block size固定在某個(gè)值上。不要因?yàn)檎{(diào)試方便把它改成1那會讓吞吐直接掉到慘不忍睹。4. 休眠喚醒排錯(cuò)從suspend到resume的完整鏈路4.1 suspend之前驅(qū)動應(yīng)該做什么休眠喚醒是整個(gè)WiFi驅(qū)動移植里最難驗(yàn)證也最容易翻車的地方因?yàn)樗鼱可娴絃inux電源管理框架、MMC子系統(tǒng)、設(shè)備樹屬性、GPIO中斷控制器、模組固件五個(gè)層面。任何一個(gè)環(huán)節(jié)斷掉表現(xiàn)就是“休眠正常喚醒沒反應(yīng)”。我們先理清楚鏈路系統(tǒng)執(zhí)行echo mem /sys/power/state之后設(shè)備模型會逐設(shè)備調(diào)用驅(qū)動的.suspend回調(diào)。如果AIC8800驅(qū)動的電源管理回調(diào)判斷device_may_wakeup(dev)為真就會通過私有命令讓模組進(jìn)入WoWWake on Wireless模式然后把OOB中斷注冊為喚醒中斷等待外部事件。同時(shí)MMC子系統(tǒng)在suspend時(shí)看到keep-power-in-suspend屬性會跳過切電操作只停掉SDIO時(shí)鐘。所以suspend階段檢查三個(gè)地方/sys/bus/platform/devices/.../wakeup/wakeup_enable是否為1dmesg里驅(qū)動是否打印了進(jìn)入WoW模式的日志SDIO總線時(shí)鐘在suspend后有沒有真正停掉用示波器量CLK腳。4.2 喚醒失敗繞過這些早發(fā)現(xiàn)我遇到過最典型的喚醒失敗是enable_irq_wake沒有被正確調(diào)用。癥狀是系統(tǒng)休眠后外部發(fā)一個(gè)網(wǎng)絡(luò)喚醒包模組確實(shí)把GPIO拉低了但SoC的中斷控制器沒有把這個(gè)GPIO當(dāng)成喚醒源系統(tǒng)就一直睡死。排查時(shí)可以打開MUSB或者GPIO相關(guān)調(diào)試先確認(rèn)中斷有沒有送到CPU# 看wakeup狀態(tài) cat /sys/kernel/debug/wakeup_sources # 看GPIO電平狀態(tài) cat /sys/kernel/debug/gpio # 看irq是否標(biāo)記為wake cat /proc/interrupts如果發(fā)現(xiàn)IRQ沒有被標(biāo)記為wake就要回驅(qū)動里看.suspend回調(diào)有沒有執(zhí)行enable_irq_wake(irq)或者設(shè)備樹里有沒有漏掉wakeup-source。wakeup-source和enable_irq_wake是從設(shè)備樹到內(nèi)核中斷控制器的一整條鏈少一個(gè)都不行。還有一個(gè)非常隱蔽的坑SDIO驅(qū)動在suspend時(shí)主動調(diào)用了sdio_disable_func或mmc_card_sleep但MMC核心隨后又把電源切了。如果設(shè)備樹里忘了keep-power-in-suspend休眠時(shí)SDIO電源被物理切掉那等喚醒以后再想讀模組寄存器就是空中樓閣什么都讀不到。這種問題表面看起來是喚醒失敗實(shí)際是“休眠時(shí)已經(jīng)死了”。4.3 一次實(shí)際排錯(cuò)復(fù)盤醒是醒了網(wǎng)卻沒了有次現(xiàn)場調(diào)試系統(tǒng)能從休眠喚醒串口能進(jìn)shell但WiFi接口完全消失ifconfig -a里連wlan0都沒有。查日志發(fā)現(xiàn)喚醒后驅(qū)動重新掃描SDIO總線枚舉到了一個(gè)全新的卡這說明喚醒時(shí)模組經(jīng)歷了復(fù)位或重上電MMC核心已經(jīng)在重新初始化設(shè)備。原因出在設(shè)備樹沒有keep-power-in-suspendMMC子系統(tǒng)在suspend時(shí)斷電了模組跟著掉電喚醒后再上電對驅(qū)動來說就是一顆“新卡”原來注冊好的wlan0、固件狀態(tài)全部丟失。加上keep-power-in-suspend之后休眠時(shí)只是停時(shí)鐘不斷電喚醒后SDIO設(shè)備還在原來的狀態(tài)wlan0保住了。所以這個(gè)屬性對于需要快速喚醒、保留連接狀態(tài)的場景幾乎是必須的。4.4 如何驗(yàn)證休眠喚醒鏈路是否完整完整的驗(yàn)證步驟我建議這么走在host和AP之間建好WiFi連接執(zhí)行echo mem /sys/power/state進(jìn)入suspend用萬用表或PMIC日志確認(rèn)模組供電沒有掉發(fā)送一個(gè)喚醒包比如ping或者專門的WoW Magic Packet系統(tǒng)喚醒后立刻dmesg看驅(qū)動的resume回調(diào)有沒有被調(diào)用檢查iw dev wlan0 link能否正??吹紸P連續(xù)進(jìn)出休眠喚醒50次以上確認(rèn)不會概率性失敗。重點(diǎn)是第7步。休眠喚醒的問題很多是概率性的一次兩次成功不代表穩(wěn)定。我在一個(gè)項(xiàng)目里就碰到過差不多30次以后才復(fù)現(xiàn)的喚醒失敗最后定位到是GPIO中斷和SDIO時(shí)鐘恢復(fù)的競態(tài)需要在resume回調(diào)里先恢復(fù)SDIO時(shí)鐘再enable_irq順序錯(cuò)了就有小概率丟中斷。5. 量產(chǎn)前必須壓測的穩(wěn)定性問題5.1 斷流與速率異常SDIO時(shí)鐘不是越高越好很多移植項(xiàng)目卡在“能連上但速度不對”。AIC8800DC至少是WiFi62.4G下如果跑出幾十Mbps懷疑驅(qū)動掛了一個(gè)不支持HT40的配置5G下如果跑不滿檢查SDIO時(shí)鐘頻率和模式。我自己的經(jīng)驗(yàn)是SDIO控制器和WiFi模組之間總線穩(wěn)定性比峰值頻率重要得多。SDR104模式看著帶寬高但一旦PCB走線沒那么講究高頻率下的信號回波損耗會讓傳輸頻繁失敗TCP吞吐反而不如降一檔用DDR50穩(wěn)定。所以量產(chǎn)板的調(diào)試建議先用50MHz跑一遍基準(zhǔn)吞吐再逐步調(diào)到100MHz、SDR104如果在高頻率下出現(xiàn)丟包、ping延遲抖動、dmesg里有大量CRC錯(cuò)誤果斷降頻。另外檢查驅(qū)動里的aggragate和AMSDU/AMPDU開關(guān)。WiFi6高吞吐靠的是幀聚合如果驅(qū)動把聚合關(guān)了哪怕SDIO跑得再快無線側(cè)也會被大量小包拖垮。5.2 功耗與發(fā)熱別讓W(xué)iFi變成一塊電老虎AIC8800DC在WiFi6模式下連接時(shí)的功耗比WiFi5時(shí)代的老方案低不少但這建立在正確進(jìn)入低功耗模式的基礎(chǔ)上。調(diào)試低功耗時(shí)我一般直接測量模組電源軌的電流空閑關(guān)聯(lián)狀態(tài)無數(shù)據(jù)流量下電流應(yīng)該降到幾mA到十幾mA級別休眠喚醒模式下應(yīng)該更低否則大概率是固件沒有正確進(jìn)入WoW或者驅(qū)動在idle時(shí)沒有關(guān)閉射頻前端如果發(fā)現(xiàn)WiFi關(guān)聯(lián)后電流居高不下檢查驅(qū)動有沒有啟用PSPower Save模式。Linux下可以用iw dev wlan0 set power_save on來打開。發(fā)熱問題往往和DMA錯(cuò)誤重傳相關(guān)。如果頻繁出現(xiàn)SDIO傳輸錯(cuò)誤驅(qū)動會反復(fù)重傳MCU一直滿負(fù)荷跑電流和溫度自然下不來。所以發(fā)現(xiàn)WiFi芯片異常發(fā)熱時(shí)先查dmesg有沒有CRC/超時(shí)報(bào)錯(cuò)不要只怪芯片本身。5.3 量產(chǎn)測試建議進(jìn)了產(chǎn)線不能只靠人工iw命令測。建議把以下內(nèi)容固化到產(chǎn)測腳本SDIO枚舉成功率如果100塊板里有幾塊枚舉失敗重點(diǎn)查貼片虛焊、復(fù)位電容、走線阻抗射頻指標(biāo)功率、靈敏度、EVM由產(chǎn)測儀器自動化測休眠喚醒穩(wěn)定性每塊板至少三次休眠喚醒出現(xiàn)一次失敗直接判NG吞吐抽測抽檢比例不用太高但要測2.4G和5G兩個(gè)頻段。其實(shí)這些條目看起來多但產(chǎn)線執(zhí)行層面就是腳本點(diǎn)擊和結(jié)果判斷的事。真正麻煩的反而是自己研發(fā)階段的這些坑產(chǎn)線基本不會遇到的問題。6. 最后說點(diǎn)大實(shí)話移植AIC8800DC這類SDIO WiFi6模組本身不算什么高精尖的活但它的排錯(cuò)鏈路長硬件上電、設(shè)備樹、MMC子系統(tǒng)、固件版本、中斷喚醒、DMA緩沖每個(gè)環(huán)節(jié)都埋著能讓你折騰兩天的雷。我個(gè)人的體會是大量時(shí)間其實(shí)是浪費(fèi)在“沒有懷疑到的那一行配置”上比如一個(gè)keep-power-in-suspend一晚上就沒了。給后來人幾條實(shí)在的建議每次只改一個(gè)變量改完立刻驗(yàn)證別一次動三處配置出了問題根本不知道是哪處引入的勤看dmesgSDIO和WiFi驅(qū)動打印的日志信息量很大不要只看錯(cuò)誤行正常枚舉成功的日志也要仔細(xì)讀固件和驅(qū)動務(wù)必同源版本混搭是你排查所有奇怪問題之前必須先排除的嫌疑硬件上的SDIO走線、電源紋波、復(fù)位時(shí)序軟件再牛也救不回來。AIC8800DC這波移植做完之后我對所有SDIO WiFi方案的敬畏心都上了一個(gè)臺階。希望這篇指南能讓你少走幾個(gè)我沒躲過的彎路。