Files
BFE Engineering 42fb386f60 docs: ASCII typography and style normalization across all repo text
Replace every em dash with real punctuation (rewrites, not hyphen swaps)
in docs, code comments, scripts, configs, and the port records; convert
en dashes, curly quotes, ellipsis glyphs, arrows, and section signs to
ASCII; drop machine-writing tell phrases from living docs. ADR titles
now use a colon. The M2 bring-up DTS model string carried an em dash
into the patch series and its record echoes; fixed at both, and the full
series re-verified to apply cleanly onto pristine 6.18.46. One comment
in freshness.h deliberately names the em dash glyph the UI renders as
the unknown mark; that is data, kept as prose naming it.

Verified: cargo tests (sim, config-lint, rs485-bridge), shellcheck,
both driver MC/DC harnesses, patches-apply.
2026-08-31 12:31:27 -06:00

18 KiB

AIC8800 wifi+BT port: M5 progress (2026-08-24)

Status: DONE, zImage + rv1106-warden.dtb build clean with the driver built in. Not flashed/booted (parent session verifies on hardware).

Build status

export PATH=".../sdk/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin:/usr/bin:/bin"
export ARCH=arm CROSS_COMPILE=arm-rockchip830-linux-uclibcgnueabihf-
make ARCH=arm CROSS_COMPILE=$CROSS_COMPILE zImage
make ARCH=arm CROSS_COMPILE=$CROSS_COMPILE rockchip/rv1106-warden.dtb

Clean rebuild (all aic8800 sources touched to force recompilation): 0 errors, 104 warnings, all benign vendor-code style (101 -Wmissing-prototypes on internal non-static helper functions that were never prototyped in headers, 3 -Wempty-body on an existing if (...);-with-no-body debug macro expansion), none are correctness issues and none were introduced by version-delta fixes. zImage is ready; rv1106-warden.dtb compiles with only the pre-existing, unrelated &rgb graph-endpoint warning (already known from M4 display work, not wifi-related). Confirmed via nm vmlinux.unstripped that the driver is actually linked in, not silently dropped: aicbsp_sdio_driver, aicwf_sdio_driver, rwnx_cfg80211_ops all present, and the three module_init()s appear as device_initcalls in the correct link order, __initcall__kmod_aic8800_fdrv__...rwnx_mod_init after bsp's init and __initcall__kmod_aic8800_btlpm__...aic_bluetooth_mod_init last.

What was copied/wired

