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.
This commit is contained in:
@@ -1,50 +1,50 @@
|
||||
# AIC8800 WiFi+BT SDIO driver — 5.10 → 6.18 port plan
|
||||
# AIC8800 WiFi+BT SDIO driver: 5.10 -> 6.18 port plan
|
||||
|
||||
Target: the M5 milestone of `../PORT-STATUS.md` / `../../docs/bringup.md` — port
|
||||
Target: the M5 milestone of `../PORT-STATUS.md` / `../../docs/bringup.md`, port
|
||||
the AIC8800 SDIO WiFi+BT driver onto the self-built **Linux 6.18.46** kernel that
|
||||
already boots WardenOS on `warden-c8a3` (M0–M3 done; M4 display in progress). No
|
||||
plan44 code (per the 2026-08-23 decision in `bringup.md`) — this is a direct
|
||||
already boots WardenOS on `warden-c8a3` (M0-M3 done; M4 display in progress). No
|
||||
plan44 code (per the 2026-08-23 decision in `bringup.md`): this is a direct
|
||||
forward-port of our own vendor source, same method already proven for
|
||||
clk/pinctrl/mach/mmc.
|
||||
|
||||
## 0. Source recommendation
|
||||
|
||||
**Port from our own vendor SDK source**, not from any external fork:
|
||||
`flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/` (§1 below is the full map). This
|
||||
is not a default-to-what-we-have choice — it's the correct one on the evidence:
|
||||
`flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/` (section 1 below is the full map). This
|
||||
is not a default-to-what-we-have choice; it's the correct one on the evidence:
|
||||
|
||||
- **Nothing more upstream exists.** AICSemi has no public upstream driver repo
|
||||
with a stable, discoverable URL, and there is no aic8800 code in Linux
|
||||
`staging` or any LKML patch series (mainline/staging status: **absent** —
|
||||
`staging` or any LKML patch series (mainline/staging status: **absent**,
|
||||
confirmed by a dedicated web-research pass; no counter-evidence found).
|
||||
There is nothing more "canonical" to port from than the vendor source we
|
||||
already have.
|
||||
- **Our tree already carries two hardware-verified fixes newer forks don't
|
||||
have**: the `queue_sz`-zero console-flood clamp
|
||||
(`flare-edge/*/sdk-patches/wifi/patches/0001-aic8800dc-no-zero-timeout-spin-and-ratelimit.patch`)
|
||||
and the SDIO-wakeup busy-spin→sleep Tier-1 hardening (live in the vendor tree
|
||||
and the SDIO-wakeup busy-spin->sleep Tier-1 hardening (live in the vendor tree
|
||||
today per `luckfox-pico-86-panel/wifi-bluetooth-aic8800.md`, tracked as
|
||||
`future-features-2/sdk-patches/wifi/patches/0002-aic8800dc-sdio-wakeup-sleep-not-spin.patch`
|
||||
— **not yet copied into this branch's `sdk-patches/`; carry both forward into
|
||||
`future-features-2/sdk-patches/wifi/patches/0002-aic8800dc-sdio-wakeup-sleep-not-spin.patch`,
|
||||
**not yet copied into this branch's `sdk-patches/`; carry both forward into
|
||||
the ported tree, and file the housekeeping gap separately**). Starting from a
|
||||
third-party fork would mean re-discovering and re-fixing both bugs on
|
||||
hardware.
|
||||
- **The vendor source already anticipates part of the delta.** `rwnx_compat.h`
|
||||
has `#if LINUX_VERSION_CODE` shims up to `KERNEL_VERSION(5, 15, 60)` — e.g.
|
||||
has `#if LINUX_VERSION_CODE` shims up to `KERNEL_VERSION(5, 15, 60)`, e.g.
|
||||
`rwnx_main.c`'s `net_device_ops` already switches between `.ndo_do_ioctl` and
|
||||
`.ndo_siocdevprivate` at the 5.15 boundary (rwnx_main.c:1457–1474). That
|
||||
`.ndo_siocdevprivate` at the 5.15 boundary (rwnx_main.c:1457-1474). That
|
||||
removes one whole item from the delta checklist below at zero cost.
|
||||
- **A cleaner community fork exists but is not itself a base — it's a reference.**
|
||||
- **A cleaner community fork exists but is not itself a base: it's a reference.**
|
||||
`radxa-pkg/aic8800` (github.com/radxa-pkg/aic8800) is an actively maintained,
|
||||
GPL-3.0, DKMS-packaged build of the same AICSemi driver family, explicitly
|
||||
patched for kernel **6.12/6.13** on Rockchip SDIO boards (Rock 3C/5C), and is
|
||||
the only community effort found that has already absorbed the post-5.15
|
||||
cfg80211/netdev/timer churn this port needs. **Use it the same way the
|
||||
pinctrl port used the upstream RV1106 patch series — as a correctness
|
||||
pinctrl port used the upstream RV1106 patch series, as a correctness
|
||||
oracle to diff against**, not as code we vendor: it targets AIC8800D80 SDIO/USB/PCIe
|
||||
variants generically, not our AIC8800DC + our two local hardening patches,
|
||||
and an Armbian forum thread reports open regressions on it at the 6.12+
|
||||
boundary — so treat its fixes as a second opinion on the wiphy-lock and
|
||||
boundary, so treat its fixes as a second opinion on the wiphy-lock and
|
||||
timer-rename hunks, verify each independently.
|
||||
- **No mainline/staging path exists to lean on instead.** Confirmed by the
|
||||
research pass: no aic8800 in `drivers/net/wireless/`, `staging/`, or any
|
||||
@@ -72,7 +72,7 @@ aic8800dc/
|
||||
Makefile # obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) += aic8800_btlpm/
|
||||
# obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
|
||||
# obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800_bsp/
|
||||
# (link order = bsp, fdrv, btlpm — matches the insmod order below)
|
||||
# (link order = bsp, fdrv, btlpm, matches the insmod order below)
|
||||
aic8800_bsp/ # SDIO bus glue + firmware bootstrap ("bsp" = board support package)
|
||||
aic_bsp_main.c # module_init/exit; per-chip firmware filename tables (fw_u02,
|
||||
# fw_8800dc_u01, fw_8800dc_u02, ...); aicbsp_probe_semaphore
|
||||
@@ -80,7 +80,7 @@ aic8800dc/
|
||||
# wildcard match + internal vendor/device ID probe:
|
||||
# SDIO_VENDOR_ID_AIC8800DC=0xc8a1, SDIO_DEVICE_ID_AIC8800DC=0xc08d
|
||||
# (aicsdio.c:75,80); calls rockchip_wifi_power()/
|
||||
# rockchip_wifi_set_carddetect() (aicsdio.c:515-580) — see §3.7
|
||||
# rockchip_wifi_set_carddetect() (aicsdio.c:515-580), see section 3.7
|
||||
aic8800dc_compat.c/.h, aic8800d80_compat.c/.h # per-chip-variant glue
|
||||
aicwf_txq_prealloc.c, md5.c, aic_bsp_driver.c/.h, aicwf_firmware_array.c/.h
|
||||
aic8800_fdrv/ # the actual cfg80211 full-MAC driver ("fdrv" = fullmac driver)
|
||||
@@ -88,51 +88,51 @@ aic8800dc/
|
||||
# (5732), wiphy_register() (6035); struct net_device_ops
|
||||
# rwnx_netdev_ops (1457) / rwnx_netdev_monitor_ops (1477);
|
||||
# 3 rtnl_lock()/rtnl_unlock() pairs (5429,6063,6097)
|
||||
rwnx_msg_rx.c # firmware→driver event handling incl. cfg80211_connect_result()
|
||||
rwnx_msg_rx.c # firmware->driver event handling incl. cfg80211_connect_result()
|
||||
# (line 958) and cfg80211_roamed() (1006,1010)
|
||||
rwnx_cfgfile.c, rwnx_tx.c, rwnx_rx.c, rwnx_txq.c # datapath
|
||||
aicwf_sdio.c # the actual SDIO transport (`aicwf_sdio_driver`, line 1216) —
|
||||
aicwf_sdio.c # the actual SDIO transport (`aicwf_sdio_driver`, line 1216),
|
||||
# THIS is the file the task's "aicwf_sdio" driver name refers to;
|
||||
# it lives inside aic8800_fdrv/, not a separate directory. Also
|
||||
# calls rockchip_wifi_power()/set_carddetect() (1260-1331) and
|
||||
# contains the Tier-1 wakeup-sleep hardening (§0) around the
|
||||
# contains the Tier-1 wakeup-sleep hardening (section 0) around the
|
||||
# `aicwf_sdio_wakeup()` retry loop (~line 1363 in the older
|
||||
# line numbering cited by the wiki; grep for `usleep_range`).
|
||||
aicwf_tcp_ack.c, aicwf_rx_prealloc.c, aic_priv_cmd.c, aic_vendor.c
|
||||
rwnx_compat.h # vendor compat shim layer, #if LINUX_VERSION_CODE guards up to
|
||||
# 5.15.60 ONLY — everything past that (timer renames, wiphy
|
||||
# 5.15.60 ONLY: everything past that (timer renames, wiphy
|
||||
# locking, netif_rx_ni removal) is new territory, not covered.
|
||||
usb_host.c/.h, rwnx_pci.*, rwnx_mesh.* # dead code on this board (no USB/PCI variant used)
|
||||
aic8800_btlpm/ # Bluetooth low-power-mode / HCI wake companion module
|
||||
aic8800_btlpm.c, aic_bluetooth_main.c, lpm.c, rfkill.c # standard rfkill_register(), no
|
||||
# Rockchip-specific RFKILL_RK dependency (checked, none found)
|
||||
aic8800dc_fw/ # firmware blobs, see §5
|
||||
aic8800dc_fw/ # firmware blobs, see section 5
|
||||
```
|
||||
|
||||
**Modules actually `insmod`ed on the running 5.10 panel** (from
|
||||
`sdk/sysdrv/drv_ko/wifi/insmod_wifi.sh:109-124`, the `#aic8800` stanza gated on
|
||||
`/proc/device-tree/model` containing `"W"` or an SDIO uevent match):
|
||||
```
|
||||
cfg80211.ko → libarc4.ko → ctr.ko → ccm.ko → libaes.ko → aes_generic.ko
|
||||
→ aic8800_bsp.ko (sleep 0.2s) → aic8800_fdrv.ko (sleep 2s) → aic8800_btlpm.ko (sleep 0.1s)
|
||||
cfg80211.ko -> libarc4.ko -> ctr.ko -> ccm.ko -> libaes.ko -> aes_generic.ko
|
||||
-> aic8800_bsp.ko (sleep 0.2s) -> aic8800_fdrv.ko (sleep 2s) -> aic8800_btlpm.ko (sleep 0.1s)
|
||||
```
|
||||
`rkwifi_server` is deliberately never started (WardenOS owns `wlan0` directly —
|
||||
`rkwifi_server` is deliberately never started (WardenOS owns `wlan0` directly,
|
||||
see `insmod_wifi.sh:126-137` and `wifi-bluetooth-aic8800.md`); nothing to
|
||||
replicate there. The crypto modules (arc4/ctr/ccm/aes) are dependencies of the
|
||||
driver's internal key-handling, not aic8800-specific — confirm they're already
|
||||
driver's internal key-handling, not aic8800-specific, confirm they're already
|
||||
`=y`/reachable in the 6.18 config (crypto is currently listed as "[ ] batch2" in
|
||||
`../DRIVER-PARITY.md`; flip alongside this work).
|
||||
|
||||
**DT node — correction to the task's framing.** The task description assumed
|
||||
**DT node: correction to the task's framing.** The task description assumed
|
||||
`sdio: mmc@ff9a0000`. **That is wrong for this board.** The AIC8800 is wired to
|
||||
**`sdmmc: mmc@ffaa0000`** (mmc1), not `sdio: mmc@ff9a0000` (mmc2) — confirmed
|
||||
**`sdmmc: mmc@ffaa0000`** (mmc1), not `sdio: mmc@ff9a0000` (mmc2), confirmed
|
||||
directly in `rv1106g-luckfox-pico-86panel.dts:83-97` (comment literally reads
|
||||
`/**********SDIO-WIFI**********/` over the `&sdmmc` node) and independently in
|
||||
`luckfox-pico-86-panel/wifi-bluetooth-aic8800.md:11`/`hardware-86-panel.md:69`.
|
||||
`&sdio` (mmc@ff9a0000) stays `status = "disabled"` and is unused on this board.
|
||||
There is **no separate DT child node** for the aic8800 chip itself — it's
|
||||
There is **no separate DT child node** for the aic8800 chip itself: it's
|
||||
discovered purely by SDIO bus-scan + vendor/device ID match inside the driver
|
||||
(`aicsdio.c`, no `of_match_table` anywhere in the tree — checked, none found);
|
||||
(`aicsdio.c`, no `of_match_table` anywhere in the tree, checked, none found);
|
||||
the only DT surface is the MMC controller node plus the power-sequencing node:
|
||||
```dts
|
||||
sdio_pwrseq: sdio-pwrseq { /* rv1106g-luckfox-pico-86panel.dts:20-23 */
|
||||
@@ -156,50 +156,50 @@ sdio_pwrseq: sdio-pwrseq { /* rv1106g-luckfox-pico-86panel.
|
||||
```
|
||||
The `sdmmc0_{clk,cmd,bus4,det}` pin groups are defined in
|
||||
`sdk/sysdrv/source/kernel/arch/arm/boot/dts/rv1106-pinctrl.dtsi:700-731` (a
|
||||
separate include from `rv1106.dtsi`) — port that block, it isn't in the DT
|
||||
files the M1–M3 work already ported.
|
||||
separate include from `rv1106.dtsi`): port that block, it isn't in the DT
|
||||
files the M1-M3 work already ported.
|
||||
|
||||
## 2. Open-source landscape (web research)
|
||||
|
||||
- **AICSemi upstream**: no discoverable, stable public GitHub org/repo carrying
|
||||
aic8800_bsp/fdrv/btlpm as canonical upstream — vendor releases exist only
|
||||
aic8800_bsp/fdrv/btlpm as canonical upstream, vendor releases exist only
|
||||
as SoC-vendor SDK drops (Rockchip's, in our case). Nothing more upstream to
|
||||
point at than what we have.
|
||||
- **Mainline/staging**: **absent.** No aic8800 anywhere in `drivers/net/wireless/`,
|
||||
`drivers/staging/`, or any LKML/patchwork series as of this research pass.
|
||||
- **Cleanest newer-kernel fork found**: `radxa-pkg/aic8800`
|
||||
(github.com/radxa-pkg/aic8800) — actively maintained, GPL-3.0, DKMS-packaged,
|
||||
(github.com/radxa-pkg/aic8800), actively maintained, GPL-3.0, DKMS-packaged,
|
||||
patched for kernel **6.12/6.13** on Rockchip SDIO boards (Radxa Rock 3C/5C),
|
||||
covering SDIO/USB/PCIe AIC8800D80 variants. Firmware ships as a companion
|
||||
`aic8800-firmware` package into `/lib/firmware/aic8800_fw/`. Treat as a
|
||||
**reference/oracle for the API-delta hunks** (§3), not a vendoring source —
|
||||
see §0 for why. An Armbian forum thread ("AIC8800 wifi sdio module not
|
||||
**reference/oracle for the API-delta hunks** (section 3), not a vendoring source,
|
||||
see section 0 for why. An Armbian forum thread ("AIC8800 wifi sdio module not
|
||||
working with kernel 6.12+") reports it has its own open regressions at that
|
||||
boundary, so cross-check rather than trust each hunk blindly.
|
||||
- **Other community efforts** (Armbian, LuckFox's own OpenWrt branch, generic
|
||||
BananaPi/OpenWrt feeds): no aic8800 kmod bundled by default even where the DT
|
||||
wiring exists — `luckfox-pico-86-panel/alternative-bsps.md:20` documents this
|
||||
wiring exists, `luckfox-pico-86-panel/alternative-bsps.md:20` documents this
|
||||
exact gap for LuckFox's own OpenWrt target (`cortexa7.mk` ships `kmod-rknpu-rockchip`
|
||||
only, no `kmod-aic8800`). Confirms there is no ready-made newer-kernel package
|
||||
to pull instead of porting.
|
||||
- **plan44's OpenWrt RV1106 fork** (`flare-edge/research/plan44-openwrt/`,
|
||||
Linux 6.6, 152 RV1106 patches): checked directly — **contains no aic8800
|
||||
Linux 6.6, 152 RV1106 patches): checked directly, **contains no aic8800
|
||||
code at all** (`find ... -ipath '*aic8800*'` empty). Confirms
|
||||
`bringup.md`'s "AIC8800 wifi (plan44 has none; ours)" and the "no plan44
|
||||
code" decision doesn't cost us anything here — there's nothing to take.
|
||||
code" decision doesn't cost us anything here: there's nothing to take.
|
||||
|
||||
## 3. 5.10 → 6.18 API-delta checklist
|
||||
## 3. 5.10 -> 6.18 API-delta checklist
|
||||
|
||||
Grounded in two passes: (a) direct kernel.org/bootlin/LWN research on 5.10→6.18
|
||||
Grounded in two passes: (a) direct kernel.org/bootlin/LWN research on 5.10->6.18
|
||||
API history, (b) `grep` evidence from the actual vendor source (file:line cited
|
||||
below) so this is a checklist against *our* code, not a generic survey.
|
||||
|
||||
### 3.1 Timers — confirmed hard breaks, exact call sites found
|
||||
`del_timer_sync`/`del_timer` → **`timer_delete_sync`/`timer_delete`**: renamed
|
||||
### 3.1 Timers: confirmed hard breaks, exact call sites found
|
||||
`del_timer_sync`/`del_timer` -> **`timer_delete_sync`/`timer_delete`**: renamed
|
||||
in `9b13df3fb64e` (landed v6.2-rc1) as a **compat-wrapped** rename; **the
|
||||
compat wrapper was removed in v6.15-rc1**, so by 6.18 the old names **do not
|
||||
exist**. `from_timer()` → **`timer_container_of()`**: a real mainline rename
|
||||
(~6.14–6.15 treewide timer-API cleanup; exact tag unconfirmed, verify against
|
||||
exist**. `from_timer()` -> **`timer_container_of()`**: a real mainline rename
|
||||
(~6.14-6.15 treewide timer-API cleanup; exact tag unconfirmed, verify against
|
||||
the actual 6.18.46 headers already unpacked at
|
||||
`flare-edge/research/linux-6.18.46/include/linux/timer.h`). Every call site in
|
||||
the driver, found by direct grep (not estimated):
|
||||
@@ -209,11 +209,11 @@ the driver, found by direct grep (not estimated):
|
||||
| `from_timer()` | `aic8800_bsp/aicsdio.c:1442`; `aic8800_fdrv/aicwf_sdio.c:279,317,2933`; `aic8800_fdrv/rwnx_main.c:1724`; `aic8800_fdrv/rwnx_rx.c:1751,2027` |
|
||||
| `del_timer_sync()` | `aic8800_bsp/aicsdio.c:1677`; `aic8800_fdrv/aicwf_sdio.c:1048,1054,1297,1303,3152`; `aic8800_fdrv/rwnx_main.c:2181`; `aic8800_fdrv/rwnx_rx.c:1501,1526` |
|
||||
| `del_timer()` (non-sync) | `aic8800_fdrv/aicwf_tcp_ack.c:108,367,401,462`; `aic8800_fdrv/rwnx_rx.c:1921,2607`; `aic8800_btlpm/aic8800_btlpm.c:580,603,951`; `aic8800_btlpm/lpm.c:558,581,935` |
|
||||
| `setup_timer()` (pre-4.14 dead branch) | `aic8800_fdrv/aicwf_tcp_ack.c:84` — already `#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)` guarded against a live `timer_setup()` branch; **delete the dead `#if` branch**, don't port it |
|
||||
| `setup_timer()` (pre-4.14 dead branch) | `aic8800_fdrv/aicwf_tcp_ack.c:84`: already `#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)` guarded against a live `timer_setup()` branch; **delete the dead `#if` branch**, don't port it |
|
||||
| `timer_setup()` calls (unaffected, just listed for completeness) | `aicsdio.c:2059`; `aicwf_sdio.c:3564,3589,3590`; `rwnx_main.c:1841,6118`; `rwnx_rx.c:1433,2510`; `aicwf_tcp_ack.c:87`; both btlpm files:1104/1054 |
|
||||
|
||||
Mechanical fix: sed-rename `from_timer`→`timer_container_of`, `del_timer_sync`→
|
||||
`timer_delete_sync`, `del_timer`→`timer_delete` across the ~20 call sites above.
|
||||
Mechanical fix: sed-rename `from_timer`->`timer_container_of`, `del_timer_sync`->
|
||||
`timer_delete_sync`, `del_timer`->`timer_delete` across the ~20 call sites above.
|
||||
`timer_setup()` itself is unchanged.
|
||||
|
||||
### 3.2 netdev
|
||||
@@ -221,25 +221,25 @@ Mechanical fix: sed-rename `from_timer`→`timer_container_of`, `del_timer_sync`
|
||||
around 5.14/5.15)**: **already handled** by the vendor. `rwnx_main.c:1457-1474`
|
||||
already has `#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)` /
|
||||
`#else .ndo_siocdevprivate = rwnx_do_ioctl,` for both `rwnx_netdev_ops` and
|
||||
`rwnx_netdev_monitor_ops`. Zero work needed — the guard picks the 6.18-correct
|
||||
`rwnx_netdev_monitor_ops`. Zero work needed: the guard picks the 6.18-correct
|
||||
member automatically. **Verify only** that `rwnx_do_ioctl`'s body (line 1368)
|
||||
still compiles against the `ndo_siocdevprivate` signature
|
||||
(`int (*)(struct net_device *, struct ifreq *, void __user *, int)` vs the
|
||||
old ioctl signature) — check on the actual 6.18.46 headers.
|
||||
old ioctl signature), check on the actual 6.18.46 headers.
|
||||
- **`netif_rx_ni()` removed (5.18, merged into plain `netif_rx()`, safe from any
|
||||
context)**: three call sites, **not** version-guarded: `rwnx_rx.c:404,598,1651`.
|
||||
Mechanical fix: `netif_rx_ni(rx_skb)` → `netif_rx(rx_skb)`.
|
||||
Mechanical fix: `netif_rx_ni(rx_skb)` -> `netif_rx(rx_skb)`.
|
||||
- **`netif_napi_add()` weight arg dropped (~6.1)**: **not used** anywhere in
|
||||
this driver (checked, no `netif_napi_add`/NAPI in the tree — the driver does
|
||||
this driver (checked, no `netif_napi_add`/NAPI in the tree, the driver does
|
||||
its own kthread-based RX processing, not NAPI polling). No action.
|
||||
|
||||
### 3.3 cfg80211 — the hard, non-mechanical part
|
||||
### 3.3 cfg80211: the hard, non-mechanical part
|
||||
**Verified directly against `flare-edge/research/linux-6.18.46/include/net/cfg80211.h`**
|
||||
(the actual target tree, not a guess from release notes):
|
||||
- **`cfg80211_connect_result()`**: **confirmed unchanged and safe.** In 6.18.46
|
||||
it's a `static inline` that just forwards to `cfg80211_connect_bss()`
|
||||
(`cfg80211.h:8654-8661`), with the exact same 8-argument signature the driver
|
||||
already calls at `rwnx_msg_rx.c:958`. `cfg80211_roamed()` — also **confirmed
|
||||
already calls at `rwnx_msg_rx.c:958`. `cfg80211_roamed()`, also **confirmed
|
||||
unchanged**: 6.18.46 signature is
|
||||
`cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, gfp_t gfp)`
|
||||
(`cfg80211.h:8748`), matching the driver's call at `rwnx_msg_rx.c:1006,1010`
|
||||
@@ -248,98 +248,98 @@ Mechanical fix: sed-rename `from_timer`→`timer_container_of`, `del_timer_sync`
|
||||
`cfg80211_connect_bss()` directly is optional cleanup, not a requirement.
|
||||
- **`wiphy_new()`/`wiphy_new_nm()`**: **confirmed unchanged.**
|
||||
`wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)`
|
||||
(`cfg80211.h:6250-6253`, inline wrapper over `wiphy_new_nm(ops, sizeof_priv, NULL)`)
|
||||
— matches `rwnx_main.c:5732`'s `wiphy_new(&rwnx_cfg80211_ops, sizeof(struct rwnx_hw))`
|
||||
(`cfg80211.h:6250-6253`, inline wrapper over `wiphy_new_nm(ops, sizeof_priv, NULL)`):
|
||||
matches `rwnx_main.c:5732`'s `wiphy_new(&rwnx_cfg80211_ops, sizeof(struct rwnx_hw))`
|
||||
exactly. No signature-driven work needed.
|
||||
- **Wiphy locking overhaul — real, confirmed present, and now precisely scoped
|
||||
- **Wiphy locking overhaul, real, confirmed present, and now precisely scoped
|
||||
(not a guess).** `cfg80211.h` (~6266, 6325-6362) confirms `wiphy_lock()`/
|
||||
`wiphy_unlock()`/`lockdep_assert_wiphy()` and a `struct wiphy_work` deferred-work
|
||||
mechanism all exist in 6.18.46, and — the load-bearing sentence, directly
|
||||
from the `wiphy_lock()` doc comment — **"When cfg80211 ops are called, the
|
||||
mechanism all exist in 6.18.46, and (the decisive sentence, directly
|
||||
from the `wiphy_lock()` doc comment) **"When cfg80211 ops are called, the
|
||||
wiphy is already locked."** That means:
|
||||
- The driver's `cfg80211_ops` callbacks themselves (`rwnx_cfg80211_scan`,
|
||||
`_connect`, `_disconnect`, `_add_key`, `_mgmt_tx`, etc., `rwnx_main.c:5365-5382`)
|
||||
need **no new locking** — cfg80211 core now takes the wiphy mutex before
|
||||
need **no new locking**: cfg80211 core now takes the wiphy mutex before
|
||||
calling into any of them, where 5.10-era cfg80211 relied on the caller
|
||||
holding RTNL instead.
|
||||
- The real risk is the **other direction**: this driver calls
|
||||
`cfg80211_scan_done()` / `cfg80211_connect_result()` / `cfg80211_roamed()`
|
||||
from **firmware-event handling, not from inside an ops callback** —
|
||||
from **firmware-event handling, not from inside an ops callback**,
|
||||
`rwnx_msg_rx.c` (async, driven by SDIO RX) and `rwnx_main.c:1212,2082,2168`
|
||||
(also async paths, not the ops entry points). Multiple `cfg80211.h` doc
|
||||
comments for adjacent notification APIs state "the caller must hold ...
|
||||
wiphy mutex" (e.g. `cfg80211.h:9428`: "Caller must hold wiphy mutex,
|
||||
therefore must only be called from sleepable context") — the pattern that
|
||||
therefore must only be called from sleepable context"), the pattern that
|
||||
replaced the old "hold RTNL" requirement. **Concretely: every
|
||||
`cfg80211_*` notification call reached from `rwnx_msg_rx.c` /
|
||||
the async paths in `rwnx_main.c` needs `wiphy_lock(wiphy)` /
|
||||
`wiphy_unlock(wiphy)` wrapped around it that wasn't there before** (5.10
|
||||
only needed `rtnl_lock()`, which this driver's 3 existing
|
||||
`rtnl_lock()`/`rtnl_unlock()` sites at `rwnx_main.c:5429/5433,
|
||||
6063/6075, 6097/6102` already show it knows how to take defensively — the
|
||||
6063/6075, 6097/6102` already show it knows how to take defensively: the
|
||||
fix is adding the wiphy-mutex equivalent at the async notification sites,
|
||||
not at those 3 sites, which are netdev-registration paths and likely stay
|
||||
RTNL-only).
|
||||
- This is still the single highest-effort item in the port — not because the
|
||||
- This is still the single highest-effort item in the port, not because the
|
||||
contract is unknown (it's now confirmed above), but because applying it
|
||||
correctly means auditing every async→cfg80211 call site in `rwnx_msg_rx.c`
|
||||
correctly means auditing every async->cfg80211 call site in `rwnx_msg_rx.c`
|
||||
and the async branches of `rwnx_main.c` (1212, 2082, 2168, 2445-2645) one
|
||||
by one, and because a wrong lock order (wiphy mutex vs. RTNL vs. this
|
||||
driver's own internal locks/semaphores) produces lockdep splats or
|
||||
deadlocks that only show up under real traffic, not at compile time. Cross-
|
||||
check each hunk against how `radxa-pkg/aic8800` (§0) handled the same
|
||||
transition on its 6.12/6.13 port — it hit this exact wall first.
|
||||
check each hunk against how `radxa-pkg/aic8800` (section 0) handled the same
|
||||
transition on its 6.12/6.13 port: it hit this exact wall first.
|
||||
|
||||
### 3.4 SDIO/MMC
|
||||
No breaking changes found in `sdio_driver`, `sdio_claim_host`/`release_host`,
|
||||
`sdio_readb`/`writesb`, `sdio_set_block_size` between 5.10 and 6.18 (low
|
||||
research depth on this axis — treat as low-risk, smoke-test rather than
|
||||
research depth on this axis, treat as low-risk, smoke-test rather than
|
||||
line-audit). The mainline `dw_mmc`/`dw_mmc-rockchip` host driver is already
|
||||
proven on 6.18 for eMMC (`../DRIVER-PARITY.md`: `dw_mmc (eMMC) | mainline | [x] M3`)
|
||||
and `CONFIG_MMC_DW_ROCKCHIP=y` is already in the live `.config` — the SDIO
|
||||
and `CONFIG_MMC_DW_ROCKCHIP=y` is already in the live `.config`, the SDIO
|
||||
*controller* side of this port is de-risked; only the AIC8800 *card driver*
|
||||
above the `sdmmc` bus is new work.
|
||||
|
||||
### 3.5 proc_ops
|
||||
`file_operations`→`proc_ops` for procfs landed in **5.6** — already true at the
|
||||
`file_operations`->`proc_ops` for procfs landed in **5.6**: already true at the
|
||||
5.10 baseline this driver was written against, and no further proc_ops changes
|
||||
were found 5.10→6.18. The three files using `proc_ops`/`proc_create`
|
||||
were found 5.10->6.18. The three files using `proc_ops`/`proc_create`
|
||||
(`aicwf_sdio.c`, `aic8800_btlpm.c`, `lpm.c`) should need no change here.
|
||||
|
||||
### 3.6 DMA
|
||||
No breaking coherent/streaming DMA API changes found 5.10→6.18 relevant to this
|
||||
No breaking coherent/streaming DMA API changes found 5.10->6.18 relevant to this
|
||||
driver; SDIO drivers ride MMC-core DMA rather than calling
|
||||
`dma_alloc_coherent`/`dma_map_single` directly for the card-side data path.
|
||||
Low risk, not independently line-audited — flag if the build surfaces anything.
|
||||
Low risk, not independently line-audited: flag if the build surfaces anything.
|
||||
|
||||
### 3.7 Vendor/Rockchip-only helpers — real mainline gap, not a version delta
|
||||
### 3.7 Vendor/Rockchip-only helpers: real mainline gap, not a version delta
|
||||
`rockchip_wifi_power()` / `rockchip_wifi_set_carddetect()` (declared in
|
||||
`include/linux/rfkill-wlan.h`, implemented in `net/rfkill/rfkill-wlan.c` in the
|
||||
**vendor 5.10 tree only** — this is a Rockchip-BSP-vendor subsystem, not
|
||||
**vendor 5.10 tree only**: this is a Rockchip-BSP-vendor subsystem, not
|
||||
mainline Linux, and does not exist in `flare-edge/research/linux-6.18.46/`).
|
||||
Call sites: `aic8800_bsp/aicsdio.c:515,517,556,580` and
|
||||
`aic8800_fdrv/aicwf_sdio.c:1260,1262,1329,1331` (all under
|
||||
`#ifdef CONFIG_PLATFORM_ROCKCHIP`, which is true for this board). **This is not
|
||||
a rename — there is nothing to rename to.** Recommended fix: **stub these
|
||||
a rename: there is nothing to rename to.** Recommended fix: **stub these
|
||||
calls out entirely** rather than port `rfkill-wlan.c`. The DT already declares
|
||||
a standard mainline `mmc-pwrseq-simple` (`sdio_pwrseq`, §1) bound via
|
||||
a standard mainline `mmc-pwrseq-simple` (`sdio_pwrseq`, section 1) bound via
|
||||
`mmc-pwrseq = <&sdio_pwrseq>`, which the mainline MMC core already drives at
|
||||
bus-scan/power-up time through `drivers/mmc/core/pwrseq_simple.c` — a real
|
||||
bus-scan/power-up time through `drivers/mmc/core/pwrseq_simple.c`, a real
|
||||
mainline mechanism doing the same job (GPIO power/reset sequencing) these
|
||||
vendor calls were a pre-DT-pwrseq-era stand-in for. `rockchip_wifi_set_carddetect()`
|
||||
is likewise redundant for a `non-removable` MMC device, which mainline already
|
||||
auto-rescans. Treat every call site as `#if 0`/deleted, not ported.
|
||||
`get_cpu_version`/`rockchip_soc_id`-style helpers: **not called anywhere** in
|
||||
this driver (checked, no hits) — the task's assumption that this driver calls
|
||||
this driver (checked, no hits), the task's assumption that this driver calls
|
||||
such a helper does not hold; no action needed. `module_param`, `kthread_run`/
|
||||
`kthread_should_stop`: stable, unaffected — used extensively (RX/TX kthreads in
|
||||
`kthread_should_stop`: stable, unaffected, used extensively (RX/TX kthreads in
|
||||
`aicwf_sdio.c`), no changes needed.
|
||||
|
||||
### 3.8 Firmware loading
|
||||
`request_firmware`/`request_firmware_nowait`/`release_firmware`: stable
|
||||
5.10→6.18, no signature changes found. Note this driver's actual firmware load
|
||||
5.10->6.18, no signature changes found. Note this driver's actual firmware load
|
||||
path is `AIC_FW_PATH`-relative direct file read via its own loader
|
||||
(`aic_load_fw`/`CONFIG_USE_FW_REQUEST` is `?= n` in the Makefile — the vendor
|
||||
(`aic_load_fw`/`CONFIG_USE_FW_REQUEST` is `?= n` in the Makefile, the vendor
|
||||
driver does **not** use the standard `request_firmware()` API by default, it
|
||||
reads firmware files from a configurable path itself). Confirm this stays true
|
||||
after the port; it's a deliberate vendor choice, not a version-driven gap.
|
||||
@@ -347,31 +347,31 @@ after the port; it's a deliberate vendor choice, not a version-driven gap.
|
||||
## 4. File / config / DT port plan
|
||||
|
||||
### 4.1 Files to bring into the 6.18 tree
|
||||
Copy `aic8800dc/{aic8800_bsp,aic8800_fdrv,aic8800_btlpm}/*.{c,h}` (source only —
|
||||
Copy `aic8800dc/{aic8800_bsp,aic8800_fdrv,aic8800_btlpm}/*.{c,h}` (source only:
|
||||
exclude every generated `.o`/`.ko`/`.mod.*`/`.cmd`/`Module.symvers`/
|
||||
`modules.order` artifact already sitting in the vendor tree from prior
|
||||
out-of-tree builds) into the 6.18 tree at:
|
||||
```
|
||||
flare-edge/research/linux-6.18.46/drivers/net/wireless/aic8800/
|
||||
Kconfig # new: top-level "source" wrapper, see 4.2
|
||||
Makefile # obj-y for the 3 subdirs, preserving bsp→fdrv→btlpm link order
|
||||
Makefile # obj-y for the 3 subdirs, preserving bsp->fdrv->btlpm link order
|
||||
aic8800_bsp/ (from aic8800dc/aic8800_bsp/)
|
||||
aic8800_fdrv/ (from aic8800dc/aic8800_fdrv/, minus usb_host.c/rwnx_pci.*/rwnx_mesh.* — dead
|
||||
aic8800_fdrv/ (from aic8800dc/aic8800_fdrv/, minus usb_host.c/rwnx_pci.*/rwnx_mesh.*: dead
|
||||
code on this board's SDIO-only, non-mesh config; keep out unless a build
|
||||
error proves them referenced elsewhere)
|
||||
aic8800_btlpm/ (from aic8800dc/aic8800_btlpm/)
|
||||
```
|
||||
This is exactly the path the vendor's own `Kconfig` already assumes
|
||||
(`source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig"`, §1) — no path
|
||||
rewriting needed inside the sub-Kconfigs. Firmware blobs (§5) go to
|
||||
(`source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig"`, section 1), no path
|
||||
rewriting needed inside the sub-Kconfigs. Firmware blobs (section 5) go to
|
||||
`aic8800dc_fw/` under the rootfs firmware path, not into the kernel tree.
|
||||
|
||||
Apply, in this order, on top of the copied source: the `0001` queue_sz clamp
|
||||
patch, and the Tier-1 SDIO-wakeup-sleep patch (currently only tracked under
|
||||
`flare-edge/future-features-2/sdk-patches/wifi/patches/0002-aic8800dc-sdio-wakeup-sleep-not-spin.patch`
|
||||
— pull it from there; it is *not* in this branch's own `sdk-patches/wifi/`, a
|
||||
`flare-edge/future-features-2/sdk-patches/wifi/patches/0002-aic8800dc-sdio-wakeup-sleep-not-spin.patch`:
|
||||
pull it from there; it is *not* in this branch's own `sdk-patches/wifi/`, a
|
||||
separate housekeeping gap worth closing regardless of this port). Then apply
|
||||
the API-delta fixes from §3.
|
||||
the API-delta fixes from section 3.
|
||||
|
||||
### 4.2 Kconfig wiring
|
||||
Add one line to `flare-edge/research/linux-6.18.46/drivers/net/wireless/Kconfig`
|
||||
@@ -380,13 +380,13 @@ list, `Kconfig:22-38`):
|
||||
```
|
||||
source "drivers/net/wireless/aic8800/Kconfig"
|
||||
```
|
||||
New `drivers/net/wireless/aic8800/Kconfig` — carry the vendor's `aic8800dc/Kconfig`
|
||||
New `drivers/net/wireless/aic8800/Kconfig`, carry the vendor's `aic8800dc/Kconfig`
|
||||
content forward nearly verbatim (it already has the right shape: an
|
||||
`AIC_WLAN_SUPPORT` bool gate, an `AIC_FW_PATH` string default, and `source`
|
||||
lines for the fdrv/btlpm sub-Kconfigs) but change the two `tristate` symbols in
|
||||
`aic8800_fdrv/Kconfig` (`AIC8800_WLAN_SUPPORT`) and `aic8800_btlpm/Kconfig`
|
||||
(`AIC8800_BTLPM_SUPPORT`) to **default `y`**, and set `AIC_WLAN_SUPPORT`
|
||||
default `y` — per the task's requirement, everything built in, not modular,
|
||||
default `y`, per the task's requirement, everything built in, not modular,
|
||||
since the 6.18 rootfs has no working module-loading pipeline yet
|
||||
(`../PORT-STATUS.md` M3 note: the old 5.10 `.ko`s already fail on 6.18 from
|
||||
vermagic mismatch, and a rebuilt 6.18 module tree for Buildroot doesn't exist
|
||||
@@ -395,7 +395,7 @@ yet either).
|
||||
### 4.3 Config symbols (`=y`, built-in)
|
||||
```
|
||||
CONFIG_WIRELESS=y # already =y in the live 6.18 .config
|
||||
CONFIG_CFG80211=y # already =y — flipped in "batch2" per ../DRIVER-PARITY.md
|
||||
CONFIG_CFG80211=y # already =y, flipped in "batch2" per ../DRIVER-PARITY.md
|
||||
CONFIG_WLAN=y # already =y
|
||||
CONFIG_MMC=y # already =y
|
||||
CONFIG_MMC_DW_ROCKCHIP=y # already =y
|
||||
@@ -403,67 +403,67 @@ CONFIG_RFKILL=y # already =y
|
||||
CONFIG_AIC_WLAN_SUPPORT=y # new
|
||||
CONFIG_AIC8800_WLAN_SUPPORT=y # new
|
||||
CONFIG_AIC8800_BTLPM_SUPPORT=y # new
|
||||
CONFIG_BT=y # currently =m in the live .config — flip to =y for the same
|
||||
CONFIG_BT=y # currently =m in the live .config, flip to =y for the same
|
||||
# no-working-module-pipeline reason as the aic8800 pieces
|
||||
CONFIG_BT_HCIUART=y # currently =m — flip alongside CONFIG_BT
|
||||
CONFIG_BT_HCIUART=y # currently =m, flip alongside CONFIG_BT
|
||||
CONFIG_BT_HCIUART_H4=y # already =y (H4 is the transport this board's BT actually uses,
|
||||
# per hardware-86-panel.md: UART1/ttyS1, hciattach -s 1500000
|
||||
# ... any 1500000 flow nosleep)
|
||||
CONFIG_CRYPTO_ARC4=y CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_CCM=y CONFIG_CRYPTO_AES=y # driver's
|
||||
# internal key-handling deps, currently "[ ] batch2" in
|
||||
# ../DRIVER-PARITY.md — confirm =y, not =m, alongside this work
|
||||
# ../DRIVER-PARITY.md, confirm =y, not =m, alongside this work
|
||||
```
|
||||
Do **not** enable `CONFIG_MAC80211` for this driver — confirmed by source
|
||||
inspection (§3.3 note, no `ieee80211_hw`/mac80211 symbol usage anywhere in
|
||||
Do **not** enable `CONFIG_MAC80211` for this driver: confirmed by source
|
||||
inspection (section 3.3 note, no `ieee80211_hw`/mac80211 symbol usage anywhere in
|
||||
`aic8800_fdrv/`) that this is a pure `cfg80211_ops` full-MAC driver; mac80211
|
||||
was only ever needed for the *other* vendor WiFi chips in the shared
|
||||
`sdk/sysdrv/drv_ko/wifi/` tree (RTL8189FS etc.), not this one. Leaving it out
|
||||
avoids pulling in a subsystem this port doesn't need. Do **not** carry
|
||||
`CONFIG_RFKILL_RK` — confirmed unused (`aic8800_btlpm/rfkill.c` calls the
|
||||
`CONFIG_RFKILL_RK`: confirmed unused (`aic8800_btlpm/rfkill.c` calls the
|
||||
standard mainline `rfkill_register()`, no Rockchip-specific rfkill hook).
|
||||
|
||||
### 4.4 DT changes
|
||||
On the board DT that M4/M5 work extends
|
||||
(`warden-sdk/kernel/rv1106-enablement/dts/rv1106-warden.dts` or its successor —
|
||||
(`warden-sdk/kernel/rv1106-enablement/dts/rv1106-warden.dts` or its successor,
|
||||
follow the pattern of the M3 `&emmc` addition in `rv1106-warden-m2.dts:126-142`):
|
||||
1. Port the `sdmmc0_{clk,cmd,bus4,det}` pinctrl group from
|
||||
`sdk/sysdrv/source/kernel/arch/arm/boot/dts/rv1106-pinctrl.dtsi:700-731`
|
||||
(not yet in the ported tree — M1–M3 only needed the eMMC/uart2/eth pin
|
||||
(not yet in the ported tree: M1-M3 only needed the eMMC/uart2/eth pin
|
||||
groups).
|
||||
2. Add the `sdmmc: mmc@ffaa0000` node (clocks `HCLK_SDMMC`/`CCLK_SRC_SDMMC` off
|
||||
`&cru`, `SCLK_SDMMC_DRV`/`SCLK_SDMMC_SAMPLE` off `&grf_cru` — the same
|
||||
`&cru`, `SCLK_SDMMC_DRV`/`SCLK_SDMMC_SAMPLE` off `&grf_cru`, the same
|
||||
`grf_cru` dependency the M2 eMMC fix already established, so no new
|
||||
prerequisite) and the `sdio_pwrseq` node, both transplanted verbatim from
|
||||
§1's block (interrupt `GIC_SPI 52`, per `rv1106.dtsi:1403-1412` in the
|
||||
section 1's block (interrupt `GIC_SPI 52`, per `rv1106.dtsi:1403-1412` in the
|
||||
vendor tree).
|
||||
3. `status = "okay"` on `&sdmmc`, matching the vendor board DT exactly (§1).
|
||||
4. **Do not** touch `&sdio` (mmc@ff9a0000) — leave `disabled`, it's genuinely
|
||||
unused hardware on this board (§1 correction).
|
||||
3. `status = "okay"` on `&sdmmc`, matching the vendor board DT exactly (section 1).
|
||||
4. **Do not** touch `&sdio` (mmc@ff9a0000): leave `disabled`, it's genuinely
|
||||
unused hardware on this board (section 1 correction).
|
||||
|
||||
### 4.5 Driver init-order note
|
||||
The 5.10 module load order (`insmod_wifi.sh`, §1) is
|
||||
`aic8800_bsp → (200ms) → aic8800_fdrv → (2s!) → aic8800_btlpm`, with real sleep
|
||||
delays between each. Built-in (`=y`), there is no equivalent explicit delay —
|
||||
The 5.10 module load order (`insmod_wifi.sh`, section 1) is
|
||||
`aic8800_bsp -> (200ms) -> aic8800_fdrv -> (2s!) -> aic8800_btlpm`, with real sleep
|
||||
delays between each. Built-in (`=y`), there is no equivalent explicit delay:
|
||||
initcall order is controlled by link order (the vendor Makefile's `obj-y` list
|
||||
is already `aic8800_btlpm/ aic8800_fdrv/ aic8800_bsp/` in Makefile-declaration
|
||||
order but Kbuild links `obj-y` in Makefile order regardless of which appears
|
||||
first in the `ifeq` block — **preserve `aic8800_bsp` before `aic8800_fdrv`
|
||||
first in the `ifeq` block, **preserve `aic8800_bsp` before `aic8800_fdrv`
|
||||
before `aic8800_btlpm` in the new `drivers/net/wireless/aic8800/Makefile`'s
|
||||
`obj-y` list**, mirroring the working insmod order) and by each subsystem's
|
||||
declared `module_init()`/initcall level (all three currently use plain
|
||||
`module_init()`, which becomes `device_initcall` level when built-in — same
|
||||
`module_init()`, which becomes `device_initcall` level when built-in, same
|
||||
level for all three, so link order is what decides relative sequencing among
|
||||
them). The observed 2-second gap between `aic8800_bsp` and `aic8800_fdrv` on
|
||||
the running 5.10 system is suspicious enough (firmware download + chip
|
||||
bring-up time) that if the built-in probe races ahead of firmware readiness,
|
||||
watch for it specifically during bring-up (§6) — this is a real risk the
|
||||
watch for it specifically during bring-up (section 6): this is a real risk the
|
||||
static-link change introduces that modular loading didn't have, not just a
|
||||
formality.
|
||||
|
||||
## 5. Firmware notes
|
||||
|
||||
Firmware is not open source (binary blobs, as expected for WiFi/BT RF/PHY
|
||||
patches) but is freely redistributable — no export-control/NDA marking found on
|
||||
patches) but is freely redistributable: no export-control/NDA marking found on
|
||||
the files themselves or in the vendor tree's licensing. 21 files,
|
||||
`sdk/sysdrv/drv_ko/wifi/aic8800dc/aic8800dc_fw/` (484 KB total):
|
||||
```
|
||||
@@ -476,25 +476,25 @@ fw_patch_{8800dc_u02,8800dc_u02_ext0,8800dc_u02h}.bin # BT patch firmware
|
||||
fw_patch_table_8800dc_{u02,u02h}.bin # BT patch tables
|
||||
lmacfw_rf_8800dc.bin # RF test-mode firmware
|
||||
```
|
||||
Per `aic_bsp_main.c`'s `fw_8800dc_u02[]` table (§1), the exact subset loaded at
|
||||
Per `aic_bsp_main.c`'s `fw_8800dc_u02[]` table (section 1), the exact subset loaded at
|
||||
runtime depends on `AICBSP_CPMODE_WORK` vs `_TEST` and on `CONFIG_SDIO_BT`
|
||||
(=n in the vendor Makefile — WiFi and BT firmware are loaded/attached
|
||||
(=n in the vendor Makefile: WiFi and BT firmware are loaded/attached
|
||||
separately, not as one combo blob, despite the combo chip). **Firmware load
|
||||
path**: `AIC_FW_PATH` Kconfig default is `/oem/usr/ko/aic8800dc_fw` — this is a
|
||||
path**: `AIC_FW_PATH` Kconfig default is `/oem/usr/ko/aic8800dc_fw`, this is a
|
||||
5.10-era Buildroot-rootfs-layout artifact (the `/oem` partition), not a kernel
|
||||
concept; on the 6.18 rootfs, point this at wherever WardenOS's 6.18 Buildroot
|
||||
userspace places firmware (likely `/lib/firmware/aic8800dc/` if following
|
||||
standard mainline convention, or keep `/oem/usr/ko/aic8800dc_fw` if the 6.18
|
||||
rootfs partition layout is unchanged from 5.10 — confirm against whatever the
|
||||
rootfs partition layout is unchanged from 5.10, confirm against whatever the
|
||||
M4/M5 rootfs build actually produces, this is a rootfs-layout decision, not a
|
||||
kernel one). Not found in `linux-firmware.git` (the mainline firmware
|
||||
project) — AIC8800 firmware has not been upstreamed there; continue shipping
|
||||
project): AIC8800 firmware has not been upstreamed there; continue shipping
|
||||
it the way the vendor tree already does (bundled alongside the driver, loaded
|
||||
by direct file read per §3.8, not `request_firmware()`).
|
||||
by direct file read per section 3.8, not `request_firmware()`).
|
||||
|
||||
**Chip variant**: **AIC8800DC**, confirmed authoritative by the board config
|
||||
(`RK_ENABLE_WIFI_CHIP=AIC8800DC`) and the SDIO device ID match in source
|
||||
(`aicsdio.c:75,80`: vendor `0xc8a1`, device `0xc08d`) — not the dual-band
|
||||
(`aicsdio.c:75,80`: vendor `0xc8a1`, device `0xc08d`), not the dual-band
|
||||
AIC8800D80 seen on other LuckFox boards. 2.4 GHz only in practice (confirmed
|
||||
on hardware per `wifi-bluetooth-aic8800.md:10`: `iw phy` shows 1 band, 0
|
||||
5 GHz channels, despite AIC8800DC being marketed dual-band-capable elsewhere).
|
||||
@@ -504,34 +504,34 @@ is authoritative.
|
||||
## 6. Verify steps
|
||||
|
||||
Follow the existing A/B `_b`-slot hardware-verification loop
|
||||
(`warden-sdk/kernel/docs/m2-boot-on-c8a3.md`), same method M1–M3 already used:
|
||||
(`warden-sdk/kernel/docs/m2-boot-on-c8a3.md`), same method M1-M3 already used:
|
||||
1. **Build**: driver compiles clean into the 6.18.46 tree (`make ... modules`
|
||||
is not the target — it's `=y`, so this is just `make zImage`/whatever M2's
|
||||
is not the target, it's `=y`, so this is just `make zImage`/whatever M2's
|
||||
`build-m2.sh` wraps, succeeding with the new `drivers/net/wireless/aic8800/`
|
||||
objects linked into `vmlinux`/the zImage).
|
||||
2. **Probe**: boot on `warden-c8a3`, confirm in `dmesg`: the `sdmmc` MMC host
|
||||
binds (`dwmmc_rockchip ffaa0000.mmc: ...`, same pattern M3 already proved
|
||||
for `ffa90000.mmc`/eMMC), then an SDIO card enumerates on it, then
|
||||
`aic8800_bsp`'s probe fires (vendor/device ID match, firmware file opens
|
||||
succeed — watch specifically for `AIC_FW_PATH` resolution failures, §5),
|
||||
succeed, watch specifically for `AIC_FW_PATH` resolution failures, section 5),
|
||||
then `aic8800_fdrv` attaches and **`wlan0` appears** in `ip link`.
|
||||
3. **cfg80211 sanity**: `iw phy` shows the expected single 2.4 GHz band/14
|
||||
channels (matching the known-good 5.10 baseline in
|
||||
`wifi-bluetooth-aic8800.md:10` — a mismatch here is a signal something in
|
||||
`wifi-bluetooth-aic8800.md:10`, a mismatch here is a signal something in
|
||||
the cfg80211/wiphy port is wrong, not a chip regression).
|
||||
4. **Scan**: `iw dev wlan0 scan` returns nearby APs — exercises
|
||||
4. **Scan**: `iw dev wlan0 scan` returns nearby APs, exercises
|
||||
`rwnx_cfg80211_scan`/`cfg80211_scan_done()` and, indirectly, whether the
|
||||
wiphy-locking port (§3.3) is functioning rather than deadlocking.
|
||||
wiphy-locking port (section 3.3) is functioning rather than deadlocking.
|
||||
5. **Connect**: associate to a real AP (`wpa_supplicant`/`wpa_cli`, matching
|
||||
WardenOS's own `wlan0` ownership model — do **not** start `rkwifi_server`,
|
||||
§1) and confirm `COMPLETED` state plus a DHCP lease — exercises
|
||||
WardenOS's own `wlan0` ownership model, do **not** start `rkwifi_server`,
|
||||
section 1) and confirm `COMPLETED` state plus a DHCP lease, exercises
|
||||
`rwnx_cfg80211_connect`/`cfg80211_connect_result()`.
|
||||
6. **Known-regression checks** (carry forward, don't re-discover): confirm the
|
||||
two hardening patches (§0/§4.1) are actually effective — no console-flood
|
||||
two hardening patches (section 0/section 4.1) are actually effective, no console-flood
|
||||
"cmd timed-out" spam under load, and no CPU-pinning busy-spin if the SDIO
|
||||
link is stressed (`aicwf_bustx_thr` should sleep, not spin, on a wakeup
|
||||
failure). Confirm `iw dev wlan0 set power_save off` still behaves as
|
||||
expected (a wall-powered panel, no reason to want power-save —
|
||||
expected (a wall-powered panel, no reason to want power-save:
|
||||
`wifi-bluetooth-aic8800.md:41`).
|
||||
7. **BT** (secondary to WiFi but same milestone): confirm `aic8800_btlpm`
|
||||
attaches and `hciattach -s 1500000 /dev/ttyS1 any 1500000 flow nosleep`
|
||||
@@ -551,12 +551,12 @@ Follow the existing A/B `_b`-slot hardware-verification loop
|
||||
`flare-edge/research/linux-6.18.46/.config` (live, post-M3, batch2 CFG80211=y),
|
||||
`flare-edge/research/linux-6.18.46/include/net/cfg80211.h` (directly read to
|
||||
verify `wiphy_new`, `cfg80211_connect_result`, `wiphy_lock`/`lockdep_assert_wiphy`
|
||||
against the actual target tree, not release notes — §3.3),
|
||||
against the actual target tree, not release notes, section 3.3),
|
||||
`flare-edge/research/plan44-openwrt/` (checked, no aic8800),
|
||||
`warden-sdk/kernel/rv1106-enablement/{PORT-STATUS.md,DRIVER-PARITY.md,OVERNIGHT-PLAN.md}`,
|
||||
`warden-sdk/kernel/docs/{bringup.md,m2-boot-on-c8a3.md}`,
|
||||
`luckfox-pico-86-panel/{wifi-bluetooth-aic8800.md,hardware-86-panel.md,alternative-bsps.md,sdk-patches.md,boot-chain.md}`.
|
||||
- Web (via research pass, see §0/§2): github.com/radxa-pkg/aic8800 +
|
||||
- Web (via research pass, see section 0/section 2): github.com/radxa-pkg/aic8800 +
|
||||
deepwiki.com/radxa-pkg/aic8800; forum.armbian.com topic 50332 ("AIC8800 wifi
|
||||
sdio module not working with kernel 6.12+"); kernel.org/patchwork commits
|
||||
`9b13df3fb64e` (timer_delete rename), `2655926aea9b` (netif_rx_ni removal),
|
||||
@@ -564,6 +564,6 @@ Follow the existing A/B `_b`-slot hardware-verification loop
|
||||
LKML/lkml.iu.edu mirrors for the timer-rename and wiphy-guard series.
|
||||
Patchwork/LWN direct fetches were partially blocked by anti-bot walls during
|
||||
research, so the *exact commit/version* the wiphy-lock migration landed in
|
||||
is not pinned precisely — but its **presence and current contract in the
|
||||
is not pinned precisely, but its **presence and current contract in the
|
||||
actual 6.18.46 tree we're porting to is directly confirmed** (previous
|
||||
paragraph), which is the fact that actually matters for this port.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# AIC8800 wifi+BT port — M5 progress (2026-08-24)
|
||||
# AIC8800 wifi+BT port: M5 progress (2026-08-24)
|
||||
|
||||
Status: **DONE — zImage + rv1106-warden.dtb build clean with the driver
|
||||
Status: **DONE, zImage + rv1106-warden.dtb build clean with the driver
|
||||
built in.** Not flashed/booted (parent session verifies on hardware).
|
||||
|
||||
## Build status
|
||||
@@ -15,14 +15,14 @@ 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
|
||||
(...);`-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_initcall`s in the correct link order —
|
||||
`module_init()`s appear as `device_initcall`s 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.
|
||||
|
||||
@@ -37,57 +37,57 @@ 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
|
||||
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
|
||||
`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`
|
||||
- `drivers/net/wireless/aic8800/Kconfig`, top-level `AIC_WLAN_SUPPORT`
|
||||
bool + `AIC_FW_PATH` string, `source`s 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 §4.5, since these are
|
||||
- `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`
|
||||
- `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 `Makefile`s (`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
|
||||
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)
|
||||
## 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` (×3), `rwnx_main.c`, `rwnx_rx.c` (×2).
|
||||
- `del_timer_sync()` → `timer_delete_sync()` — 10 sites: `aicsdio.c`,
|
||||
`aicwf_sdio.c` (×5), `rwnx_main.c` (×2, one more than the plan's count —
|
||||
- `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` (×2).
|
||||
- `del_timer()` → `timer_delete()` — 9 sites: `aicwf_tcp_ack.c` (×4),
|
||||
`rwnx_rx.c` (×2), `aic8800_btlpm/aic8800_btlpm.c` (×3, dead — not in this
|
||||
`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`
|
||||
(×3, same — `lpm.c` isn't compiled, `CONFIG_SUPPORT_LPM=n`).
|
||||
- `netif_rx_ni()` → `netif_rx()` — 3 sites, all `rwnx_rx.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
|
||||
`-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
|
||||
@@ -100,12 +100,12 @@ out-of-tree `KDIR=` external-module style and don't apply directly):
|
||||
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
|
||||
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
|
||||
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
|
||||
@@ -123,41 +123,41 @@ out-of-tree `KDIR=` external-module style and don't apply directly):
|
||||
`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) —
|
||||
`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)` —
|
||||
`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()`
|
||||
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
|
||||
- **`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
|
||||
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
|
||||
- **`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 §3.7)** — removed
|
||||
- **`<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
|
||||
this build never defines, only plain `ROCKCHIP`), so none needed
|
||||
stubbing individually; only the unconditional header `#include`s 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
|
||||
- **`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
|
||||
@@ -172,31 +172,31 @@ 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
|
||||
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
|
||||
`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
|
||||
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
|
||||
`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,
|
||||
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
|
||||
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
|
||||
@@ -208,11 +208,11 @@ 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=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
|
||||
# CONFIG_MAC80211 is not set (explicitly left off, pure cfg80211 full-MAC
|
||||
driver, confirmed no mac80211/ieee80211_hw
|
||||
symbol usage anywhere in aic8800_fdrv)
|
||||
```
|
||||
@@ -231,12 +231,12 @@ ported drivers' symbols (`CONFIG_CLK_RV1106`, `CONFIG_PINCTRL_ROCKCHIP`,
|
||||
`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
|
||||
- `&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) —
|
||||
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
|
||||
@@ -245,7 +245,7 @@ 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) —
|
||||
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:
|
||||
@@ -260,7 +260,7 @@ previously applied) patch detected" against the freshly-copied tree, and
|
||||
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
|
||||
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
|
||||
@@ -269,35 +269,35 @@ 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
|
||||
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.
|
||||
hardware: no kflash, no reboot, no `/dev/ttyUSB2`, no Pi.
|
||||
|
||||
## What the parent should watch for on hardware
|
||||
|
||||
Per PORT-PLAN.md §6's verify sequence:
|
||||
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
|
||||
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
|
||||
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
|
||||
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 (§3.3 of the plan) — this is the area with 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
|
||||
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/
|
||||
@@ -307,6 +307,6 @@ Per PORT-PLAN.md §6's verify sequence:
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# AIC8800 wifi — VERIFIED on warden-c8a3 (self-built 6.18.46), 2026-08-25
|
||||
# AIC8800 wifi: VERIFIED on warden-c8a3 (self-built 6.18.46), 2026-08-25
|
||||
|
||||
**Result: wifi works end-to-end on our self-built Linux 6.18.46.** Modules built
|
||||
from the ported source (vermagic `6.18.46 SMP mod_unload ARMv7 p2v8`), loaded on
|
||||
@@ -6,39 +6,39 @@ the panel, downloaded firmware to the AIC8800DC, created `wlan0`, and completed
|
||||
live RF scan.
|
||||
|
||||
## Evidence (serial console, _b slot = our 6.18 kernel)
|
||||
- `insmod aic8800_bsp.ko` → firmware download OK: `aicwf_patch_config_8800dc done`,
|
||||
- `insmod aic8800_bsp.ko` -> firmware download OK: `aicwf_patch_config_8800dc done`,
|
||||
`Start app: 00120000`, BSP_RC=0.
|
||||
- `insmod aic8800_fdrv.ko` → `ieee80211 phy0: HT supp 1, VHT supp 1, HE supp 1`,
|
||||
- `insmod aic8800_fdrv.ko` -> `ieee80211 phy0: HT supp 1, VHT supp 1, HE supp 1`,
|
||||
FDRV_RC=0.
|
||||
- `wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> ... link/ether <device MAC>`
|
||||
- `iw dev wlan0 scan` found real APs (SSIDs/BSSIDs redacted for publication):
|
||||
- **the site AP at 2412 MHz, −43 dBm**
|
||||
- a neighboring guest AP at 2412 MHz, −73 dBm
|
||||
- +several more, correct signal strengths → RF path fully functional.
|
||||
- **the site AP at 2412 MHz, -43 dBm**
|
||||
- a neighboring guest AP at 2412 MHz, -73 dBm
|
||||
- +several more, correct signal strengths -> RF path fully functional.
|
||||
|
||||
## Why MODULES, not built-in (=y)
|
||||
Built-in device_initcalls run BEFORE the dw_mmc/SDIO controller probes. Initcalls
|
||||
are sequential: `aicbsp_init` blocked 3.3–7.5 s doing the eager chip bring-up, and
|
||||
the mmc controller only probed at 7.9 s (SDIO card at 8.2 s) — AFTER aicbsp had
|
||||
already given up (`aicsdio.c:597` 2 s `down_timeout` → `sdio_unregister_driver`).
|
||||
are sequential: `aicbsp_init` blocked 3.3-7.5 s doing the eager chip bring-up, and
|
||||
the mmc controller only probed at 7.9 s (SDIO card at 8.2 s), AFTER aicbsp had
|
||||
already given up (`aicsdio.c:597` 2 s `down_timeout` -> `sdio_unregister_driver`).
|
||||
Extending the timeout can't help (aicbsp blocks the very mmc probe that would
|
||||
enumerate the card — a deadlock). Loaded as modules AFTER boot (mmc up, card at
|
||||
enumerate the card, a deadlock). Loaded as modules AFTER boot (mmc up, card at
|
||||
4 s), `insmod aic8800_bsp` registers the SDIO driver against an already-present
|
||||
card → probe fires immediately → firmware download → fdrv → wlan0. This is the
|
||||
card -> probe fires immediately -> firmware download -> fdrv -> wlan0. This is the
|
||||
vendor-proven flow.
|
||||
|
||||
## Kernel-size fix (needed to boot the wifi kernel at all)
|
||||
The wifi kernel grew the gzip zImage to 12.12 MB; rockchip U-Boot loads the kernel
|
||||
blob at 0x8000 and relocates the DTB to 0xc00000 (12 MB), so a >~11.95 MB zImage
|
||||
overruns the FDT at U-Boot load time (`Sysmem Error: KERNEL overlap with FDT`) and
|
||||
FLARE-AB falls back to _a. Switched `CONFIG_KERNEL_GZIP` → `CONFIG_KERNEL_XZ`:
|
||||
zImage 12.12 MB → 8.15 MB (module build), ~4 MB headroom under the FDT. Also the
|
||||
FLARE-AB falls back to _a. Switched `CONFIG_KERNEL_GZIP` -> `CONFIG_KERNEL_XZ`:
|
||||
zImage 12.12 MB -> 8.15 MB (module build), ~4 MB headroom under the FDT. Also the
|
||||
right call for a firmware kernel. (Uncompressed Image is ~30 MB; the ARM
|
||||
decompressor relocates the FDT at runtime, so only the U-Boot LOAD-time overlap
|
||||
mattered — proven by the kernel booting once the zImage fit.)
|
||||
mattered: proven by the kernel booting once the zImage fit.)
|
||||
|
||||
## Boot-time auto-load (follow-up, deployment layer — not the kernel port)
|
||||
## Boot-time auto-load (follow-up, deployment layer, not the kernel port)
|
||||
Modules were insmod'd manually for this verify. Production auto-load needs a
|
||||
loader that inserts `aic8800_bsp.ko` → `aic8800_fdrv.ko` (→ `aic8800_btlpm.ko`) in
|
||||
loader that inserts `aic8800_bsp.ko` -> `aic8800_fdrv.ko` (-> `aic8800_btlpm.ko`) in
|
||||
order from wherever they're staged; the vendor `insmod_wifi.sh` references a
|
||||
different variant (`aic_load_fw.ko`/`bcmdhd.ko`, absent here). Track in the rootfs.
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
# AICSemi AIC8800DC SDIO WiFi+BT driver (WardenOS M5 port).
|
||||
#
|
||||
# Ported from the vendor 5.10.160 out-of-tree source
|
||||
# (flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/) — see
|
||||
# (flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/), see
|
||||
# warden-sdk/kernel/rv1106-enablement/wifi/PORT-PLAN.md and PORT-PROGRESS.md.
|
||||
# Modules (=m), loaded late by /oem/usr/ko/insmod_wifi.sh: the AIC8800 SDIO
|
||||
# bring-up is two-stage (bsp downloads firmware, chip re-enumerates, fdrv
|
||||
# attaches). Built-in device_initcalls run BEFORE the dw_mmc/SDIO controller
|
||||
# probes — initcalls are sequential, so aicbsp_init blocks [3.3-7.5]s while the
|
||||
# probes: initcalls are sequential, so aicbsp_init blocks [3.3-7.5]s while the
|
||||
# mmc controller only probes at [7.9]s afterward, and the eager bring-up
|
||||
# deadlocks (it waits for a card the blocked mmc probe hasn't enumerated).
|
||||
# Late module load, after the mmc-pwrseq enumerates the card, is the
|
||||
@@ -28,7 +28,7 @@ config AIC_FW_PATH
|
||||
default "/oem/usr/ko/aic8800dc_fw"
|
||||
help
|
||||
Path to the firmware & config files. The driver reads these
|
||||
directly (not via request_firmware()) — see PORT-PLAN.md §3.8.
|
||||
directly (not via request_firmware()), see PORT-PLAN.md section 3.8.
|
||||
|
||||
if AIC_WLAN_SUPPORT
|
||||
source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Link order matters: bsp before fdrv before btlpm, mirroring the working
|
||||
# insmod order (insmod_wifi.sh) now that these are built-in (=y) instead of
|
||||
# modules — see PORT-PLAN.md §4.5.
|
||||
# modules, see PORT-PLAN.md section 4.5.
|
||||
obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800_bsp/
|
||||
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
|
||||
obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) += aic8800_btlpm/
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# aic8800_bsp — SDIO bus glue + firmware bootstrap, ported in-tree from the
|
||||
# aic8800_bsp: SDIO bus glue + firmware bootstrap, ported in-tree from the
|
||||
# vendor out-of-tree Makefile (flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/
|
||||
# aic8800_bsp/Makefile). CONFIG_AIC_FW_PATH is now a real Kconfig string
|
||||
# symbol (see ../Kconfig) so it needs no -D here — the driver picks it up
|
||||
# symbol (see ../Kconfig) so it needs no -D here; the driver picks it up
|
||||
# from include/generated/autoconf.h directly (aicsdio.c, aic_bsp_driver.h).
|
||||
#
|
||||
# Vendor CONFIG_* build-time knobs below are preserved as fixed -D flags
|
||||
|
||||
@@ -3,5 +3,5 @@ config AIC8800_BTLPM_SUPPORT
|
||||
default y
|
||||
help
|
||||
This is support for the aic8800 bluetooth low-power-mode / HCI
|
||||
wake companion module (aic8800_btlpm). Built-in (y) by default —
|
||||
wake companion module (aic8800_btlpm). Built-in (y) by default,
|
||||
see the aic8800 port notes in warden-sdk/kernel/rv1106-enablement/wifi/.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# aic8800_btlpm — Bluetooth low-power-mode / HCI wake companion module,
|
||||
# aic8800_btlpm: Bluetooth low-power-mode / HCI wake companion module,
|
||||
# ported in-tree from the vendor out-of-tree Makefile
|
||||
# (flare-edge/sdk/sysdrv/drv_ko/wifi/aic8800dc/aic8800_btlpm/Makefile).
|
||||
# lpm.c stays out of the build (CONFIG_SUPPORT_LPM was already off in the
|
||||
|
||||
@@ -3,5 +3,5 @@ config AIC8800_WLAN_SUPPORT
|
||||
default y
|
||||
help
|
||||
This is support for the aic8800 cfg80211 full-MAC wifi driver
|
||||
(aic8800_fdrv). Built-in (y) by default — see the aic8800 port
|
||||
(aic8800_fdrv). Built-in (y) by default, see the aic8800 port
|
||||
notes in warden-sdk/kernel/rv1106-enablement/wifi/.
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# aic8800_fdrv — the cfg80211 full-MAC driver ("fdrv"), ported in-tree from
|
||||
# aic8800_fdrv: the cfg80211 full-MAC driver ("fdrv"), ported in-tree from
|
||||
# the vendor out-of-tree Makefile (flare-edge/sdk/sysdrv/drv_ko/wifi/
|
||||
# aic8800dc/aic8800_fdrv/Makefile). SDIO-only build (this board has no
|
||||
# USB/PCI variant) — usb_host.c and rwnx_pci.c are dropped from the tree
|
||||
# entirely (PORT-PLAN.md §4.1 flagged both as candidates to drop "unless a
|
||||
# build error proves them referenced elsewhere" — that held for these two).
|
||||
# USB/PCI variant): usb_host.c and rwnx_pci.c are dropped from the tree
|
||||
# entirely (PORT-PLAN.md section 4.1 flagged both as candidates to drop "unless a
|
||||
# build error proves them referenced elsewhere", that held for these two).
|
||||
# rwnx_mesh.c was ALSO dropped initially on the same theory but had to be
|
||||
# restored: rwnx_tx.c's NL80211_IFTYPE_MESH_POINT switch-case is not
|
||||
# preprocessor-gated, so rwnx_mesh.h's types/prototypes are needed to
|
||||
# compile even though this board never creates a mesh-type interface.
|
||||
# md5.o: fdrv carries its OWN copy (vendor ships md5.c in both aic8800_bsp/ and
|
||||
# aic8800_fdrv/). As separate modules each .ko needs its own MD5 — bsp does not
|
||||
# aic8800_fdrv/). As separate modules each .ko needs its own MD5: bsp does not
|
||||
# EXPORT_SYMBOL(MD5Init/...), so fdrv.ko cannot resolve them from aic8800_bsp.ko
|
||||
# (modpost: "MD5Final undefined"). The two copies are byte-identical and live in
|
||||
# separate module namespaces, so there is no collision. (When these were briefly
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* --- M5: AIC8800DC wifi/BT SDIO (on &sdmmc, mmc@ffaa0000 — NOT &sdio) --- */
|
||||
/* --- M5: AIC8800DC wifi/BT SDIO (on &sdmmc, mmc@ffaa0000, NOT &sdio) --- */
|
||||
&sdmmc {
|
||||
max-frequency = <50000000>;
|
||||
bus-width = <4>;
|
||||
|
||||
Reference in New Issue
Block a user