Files
test0r b8ba0b342e patches: re-roll staging-prep as 7-patch series (tx-bounce added)
Fold bes2600/tx-sdio-dma-oob into the linear series as 7/7.
Re-cover-letter and update testing matrix. Update UPSTREAM.md table
and submission route to list the 7th branch. The PS Mode Error
residual note is removed from the known-limitations section -- it
stopped recurring after 7/7 deployed.

Both staging-prep-series/ (Mobian paths) and staging-prep-series-
danctnix/ (drivers/staging/bes2600/ paths) variants regenerated;
all 14 patch files checkpatch --strict clean (0/0/0).

Net: +117 / -550 lines across 9 files.
2026-04-23 12:43:29 +02:00

14 KiB

BES2600 driver -- upstream submission prep

Status

Seven patches, all checkpatch --strict clean, all deployed and verified on a PineTab2 (BES2600WM + Rockchip RK3566) running linux-pinetab2 6.19.10-danctnix1. Ready for Mobian DKMS merge requests and as the basis for a future drivers/staging/bes2600/ submission to linux-wireless.

The 7th patch (tx-sdio-dma-oob) fixes a KFENCE-detected SDIO DMA out-of-bounds read on every TX burst -- a real memory-safety bug that also leaks adjacent kernel memory onto the air. This upgrades the series from "cleanup" to "cleanup + live bug fix" and should precede any linux-wireless RFC.

The series

Recommended submission order (dependency-clean, bisectable):