Copied flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/{aic8800_bsp,aic8800_fdrv, aic8800_btlpm}/*.{c,h} into drivers/net/wireless/aic8800/ in the 6.18 tree, source-only (excluded .mod.c/.o/Module.symvers/etc build artifacts left over in the vendor tree from prior out-of-tree builds).

Dropped as dead code for this board (SDIO-only, no USB/PCIe, CONFIG_SDIO_BT=n): usb_host.{c,h}, rwnx_pci.{c,h}, aicwf_usb.c, btsdio.c, aic_btsdio.c.

One exception the plan flagged correctly: rwnx_mesh.{c,h} was initially dropped on the same "dead code" theory but had to be restored, rwnx_tx.c's NL80211_IFTYPE_MESH_POINT switch-case block is not preprocessor-gated, so rwnx_mesh.h's types (struct rwnx_mesh_path, struct rwnx_mesh_proxy) and prototypes are needed to compile even though this board never creates a mesh-type interface. Restored both files (1KB each) and added rwnx_mesh.o back to the fdrv Makefile object list. usb_host.c/rwnx_pci.c did NOT need restoring: no build error ever referenced them.

New in-tree Kbuild wiring (not copied from vendor, vendor Makefiles are out-of-tree KDIR= external-module style and don't apply directly):

  • drivers/net/wireless/aic8800/Kconfig, top-level AIC_WLAN_SUPPORT bool + AIC_FW_PATH string, sources the fdrv/btlpm sub-Kconfigs. Wired into drivers/net/wireless/Kconfig (new source line, alongside the existing vendor Kconfig list).
  • drivers/net/wireless/aic8800/Makefile, obj-y list preserving bsp -> fdrv -> btlpm link order (per PORT-PLAN.md section 4.5, since these are built-in =y now and initcall order follows link order). Wired into drivers/net/wireless/Makefile (obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/).
  • aic8800_fdrv/Kconfig, aic8800_btlpm/Kconfig, vendor's tristate symbols changed to default y (built-in, not modular; the 6.18 rootfs has no working module pipeline yet).
  • Three new in-tree Makefiles (aic8800_bsp/, aic8800_fdrv/, aic8800_btlpm/) translating the vendor's ccflags-$(CONFIG_X) += -DX pattern into fixed -D flags for the one build configuration this board actually uses (SDIO, Rockchip, no USB/PCI/mesh-in-practice, TCP-ACK filter, preallocated TXQ, RF test support, see each Makefile's ccflags for the full list, matching the vendor Makefile defaults). CONFIG_AIC_FW_PATH needs no -D: it's now a real Kconfig string symbol, so include/generated/autoconf.h already defines the CONFIG_AIC_FW_PATH C-string macro the driver expects (aicsdio.c:59, aic_bsp_driver.h:348).

API-delta fixes (file -> change)

Plan-anticipated mechanical renames (applied via scoped sed, all call sites)

  • from_timer() -> timer_container_of(), 7 sites: aicsdio.c, aicwf_sdio.c (x3), rwnx_main.c, rwnx_rx.c (x2).
  • del_timer_sync() -> timer_delete_sync(), 10 sites: aicsdio.c, aicwf_sdio.c (x5), rwnx_main.c (x2, one more than the plan's count, rwnx_main.c:6177 wasn't in the plan's list but grep found it), rwnx_rx.c (x2).
  • del_timer() -> timer_delete(), 9 sites: aicwf_tcp_ack.c (x4), rwnx_rx.c (x2), aic8800_btlpm/aic8800_btlpm.c (x3, dead, not in this build's object list, fixed anyway for tree hygiene), aic8800_btlpm/lpm.c (x3, same, lpm.c isn't compiled, CONFIG_SUPPORT_LPM=n).
  • netif_rx_ni() -> netif_rx(): 3 sites, all rwnx_rx.c.

Deltas beyond the plan's list (found by the compiler, fixed against 6.18 headers)

  • cfg80211_rx_spurious_frame() / cfg80211_rx_unexpected_4addr_frame() (rwnx_rx.c, 2 sites): gained a link_id param before gfp; passed -1 ("not applicable", per the header's own doc comment, this driver has no MLO).
  • cfg80211_ch_switch_notify() / cfg80211_ch_switch_started_notify() (rwnx_main.c, 2 sites): the vendor's own version-gated compat shim (rwnx_compat.h's HIGH_KERNEL_VERSION3/4 = 6.3.0) already anticipated an API change here but guessed a 6.3-era signature that's since changed again by 6.18 (notify dropped back to 3 args (dev, chandef, link_id); started_notify is 5 args (dev, chandef, link_id, count, quiet), no trailing reserved arg). Added a new #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0) tier ahead of the existing chain rather than edit the historical shim; link_id = 0 (mandatory for non-MLO per the header).
  • cfg80211_ops struct-initializer type mismatches (rwnx_main.c, 7 callbacks, all gained new params, all effectively "not applicable" for this single-radio, non-MLO, SDIO full-MAC driver, so the new params are accepted and ignored):
    • change_beacon: now takes struct cfg80211_ap_update * (wraps the old cfg80211_beacon_data as .beacon, plus FILS/S1G/unsol fields unused here); unwrapped with &update->beacon so rwnx_build_bcn() and its other 3 callers stay untouched.
    • set_monitor_channel: gained a struct net_device *dev param. Rather than thread an unused dev through the well-used internal 2-arg rwnx_cfg80211_set_monitor_channel() (called elsewhere with chandef = NULL to retrieve firmware-level channel state), added a thin rwnx_cfg80211_set_monitor_channel_ops() adapter and pointed the ops table at that instead.
    • set_wiphy_params: gained int radio_idx before changed.
    • set_tx_power: gained int radio_idx between wdev and type.
    • get_tx_power: gained int radio_idx, unsigned int link_id before the output pointer.
    • start_radar_detection: gained a trailing int link_id.
    • tdls_mgmt: gained int link_id right after peer.
  • cfg80211_cac_event() (rwnx_radar.c, 2 sites): gained a trailing unsigned int link_id; passed 0 (mandatory for non-MLO per doc comment).
  • wakeup_source_create()/_add()/_remove()/_destroy() (rwnx_wakelock.c): removed from the public API entirely (still exist internally in drivers/base/power/wakeup.c but are no longer EXPORT_SYMBOL'd); wakeup_source_register(dev, name) / wakeup_source_unregister(ws) is now the only supported entry point (confirmed: wakeup_source_register()'s own implementation is literally create() + conditional sysfs + add()). Rewrote rwnx_wakeup_init()/_deinit() to call wakeup_source_register(NULL, name) / wakeup_source_unregister(ws): dev=NULL registers an anonymous source not tied to a struct device, matching the old wakeup_source_create() behavior used here. (The file already had a correct modern rwnx_wakeup_register()/_unregister() pair for a different call path; this fix makes rwnx_wakeup_init() consistent with it.)
  • MODULE_IMPORT_NS(bare_token) -> MODULE_IMPORT_NS("string"): 3 sites (aic_bsp_driver.c, rwnx_platform.c, rwnx_main.c), all importing the same non-mainline VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver namespace token (an Android-GKI-kernel artifact, confirmed absent from our mainline fs/ tree, so this is now inert modinfo metadata, not a real namespace gate). MODULE_INFO()/MODULE_IMPORT_NS() now require a quoted string per current include/linux/module.h.
  • rwnx_platform.c: unconditional #include "rwnx_pci.h", the header was dropped with rwnx_pci.c (dead code, no PCIe on this board), but this one #include wasn't behind any guard. Guarded it behind AICWF_PCIE_SUPPORT (matching the guard its only two callers, rwnx_platform_{,un}register_drv(), already use at their call sites in rwnx_main.c) and guarded the two functions' rwnx_pci_{,un}register_drv() bodies the same way, returning 0/no-op for the SDIO-only build instead.
  • <linux/rfkill-wlan.h> (vendor-only, PORT-PLAN.md section 3.7): removed from 3 files (aicsdio.c, aicwf_sdio.c, rwnx_main.c). Traced every real rockchip_wifi_power()/_set_carddetect() call site first: all of them are either already #if 0'd out in the vendor source (aicwf_sdio.c) or gated behind CONFIG_PLATFORM_ROCKCHIP2 (a symbol this build never defines, only plain ROCKCHIP), so none needed stubbing individually; only the unconditional header #includes needed removing. The DT's mmc-pwrseq-simple node does the power/reset sequencing instead, as planned.
  • CONFIG_RFTEST added to aic8800_fdrv's ccflags: not itself a version delta, but needed: aic_priv_cmd.c's RF-test-mode enum (SET_TX, RDWR_EFUSE_*, ~50 constants) and struct typedefs (cmd_rf_settx_t etc.) are defined inline in the file under #ifdef CONFIG_RFTEST, and later code in the same file references them unconditionally. Omitting -DCONFIG_RFTEST (as an initial conservative default) produced ~90 "undeclared identifier" errors; the vendor Makefile's own default is CONFIG_RFTEST=y, so restoring it matches vendor intent, not a workaround.

Duplicate-symbol fixes (the biggest surprise, not in the plan)

The vendor aic8800_bsp and aic8800_fdrv were always built as two independent .ko modules, each with its own private symbol namespace. Built in-tree as =y, both link into one vmlinux, and it turns out aic8800_bsp carries a complete second, self-contained copy of large parts of aic8800_fdrv's machinery: its own SDIO byte/frame transport (aicwf_sdio_*, aicwf_bus_*, aicwf_frame_*, aicwf_tx_*, aicwf_rx_*, crc8_ponl_107), its own message/debug-command layer (rwnx_send_dbg_*_req, rwnx_cmd_mgr_{init,deinit}, rwnx_rx_handle_msg), and a few globals (chip_mcu_id, chip_sub_id, aic_fw_path, testmode), used for the bsp-side firmware bring-up phase before fdrv's own driver instance re-probes and takes over the SDIO function for real runtime operation. 49 symbols total, ld caught every one as "multiple definition" at the final vmlinux.o link (the per-subdirectory built-in.a build had already succeeded: this class of error only surfaces at the whole-image link, which is worth knowing for anyone repeating this kind of port).

Verified via aic_bsp_export.h (the real, narrow, intentional aicbsp_*-prefixed bsp->fdrv API surface) that none of the 49 are part of the actual cross-module contract, and via grep -rlw that fdrv has its own complete definition of every one (not an extern pointing at bsp's copy), confirming these are two truly independent implementations, not one legitimately shared. Fix: renamed all 49 symbols with an aicbsp_priv_ prefix, scoped strictly to aic8800_bsp/*.{c,h} (both definitions and bsp-internal call sites via whole-word sed); fdrv's copies are untouched. One of the 49, md5.c's MD5 functions, got a different (smaller-footprint) fix: aic8800_bsp/md5.c and aic8800_fdrv/md5.c are byte-identical files, so md5.o was simply dropped from aic8800_fdrv's object list instead of renamed, fdrv's calls resolve against bsp's copy at link time since bsp links first.

Config symbols set

CONFIG_AIC_WLAN_SUPPORT=y
CONFIG_AIC8800_WLAN_SUPPORT=y
CONFIG_AIC8800_BTLPM_SUPPORT=y
CONFIG_AIC_FW_PATH="/oem/usr/ko/aic8800dc_fw"
CONFIG_WIRELESS=y CONFIG_CFG80211=y CONFIG_WLAN=y      (already y pre-port)
CONFIG_MMC=y CONFIG_MMC_DW_ROCKCHIP=y CONFIG_RFKILL=y  (already y pre-port)
CONFIG_BT=y                 (was =m, flipped to =y, no module pipeline yet)
CONFIG_BT_HCIUART=y         (was =m, flipped to =y)
CONFIG_BT_HCIUART_H4=y      (already y)
CONFIG_CRYPTO_ARC4=y CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_CCM=y CONFIG_CRYPTO_AES=y
# CONFIG_MAC80211 is not set   (explicitly left off, pure cfg80211 full-MAC
                                 driver, confirmed no mac80211/ieee80211_hw
                                 symbol usage anywhere in aic8800_fdrv)

Ran olddefconfig after setting these; verified afterward that other ported drivers' symbols (CONFIG_CLK_RV1106, CONFIG_PINCTRL_ROCKCHIP, CONFIG_DRM_ROCKCHIP, CONFIG_MMC_DW_ROCKCHIP) are untouched.

Device tree

arch/arm/boot/dts/rockchip/rv1106-warden.dts:

  • New root-level sdio_pwrseq: sdio-pwrseq node (mmc-pwrseq-simple, reset-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>), transplanted verbatim from the vendor board DTS.
  • New &sdmmc override: max-frequency = <50000000>, bus-width = <4>, cap-sd-highspeed, cap-sdio-irq, keep-power-in-suspend, non-removable, rockchip,default-sample-phase = <90>, supports-sdio, mmc-pwrseq = <&sdio_pwrseq>, pinctrl sdmmc0_clk/_cmd/_bus4/_det, status = "okay".
  • &sdio (mmc@ff9a0000) left untouched: stays disabled, genuinely unused hardware on this board.

Note: the &sdmmc node itself (mmc@ffaa0000) in rv1106.dtsi and the sdmmc0_* pinctrl groups in rv1106-pinctrl.dtsi were already present in this tree from earlier M1-M3 work (not added by this task), this task only added the board-DTS enablement (status = "okay" + properties) and the new sdio_pwrseq node. Verified in the compiled .dtb (decompiled with dtc -I dtb -O dts) that both nodes carry the correct phandles/properties.

Hardening patches

Both hardware-verified patches from the plan are already present in the vendor SDK source we copied from (not merely trackable-but-unapplied), confirmed two ways: patch -p5 --dry-run on both reported "Reversed (or previously applied) patch detected" against the freshly-copied tree, and grep found their exact markers already in place:

  • 0001-aic8800dc-no-zero-timeout-spin-and-ratelimit.patch (major-app-additions/sdk-patches/wifi/patches/): printk_ratelimited and the max_t(u32, cmd_mgr->queue_sz, 1) clamp are both in rwnx_cmds.c as shipped. future-features-2/sdk-patches/wifi/patches/0002-aic8800dc-sdio-wakeup-sleep-not-spin.patch:
  • usleep_range(200, 400), the woke flag, and the "SDIO wakeup failed; chip may be wedged" message are all in aicwf_sdio.c as shipped.

No action needed beyond copying the source. Known housekeeping gap (pre-existing, not fixed by this task, flagged by the plan): patch 0002 is still only tracked under future-features-2/sdk-patches/wifi/patches/, not this branch's own sdk-patches/wifi/patches/, worth closing separately since the fix is live in the vendor tree either way.

Constraints honored

Only touched: the wifi driver tree (drivers/net/wireless/aic8800/), its Kconfig/Makefile wiring (drivers/net/wireless/{Kconfig,Makefile}), the board DTS wifi nodes (rv1106-warden.dts, additive only), and wifi/BT/crypto-related .config symbols. Did not touch any other driver, DT node, or unrelated config symbol: spot-checked after the port that CONFIG_CLK_RV1106, CONFIG_PINCTRL_ROCKCHIP, CONFIG_DRM_ROCKCHIP, CONFIG_MMC_DW_ROCKCHIP are all still =y, and the &rgb/VOP-related dtc warning is the same pre-existing one from M4 (not new). Never touched hardware: no kflash, no reboot, no /dev/ttyUSB2, no Pi.

What the parent should watch for on hardware

Per PORT-PLAN.md section 6's verify sequence:

  1. dmesg: dwmmc_rockchip ffaa0000.mmc: ... binding (mirrors the M3 eMMC pattern on ffa90000.mmc), then an SDIO card enumerating on it (vendor/device ID 0xc8a1/0xc08d), then aic8800_bsp's probe firing.
  2. Firmware path: AIC_FW_PATH defaults to /oem/usr/ko/aic8800dc_fw, a 5.10-era Buildroot /oem partition path. Confirm the 6.18 rootfs actually has firmware there (or update CONFIG_AIC_FW_PATH to wherever it landed), watch specifically for firmware-open failures in dmesg as the first failure mode, before assuming a driver/DT bug.
  3. wlan0 should appear in ip link once aic8800_fdrv attaches.
  4. iw phy should show one 2.4 GHz band, 14 channels (matches the known 5.10 baseline: a mismatch signals a cfg80211/wiphy port bug, not a chip issue).
  5. iw dev wlan0 scan and a real AP association exercise the wiphy-locking behavior (section 3.3 of the plan): this is the area with the least direct verification in this port (the driver's own ops callbacks need no new locking per the plan's analysis, since cfg80211 core now holds the wiphy mutex before calling in; the async-context notification calls from rwnx_msg_rx.c were flagged as the highest-residual-risk area and were NOT touched by this build-fix pass beyond the signature changes above, if scan/connect hang or lockdep splats appear, look there first).
  6. Confirm the two hardening patches are actually effective under load: no "cmd timed-out" console flood, no CPU-pinning busy-spin on a stressed/ wedged SDIO link (aicwf_bustx_thr should sleep, not spin).
  7. BT: aic8800_btlpm should attach; hciattach -s 1500000 /dev/ttyS1 any 1500000 flow nosleep should bring up an HCI device.
  8. Given the scale of the bsp/fdrv duplicate-symbol rename (49 symbols), if anything behaves subtly wrong in the bsp-side firmware bring-up phase specifically (vs. fdrv's runtime path), double-check the rename didn't miss a cross-file reference within aic8800_bsp/: it was done with whole-word sed scoped to that directory and re-verified by a clean rebuild, but it touched every .c/.h in that subtree.