# Branch Commit Intent
01 bes2600/factory-request-firmware 1a5d54a c1 -- Replace filp_open + kernel_read in the factory-read path with request_firmware(). Repoint FACTORY_PATH macro to the firmware-class name. Kills a kernel-mainline anti-pattern and the (NULL device *) read and check /lib/firmware/bes2600_factory.txt error boot spam on PineTab2.
02 bes2600/factory-no-efuse-flag 82ba594 c5 -- Default STANDARD_FACTORY_EFUSE_FLAG from y to n. The shipped bes2600_factory.txt has 30 calibration fields; the driver was expecting 31 (incl. a ##select_efuse_flag section this firmware doesn't ship). Also drops an inconsistent #if defined(STANDARD_FACTORY_EFUSE_FLAG) wrapper around the wsm_save_factory_txt_to_mcu() prototype -- the definition and call site are always ungated, so the gate broke the build once EFUSE_FLAG=n.
03 bes2600/factory-thread-dev 8732881 c1.1 -- Thread struct device * through factory_section_read_file() via a module-local setter invoked at SDIO probe, so request_firmware() gets proper per-device context instead of NULL. Removes the (NULL device *) log prefix from factory-related diagnostics.
04 bes2600/pm-gate-on-handshake 80178ec c2 -- Gate the device-end of the LP transition on successful per-VIF firmware handshake. Before: bes2600_pwr_device_enter_lp_mode() was called unconditionally even when wait_for_completion_timeout() returned 0 (firmware never ack'd). On PineTab2 this produced bes2600_pwr_enter_lp_mode, wait pm ind timeout every 5-10s and cascaded into sdio_tx_work WARN splats. After: -ETIMEDOUT returned cleanly, dmesg silent, SDIO stable.
05 bes2600/remove-chardev-user-interface f43bcc5 c3 -- Remove the custom /dev/bes2600 character-device interface (fops, command dispatcher, bes2600_op_* handlers, bes2600_load_uevent, alloc_chrdev_region/class_create/device_create registration, cdev fields in struct bes_cdev). 519-line deletion. Keeps all in-kernel accessor functions (13 callers) and the fw_type module parameter as the user-facing replacement.
06 bes2600/enable-testmode 9398d30 c4 -- Flip CONFIG_BES2600_TESTMODE default from n to y, exposing the driver's mac80211 testmode_cmd surface (dispatches to the firmware's patch_wifi_testMode path) through the standard nl80211 testmode interface. Also fixes accumulated bit-rot revealed by enabling the flag: adds compat shim macros in bes_log.h for the legacy bes2600_info() / bes2600_err() / bes2600_warn() / bes2600_dbg() / bes2600_err_with_cond() family (which had no definition anywhere, despite ~41 call sites in testmode code), defines BES2600_DBG_* subsystem ids as 0 constants, and marks 3 TSM/roam-delay helpers in sta.c as static for -Werror=missing-prototypes.
07 bes2600/tx-sdio-dma-oob 10a05d2 tx-bounce -- Fix a KFENCE OOB read in the SDIO TX path. sdio_tx_work() handed dma_map_sg a block-aligned length (blks * cur_blksize, or 1632) but tx_buffer->buf is only tx_buffer->len bytes long (aliases into an skb linear head sized by pskb_expand_head / TCP). DMA read up to one block past the skb -- KFENCE fires out-of-bounds read in __pi_memcpy_generic / sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper+0x18c, and the padding bytes are transmitted to the peer (kernel-memory leak to air). Allocate a driver-owned DMA-pages bounce buffer of MAX_SDIO_TRANSFER_LEN, memcpy each TX buffer into its slot, zero-pad, and point SG entries at the bounce. Separate from single_gathered_buffer (that one is bus-serialised via sdio_claim_host but sdio_tx_work accumulates SG entries before claiming).

Total: +117 / -550 lines excluding commit messages.

Driver lineage (for the cover letter)

The BES2600 Linux driver is a descendant of the ST-Ericsson CW1200 driver already in mainline at drivers/net/wireless/st/cw1200/. Evidence:

  • Same author on both: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> (visible in the running modinfo on ohm and in the mainline cw1200 commit history).
  • Kconfig option names carry the ancestry: CONFIG_BES2600_USE_STE_EXTENSIONS (STE = ST-Ericsson), CONFIG_BES2600_WSM_DEBUG (WSM = CW1200's host <-> firmware Wireless Sensor Module protocol).
  • File-layout parallel: bh.c, hwio.c, fwio.c, queue.c, scan.c, sta.c, txrx.c, wsm.c, pm.c, main.c -- same spine as CW1200, plus BES-specific additions (ePTA coexistence, bes2600_btuart, 5 GHz support, bes_pwr, bes2600_factory, itp, bes_chardev).

ST-Ericsson wound down in 2013; Bestechnic (founded 2015) appears to have licensed or acquired the CW1200 IP. No public LKML/linux-wireless RFC linking the two has been filed. Bestechnic has never contributed the BES2600 driver upstream.

Background on which fork this series lands

Upstream today for BES2600 is fragmented:

  • salsa.debian.org/Mobian-team/devices/bes2600-dkms -- Mobian DKMS package, actively maintained (last commit 2025-12). Primary PR target.
  • codeberg.org/DanctNIX/linux-pinetab2 -- danctnix kernel fork; ships the driver in-tree at drivers/staging/bes2600/ at tag v6.19.10-danctnix1.
  • gitlab.com/arjanvlek/bes2600 -- original community fork; master was sanitized in 2024-10 (e5055a3 "Removed sources from main branch"). gitlab.com/TuxThePenguin0/bes2600 preserves the pre-sanitization snapshot.

The Mobian DKMS tree and the danctnix in-kernel tree have converged -- 0- hunk diff on bes_pwr.c, bes2600_factory.c, wsm.c between them. This series lands on Mobian first (branches already pushed to git.reauktion.de/marfrit/bes2600-dkms).

Testing

Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566, 8a:2e:77:1f:ec:05, AP newton @ 2.4 GHz ch11 / TelekomHotspot@ERGO @ 5 GHz ch36).

Host kernel: linux-pinetab2 6.19.10-danctnix1-1-pinetab2 with CONFIG_NL80211_TESTMODE=y.

Per-patch:

  • c1: post-reboot dmesg no longer shows read and check /lib/firmware/ bes2600_factory.txt error; request_firmware() reads the file cleanly.
  • c5: factory_parse() now succeeds on the shipped 30-field bes2600_factory.txt; no parse fail / factory cali data get failed.
  • c1.1: factory-related log lines no longer carry the (NULL device *): prefix.
  • c2: pre-patch dmesg carried ~20-30 wait pm ind timeout messages per 5 min and 2+ sdio_tx_work WARN splats; post-patch wait pm ind timeout is 0 in the same window and [RX] Receive failure: 4. disappears. A residual sdio_tx_work+0x2b4 splat (~1 per reboot) still recurred with c1..c6 alone; see c7 below for its root cause and fix.
  • c3: /dev/bes2600 character device node is absent post-reboot; lsmod | grep bes2600 still shows both bes2600 and bes2600_btuart loaded and associated; WiFi continues to function.
  • c4: iw phy0 now lists testmode under Supported commands; nl80211 testmode interface reachable via iw phy0 testmode cmd <data> (not exercised end-to-end yet -- depends on userspace tooling).

Full stack c1+c5+c1.1+c2+c3+c4: WiFi associates and passes traffic across 3+ reboots.

Known limitations / not-in-this-series

  • factory_section_write_file() in bes2600_factory.c still uses kernel_write() + filp_open(O_CREAT | O_TRUNC | O_RDWR) to persist per-channel calibration updates back to /lib/firmware/bes2600_factory.txt. Converting the write-back path to a debugfs or nl80211 testmode interface is out of scope here; upstream submission for drivers/staging/ will need to take that on.

  • bes_chardev.c still carries bes2600_chrdev_write_dpd_data_to_file() (gated BES2600_WRITE_DPD_TO_FILE, off by default so dead code in the default build) and bes2600_chrdev_read_and_check_dpd_data(). Both use filp_open/kernel_read/kernel_write and need the same treatment.

  • bes_fw.c:587 unconditionally creates /lib/firmware/bes2002_fw_write.bin via filp_open(O_CREAT | O_RDWR) to capture firmware bytes as they are sent to the chip. Pure debug helper; should be deleted or gated behind a debugfs trigger.

  • After c3, the bes2600_chrdev_is_signal_mode() / _update_signal_mode() family still reads/writes a bes_cdev singleton. Threading struct bes2600_common * through those call sites (13 files) requires first replacing the fw_type module_param with a per-phy debugfs knob or nl80211 testmode command -- a migration that overlaps with c4's testmode plumbing. Tracked as c3.1 (deferred).

  • One residual dmesg notice after the full stack: bes2600_wlan mmc2:0001:1: PS Mode Error, Reason:1 at T+40s on fresh boot. Distinct from the pre-c2 wait pm ind timeout cascade -- benign, driver recovers, WiFi stays up. Root cause not investigated; candidate for a future c2.1 or firmware-RE follow-up.

  • Firmware RE (task d) was pursued briefly. The shipped firmware keeps many format-string literals (e.g. patch_HI_Set_Coex_Params, hw_epta_ enable:0x%x, new_run_flag:0x%x, gEptaBypass: %d) as dead data -- the string is in the blob but no code references it in any encoding. The compiler kept the literal while dead-stripping the TRACE() / patch_*() callers that would have used it. Takeaway: strings-mining overstates the reachable feature surface. A proper firmware RE would need function-graph analysis from the reset vector; out of scope here.

Submission routes

Near-term: Mobian DKMS merge request

All 7 branches are pushed to git.reauktion.de/marfrit/bes2600-dkms with upstream set to salsa.debian.org/Mobian-team/devices/bes2600-dkms. To open an MR against Mobian:

  1. Create a salsa.debian.org account and add the Gitea-side SSH key.
  2. Push the branches to a personal fork on salsa:
    git remote add salsa git@salsa.debian.org:<user>/bes2600-dkms.git
    for br in \
        bes2600/factory-request-firmware \
        bes2600/factory-no-efuse-flag \
        bes2600/factory-thread-dev \
        bes2600/pm-gate-on-handshake \
        bes2600/remove-chardev-user-interface \
        bes2600/enable-testmode \
        bes2600/tx-sdio-dma-oob; do
      git push salsa $br
    done
    
  3. For each branch open an MR against Mobian-team/devices/bes2600-dkms:mobian. Use the commit message as the MR description (it already reads as a standalone rationale).
  4. Consider bundling into a single MR with all 7 commits if the Mobian reviewer prefers series review.

Near-term alt: danctnix linux-pinetab2 (codeberg)

Danctnix is the de-facto upstream for PineTab2 Arch-ARM images (maintainer Danct12). The driver ships in-tree at drivers/staging/bes2600/ in codeberg.org/DanctNIX/linux-pinetab2.

A danctnix-layout variant of the series (same content, paths rooted at drivers/staging/bes2600/ instead of Mobian's bes2600/) is at marfrit/besser/patches/staging-prep-series-danctnix/. Verified to apply cleanly against tag v6.19.10-danctnix1 and checkpatch-clean.

Submission route:

  1. Create a codeberg.org account + add your SSH key.
  2. Fork DanctNIX/linux-pinetab2 on codeberg; push the 7 commits as a branch bes2600/staging-prep-series.
  3. Open a codeberg PR against DanctNIX/linux-pinetab2:master with the cover-letter content as PR description.
  4. Alt: ping Danct12 directly (Matrix / IRC #pine64 / mastodon @danctnix@social.treehouse.systems). Their merge workflow may be more casual than formal PR review.

Mobian and danctnix share the bes2600 source -- bes_pwr.c, bes2600_factory.c, wsm.c all 0-hunk diff at the patched files. Landing in either benefits users of both.

Longer-term: linux-wireless RFC for drivers/staging/bes2600/

This series cleans up the Mobian DKMS tree. A proper mainline staging submission is bigger work -- new Kconfig + Makefile integration under drivers/staging/, a MAINTAINERS entry for Markus Fritsche + CC Dmitry Tarnyagin for CW1200 lineage ack, cover-letter framing the driver as a new staging submission with the CW1200 ancestry cited so reviewers can contextualise the structural parallels.

Gate: the kernel_write() / filp_open() leftovers (factory write-back, DPD-to-file, observe_file debug path) must all go before staging will accept it -- drivers/staging still has a nominal filter against direct filesystem manipulation. Plan those as follow-up patches (c1.2, c1.3, c1.4) and include them in the staging series.

Recommended linux-wireless CC list for a future RFC:

  • Johannes Berg <johannes@sipsolutions.net> (wireless maintainer)
  • Kalle Valo <kvalo@kernel.org> (wireless drivers maintainer)
  • Dmitry Tarnyagin (CW1200 author; email may be stale post-ST-Ericsson)
  • Dang Huynh <dang.huynh@mainlining.org> (bes2600_btuart.c author)
  • Julian <mail@julianfairfax.ch> (Mobian DKMS maintainer)
  • Danct12 (dreemurrs-embedded, PineTab2 kernel maintainer)
  • linux-wireless@vger.kernel.org
  • linux-arm-kernel@lists.infradead.org (PineTab2 RK3566 context)
  • linux-staging@lists.linux.dev (if targeting drivers/staging/)

Signed-off-by chain: every patch has one. Tested-on: PineTab2 (BES2600WM + RK3566) line on each patch.