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.
This commit is contained in:
2026-04-23 12:43:29 +02:00
parent b9f90c30e1
commit b8ba0b342e
17 changed files with 617 additions and 239 deletions
@@ -1,134 +1,185 @@
From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001
From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001
Message-ID: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 14:27:00 +0200
Subject: [PATCH 0/6] bes2600: staging-prep cleanup for PineTab2 (BES2600WM)
Date: Thu, 23 Apr 2026 12:35:28 +0200
Subject: [PATCH 0/7] bes2600: staging-prep cleanup for PineTab2 (BES2600WM)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is the danctnix-layout variant of the bes2600 staging-prep series.
All six patches target `drivers/staging/bes2600/` in
`codeberg.org/DanctNIX/linux-pinetab2` at tag `v6.19.10-danctnix1`. Apply
cleanly, `checkpatch.pl --no-tree --strict` clean.
This series is a staging-prep cleanup for the out-of-tree Bestechnic
BES2600WM Wi-Fi/BT combo-chip driver as shipped by Mobian's bes2600-dkms
package (and in-tree at drivers/staging/bes2600/ in the danctnix
linux-pinetab2 fork). Target hardware is the Pine64 PineTab2 (RK3566
+ BES2600WM, SDIO vendor 0xBE57 / device 0x2002).
The Mobian `bes2600-dkms` variant of this series (same content, paths
rooted at `bes2600/` rather than `drivers/staging/bes2600/`) lives at
`git.reauktion.de/marfrit/bes2600-dkms` branch
`bes2600/staging-prep-series`. If you maintain both trees, you may
prefer to apply there and propagate to the danctnix in-tree copy.
The driver descends from the ST-Ericsson CW1200 (drivers/net/wireless/
st/cw1200/) -- same author, Dmitry Tarnyagin, shared WSM host<->firmware
protocol, shared SDIO bus backend. Kconfig ancestry markers survive in
this tree today: CONFIG_BES2600_USE_STE_EXTENSIONS (STE = ST-Ericsson),
CONFIG_BES2600_WSM_DEBUG (WSM). ST-Ericsson wound down in 2013;
Bestechnic (founded 2015) appears to have inherited or licensed the
CW1200 IP. No linux-wireless RFC has ever linked the two chips.
## Background
The BES2600 Linux driver descends from the ST-Ericsson CW1200 driver in
mainline (`drivers/net/wireless/st/cw1200/`). Same author -- Dmitry
Tarnyagin; shared WSM host<->firmware protocol plumbing; shared SDIO bus
backend. Kconfig ancestry markers survive: `CONFIG_BES2600_USE_STE_EXTENSIONS`
(STE = ST-Ericsson), `CONFIG_BES2600_WSM_DEBUG` (WSM). ST-Ericsson was
wound down in 2013; Bestechnic (founded 2015) appears to have inherited
or licensed the CW1200 IP. No linux-wireless RFC has ever linked the two
chips.
The series fixes observable defects on a PineTab2 running the danctnix
kernel 6.19.10-danctnix1-1 and removes two upstream blockers. Each
patch is independently testable and bisectable; the order below
preserves dependencies.
The series fixes observable defects on a PineTab2 running linux-pinetab2
6.19.10-danctnix1-1 and removes two upstream blockers. Each patch is
independently testable and bisectable; the order below preserves
dependencies.
## What the series does
* 1/6 -- Replace `filp_open()` + `kernel_read()` in the factory-
calibration read path with `request_firmware()`. Repoint the
FACTORY_PATH macro to the firmware-class name
(`bes2600/bes2600_factory.txt`). Kills a kernel-mainline anti-pattern
and the `(NULL device *): read and check /lib/firmware/bes2600_factory.txt
error` boot spam.
* 1/7 -- Replace filp_open() + kernel_read() in the factory-calibration
read path with request_firmware(). Repoint the FACTORY_PATH macro to
the firmware-class name (bes2600/bes2600_factory.txt, matching the
/lib/firmware/ layout). Kills a kernel-mainline anti-pattern and the
'(NULL device *): read and check /lib/firmware/bes2600_factory.txt
error' boot spam on PineTab2.
* 2/6 -- Default `STANDARD_FACTORY_EFUSE_FLAG` from y to n. The shipped
`bes2600_factory.txt` on PineTab2 contains 30 calibration fields; the
driver was expecting 31 (including a `##select_efuse_flag` section
* 2/7 -- Default STANDARD_FACTORY_EFUSE_FLAG from y to n. The shipped
bes2600_factory.txt on PineTab2 contains 30 calibration fields; the
driver was expecting 31 (including a ##select_efuse_flag section
absent from this firmware). Also unguards the
`wsm_save_factory_txt_to_mcu()` prototype in `wsm.h` which was
inconsistently wrapped in `#if defined(STANDARD_FACTORY_EFUSE_FLAG)`
while its definition in `wsm.c` and its call site in `sta.c` were
ungated.
wsm_save_factory_txt_to_mcu() prototype in wsm.h which was
inconsistently wrapped in '#if defined(STANDARD_FACTORY_EFUSE_FLAG)'
while its definition in wsm.c and its call site in sta.c were
ungated -- gcc -Werror=missing-prototypes broke the build with the
new default until this is fixed.
* 3/6 -- Thread `struct device *` through `factory_section_read_file()`
via a module-local setter invoked at SDIO probe. `request_firmware()`
now receives a real device pointer; `(NULL device *):` no longer
prefixes factory-related diagnostics.
* 3/7 -- Thread struct device * through factory_section_read_file() via
a module-local setter invoked at SDIO probe. request_firmware() now
receives a real device pointer; '(NULL device *):' no longer prefixes
factory-related diagnostics.
* 4/6 -- Gate the device-end of the low-power transition on successful
per-VIF firmware handshake. Pre-patch: `bes2600_pwr_enter_lp_mode()`
called `bes2600_pwr_device_enter_lp_mode()` unconditionally even when
`wait_for_completion_timeout()` returned 0. On PineTab2 this recurred
every 5-10 s in idle-associated state, flooded dmesg, and cascaded
into `sdio_tx_work` WARN splats. Post-patch: `-ETIMEDOUT` returned
cleanly, dmesg silent, SDIO stable.
* 4/7 -- Gate the device-end of the low-power transition on successful
per-VIF firmware handshake. Pre-patch bes2600_pwr_enter_lp_mode()
called bes2600_pwr_device_enter_lp_mode() unconditionally even when
wait_for_completion_timeout() returned 0 (firmware never posted the
PM-change indication). On PineTab2 this recurred every 5-10 s
whenever the interface was associated and idle, flooded dmesg, and
cascaded into sdio_tx_work WARN splats / [RX] Receive failure
messages. Post-patch: -ETIMEDOUT returned cleanly, dmesg silent,
SDIO stable.
* 5/6 -- Remove the custom `/dev/bes2600` character-device interface.
`file_operations`, open/read/write/release, `bes2600_op_*` command-
dispatch table, `bes2600_load_uevent`, cdev registration in the init
path -- 519 lines deleted. In-kernel accessors (`is_signal_mode`,
`get_fw_type`, etc., 13 call sites) and the `fw_type` module
parameter are preserved.
* 5/7 -- Remove the custom /dev/bes2600 character-device interface.
file_operations, open/read/write/release, bes2600_op_*
command-dispatch table, bes2600_load_uevent, alloc_chrdev_region /
cdev_init / cdev_add / class_create / device_create in the init
path, and the matching teardown in bes2600_chrdev_free -- 519 lines
deleted. The in-kernel accessor functions (is_signal_mode,
get_fw_type, etc., 13 call sites) and the fw_type module parameter
are preserved; the userspace interface becomes rfkill + module_param
+ (with 6/7) nl80211 testmode.
* 6/6 -- Flip `CONFIG_BES2600_TESTMODE` default from n to y. Also fixes
accumulated bit-rot revealed by enabling the flag: shim macros in
`bes_log.h` for the legacy `bes2600_info/err/warn/dbg/err_with_cond`
family, `BES2600_DBG_*` constants defined as 0, 3 TSM/roam-delay
helpers marked `static`.
* 6/7 -- Flip CONFIG_BES2600_TESTMODE default from n to y. The driver
already implements a mac80211 testmode_cmd dispatcher (routing to
the firmware's patch_wifi_testMode path), already gated on the flag;
CONFIG_NL80211_TESTMODE=y is common on target kernels. Enabling the
flag also exposes accumulated bit-rot -- ~41 calls to undefined
bes2600_info/err/warn/dbg/err_with_cond macros, and 3 TSM/roam-delay
helpers with external linkage but no prototype. Add shim macros to
bes_log.h rewiring the legacy calls onto the existing bes_info /
bes_err / bes_warn / bes_devel family, define BES2600_DBG_* subsystem
ids as 0 constants, and mark the 3 helpers static.
* 7/7 -- Bounce SDIO TX buffers to avoid DMA out-of-bounds reads.
sdio_tx_work() rounded the transfer length up to the SDIO block size
(align = blks * cur_blksize, or 1632) and handed that length to
dma_map_sg() via sg_set_buf(..., tx_buffer->buf, align); tx_buffer->buf
typically aliases into an skb linear head allocated to tx_buffer->len,
not the block-aligned length. The DMA engine therefore read up to one
block past the end of the skb -- KFENCE on PineTab2 fires as
'out-of-bounds read in __pi_memcpy_generic ... 704B right of
kfence-#...' with sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper in
the stack and pskb_expand_head / validate_xmit_skb / tcp_write_xmit in
the allocator stack. Besides being undefined behavior, the padding
bytes are transmitted to the peer, leaking adjacent kernel memory on
the air. Allocate a driver-owned DMA-pages bounce buffer of
MAX_SDIO_TRANSFER_LEN, memcpy each TX buffer into its slot, zero the
padding tail, and point the SG entries at the bounce. Mirrors the
pattern already used for single_gathered_buffer; kept as a separate
allocation because sdio_tx_work accumulates SG entries before claiming
the bus.
## Testing
Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566,
MAC `8a:2e:77:1f:ec:05`). Host kernel: linux-pinetab2
6.19.10-danctnix1-1 with `CONFIG_NL80211_TESTMODE=y`. Full stack
applied, verified over 3+ reboots: WiFi associates and passes traffic
on both 2.4 GHz (newton / ch11) and 5 GHz (TelekomHotspot@ERGO / ch36).
8a:2e:77:1f:ec:05, LAN AP newton @ 2.4 GHz ch11, tested also on
TelekomHotspot@ERGO @ 5 GHz ch36).
Per-patch outcomes in post-reboot dmesg:
- 1/6: `read and check /lib/firmware/bes2600_factory.txt error` -- gone
- 2/6: `bes2600_factory.txt parse fail` / `factory cali data get failed.` -- gone
- 3/6: `(NULL device *):` prefix on factory lines -- gone
- 4/6: `wait pm ind timeout` (pre-patch 20-30 msgs / 5 min) -- 0 per 5 min;
`sdio_tx_work` WARN splat (pre-patch 2+ / 5 min) -- 0 per 5 min;
`[RX] Receive failure: 4.` -- gone
- 5/6: `/dev/bes2600` -- absent; driver continues to associate
- 6/6: `iw phy0` lists `testmode` under *Supported commands*
Host kernel: linux-pinetab2 6.19.10-danctnix1-1-pinetab2 with
CONFIG_NL80211_TESTMODE=y and CONFIG_KFENCE=y (for 7/7 verification).
Driver installed via /lib/modules/<ver>/extra/ and verified loaded via
modinfo srcversion.
Per-patch outcomes in post-reboot dmesg (full-stack applied, 11+ min
soak, 245k RX packets / 365 MB traffic):
- 1/7: 'read and check /lib/firmware/bes2600_factory.txt error' -- gone
- 2/7: 'bes2600_factory.txt parse fail' / 'factory cali data get
failed.' -- gone
- 3/7: '(NULL device *):' prefix on factory lines -- gone
- 4/7: 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' (pre-patch 20-30
msgs / 5 min window) -- 0 per 5 min; '[RX] Receive failure: 4.' --
gone
- 5/7: /dev/bes2600 -- absent; driver continues to associate
- 6/7: 'iw phy0' lists 'testmode' under Supported commands; module
builds cleanly
- 7/7: 'BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic'
(pre-patch ~65 splats per 4 h of real traffic, always via
sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper+0x18c) -- 0;
'sdio_tx_work+0x2b4' WARN splat residual from 4/7's cascade -- 0
(previously recurred ~1 per reboot even with 4/7 applied);
'PS Mode Error, Reason:1' benign handshake notice at T+40s --
also gone, apparently a downstream effect of no longer DMAing
uninitialised padding bytes into firmware
Full stack: wifi associates and passes traffic across 3+ reboots.
## Known limitations / out of scope
- `factory_section_write_file()` still uses `kernel_write()` + `filp_open()`
for calibration persistence. Conversion to debugfs/nl80211 is a
- factory_section_write_file() in bes2600_factory.c still uses
kernel_write() + filp_open(O_CREAT) to persist per-channel
calibration updates back to /lib/firmware/bes2600_factory.txt.
Converting the write-back path to debugfs or nl80211 testmode is a
follow-up.
- `bes_chardev.c` still contains DPD-to-file read/write paths (gated by
`BES2600_WRITE_DPD_TO_FILE`, off by default -- dead code in default
builds). Same treatment needed.
- `bes_fw.c:587` unconditionally creates
`/lib/firmware/bes2002_fw_write.bin` via `filp_open()` for debug
observation. Must go before a future drivers/net/wireless/st/
promotion.
- `bes_cdev` singleton still holds `sig_mode`/`fw_type`. Migrating
fw_type from module_param to per-phy debugfs knob or nl80211 testmode
is the next architectural step.
- Residual benign dmesg: `bes2600_wlan mmc2:0001:1: PS Mode Error,
Reason:1` at T+40 s on fresh boot. Distinct from the pre-4/6 timeout
cascade; driver recovers, WiFi stays up.
Markus Fritsche (6):
- bes_chardev.c still carries DPD file-read/write paths gated by
BES2600_WRITE_DPD_TO_FILE (off by default, so dead code in the
default build). Same treatment needed.
- bes_fw.c:587 unconditionally creates
/lib/firmware/bes2002_fw_write.bin via filp_open() for debug
observation. Needs to go before drivers/staging/ accepts the driver.
- bes_cdev global singleton still holds sig_mode and fw_type. Moving
those to per-hw_priv state is blocked by fw_type being a module
parameter (inherently singleton). Migrating fw_type to a per-phy
debugfs knob or nl80211 testmode command is the next step; overlaps
with 6/7's testmode plumbing.
Markus Fritsche (7):
bes2600: use request_firmware() for factory.txt read
bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format
bes2600: thread struct device * through factory request_firmware() call
bes2600: gate device LP-mode entry on successful per-VIF firmware handshake
bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2
factory.txt format
bes2600: thread struct device * through factory request_firmware()
call
bes2600: gate device LP-mode entry on successful per-VIF firmware
handshake
bes2600: remove userspace /dev/bes2600 character device interface
bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted testmode plumbing
bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted
testmode plumbing
bes2600: bounce SDIO TX buffers to avoid DMA OOB read
drivers/staging/bes2600/Makefile | 6 +-
drivers/staging/bes2600/bes2600_factory.c | 45 +--
drivers/staging/bes2600/bes2600_factory.c | 45 ++--
drivers/staging/bes2600/bes2600_factory.h | 3 +
drivers/staging/bes2600/bes2600_sdio.c | 4 +
drivers/staging/bes2600/bes_chardev.c | 519 --------------------------------
drivers/staging/bes2600/bes2600_sdio.c | 43 +++-
drivers/staging/bes2600/bes_chardev.c | 519 --------------------------------------
drivers/staging/bes2600/bes_log.h | 23 ++
drivers/staging/bes2600/bes_pwr.c | 20 +-
drivers/staging/bes2600/sta.c | 6 +-
drivers/staging/bes2600/wsm.h | 2 -
9 files changed, 79 insertions(+), 549 deletions(-)
9 files changed, 117 insertions(+), 550 deletions(-)
--
2.53.0
@@ -1,7 +1,10 @@
From 30a51afef7db9c4ce964cfbb2ffd15ed9eeadab0 Mon Sep 17 00:00:00 2001
From d18aa6a9bc03a03e455434f83577892aa1a60ffe Mon Sep 17 00:00:00 2001
Message-ID: <d18aa6a9bc03a03e455434f83577892aa1a60ffe.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 10:09:44 +0200
Subject: [PATCH 1/6] bes2600: use request_firmware() for factory.txt read
Subject: [PATCH 1/7] bes2600: use request_firmware() for factory.txt read
The BES2600 factory calibration file (bes2600_factory.txt) was being read
via filp_open() + kernel_read() from a hard-coded absolute path baked in
@@ -59,11 +62,11 @@ exposed and tracked separately).
Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
---
drivers/staging/bes2600/Makefile | 2 +-
drivers/staging/bes2600/bes2600_factory.c | 33 ++++++++++-------------
drivers/staging/bes2600/bes2600_factory.c | 33 ++++++++++++++-------------------
2 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile
index df5e55d..95b07fa 100644
diff --git a/drivers/staging/bes2600/Makefile b/bes2600/Makefile
index 300912b..788aee2 100644
--- a/drivers/staging/bes2600/Makefile
+++ b/drivers/staging/bes2600/Makefile
@@ -66,7 +66,7 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116
@@ -71,11 +74,11 @@ index df5e55d..95b07fa 100644
FACTORY_CRC_CHECK ?= n
STANDARD_FACTORY_EFUSE_FLAG ?= y
-FACTORY_PATH ?= /lib/firmware/bes2600_factory.txt
+FACTORY_PATH ?= bes2600/bes2600_factory.txt
+FACTORY_PATH ?= drivers/staging/bes2600/bes2600_factory.txt
endif
# basic function
diff --git a/drivers/staging/bes2600/bes2600_factory.c b/drivers/staging/bes2600/bes2600_factory.c
diff --git a/drivers/staging/bes2600/bes2600_factory.c b/bes2600/bes2600_factory.c
index dc5d3da..8d60b7c 100644
--- a/drivers/staging/bes2600/bes2600_factory.c
+++ b/drivers/staging/bes2600/bes2600_factory.c
@@ -1,7 +1,10 @@
From 6cc2efd4dfbb6358e2d458398afcebda4e05ffe6 Mon Sep 17 00:00:00 2001
From a826f4db7d97a3a872d92079db37dbdaf9a0cdec Mon Sep 17 00:00:00 2001
Message-ID: <a826f4db7d97a3a872d92079db37dbdaf9a0cdec.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 12:17:56 +0200
Subject: [PATCH 2/6] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for
Subject: [PATCH 2/7] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for
PineTab2 factory.txt format
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
@@ -23,7 +26,7 @@ The PineTab2 factory.txt has no select_efuse_flag section, so sscanf
stops after field 30 and factory_parse() returns -1 with:
bes2600_factory.txt parse fail
read and check bes2600/bes2600_factory.txt error
read and check drivers/staging/bes2600/bes2600_factory.txt error
factory cali data get failed.
This was latent until the preceding patch (use request_firmware() for
@@ -53,8 +56,8 @@ Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
drivers/staging/bes2600/wsm.h | 2 --
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile
index 95b07fa..4ea2424 100644
diff --git a/drivers/staging/bes2600/Makefile b/bes2600/Makefile
index 788aee2..2dcba09 100644
--- a/drivers/staging/bes2600/Makefile
+++ b/drivers/staging/bes2600/Makefile
@@ -65,7 +65,7 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116
@@ -63,10 +66,10 @@ index 95b07fa..4ea2424 100644
FACTORY_CRC_CHECK ?= n
-STANDARD_FACTORY_EFUSE_FLAG ?= y
+STANDARD_FACTORY_EFUSE_FLAG ?= n
FACTORY_PATH ?= bes2600/bes2600_factory.txt
FACTORY_PATH ?= drivers/staging/bes2600/bes2600_factory.txt
endif
diff --git a/drivers/staging/bes2600/wsm.h b/drivers/staging/bes2600/wsm.h
diff --git a/drivers/staging/bes2600/wsm.h b/bes2600/wsm.h
index 0673131..22845ac 100644
--- a/drivers/staging/bes2600/wsm.h
+++ b/drivers/staging/bes2600/wsm.h
@@ -1,7 +1,10 @@
From cfbbf5d5430925e2175f53f153c482cb17520d6d Mon Sep 17 00:00:00 2001
From c7ba2044b78cc3778763737daea60c9912b710c6 Mon Sep 17 00:00:00 2001
Message-ID: <c7ba2044b78cc3778763737daea60c9912b710c6.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 13:18:38 +0200
Subject: [PATCH 3/6] bes2600: thread struct device * through factory
Subject: [PATCH 3/7] bes2600: thread struct device * through factory
request_firmware() call
Follow-up to \"bes2600: use request_firmware() for factory.txt read\".
@@ -43,7 +46,7 @@ Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
drivers/staging/bes2600/bes2600_sdio.c | 4 ++++
3 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/bes2600/bes2600_factory.c b/drivers/staging/bes2600/bes2600_factory.c
diff --git a/drivers/staging/bes2600/bes2600_factory.c b/bes2600/bes2600_factory.c
index 8d60b7c..1cda447 100644
--- a/drivers/staging/bes2600/bes2600_factory.c
+++ b/drivers/staging/bes2600/bes2600_factory.c
@@ -75,7 +78,7 @@ index 8d60b7c..1cda447 100644
if (ret) {
bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret);
return -1;
diff --git a/drivers/staging/bes2600/bes2600_factory.h b/drivers/staging/bes2600/bes2600_factory.h
diff --git a/drivers/staging/bes2600/bes2600_factory.h b/bes2600/bes2600_factory.h
index 3835b0d..7dbe9f8 100644
--- a/drivers/staging/bes2600/bes2600_factory.h
+++ b/drivers/staging/bes2600/bes2600_factory.h
@@ -89,8 +92,8 @@ index 3835b0d..7dbe9f8 100644
/* read wifi & bt factory cali value*/
u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path);
void factory_little_endian_cvrt(u8 *data);
diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/drivers/staging/bes2600/bes2600_sdio.c
index 13d4ff1..f172d53 100644
diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/bes2600/bes2600_sdio.c
index b595365..371ef4f 100644
--- a/drivers/staging/bes2600/bes2600_sdio.c
+++ b/drivers/staging/bes2600/bes2600_sdio.c
@@ -30,6 +30,7 @@
@@ -1,7 +1,10 @@
From 28a5de5303e72ff0670ee2e3509088c228270829 Mon Sep 17 00:00:00 2001
From 108d3967eac4ba3a6e0f508d865a5f221b49079d Mon Sep 17 00:00:00 2001
Message-ID: <108d3967eac4ba3a6e0f508d865a5f221b49079d.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 12:37:45 +0200
Subject: [PATCH 4/6] bes2600: gate device LP-mode entry on successful per-VIF
Subject: [PATCH 4/7] bes2600: gate device LP-mode entry on successful per-VIF
firmware handshake
bes2600_pwr_enter_lp_mode() drives the transition to low-power for each
@@ -49,7 +52,7 @@ Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
drivers/staging/bes2600/bes_pwr.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/bes2600/bes_pwr.c b/drivers/staging/bes2600/bes_pwr.c
diff --git a/drivers/staging/bes2600/bes_pwr.c b/bes2600/bes_pwr.c
index e7a1045..f62ae22 100644
--- a/drivers/staging/bes2600/bes_pwr.c
+++ b/drivers/staging/bes2600/bes_pwr.c
@@ -1,7 +1,10 @@
From adb2cb22a8189ee6d2de5521e65aed63aebf1d09 Mon Sep 17 00:00:00 2001
From 3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f Mon Sep 17 00:00:00 2001
Message-ID: <3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 13:04:27 +0200
Subject: [PATCH 5/6] bes2600: remove userspace /dev/bes2600 character device
Date: Wed, 22 Apr 2026 12:55:18 +0200
Subject: [PATCH 5/7] bes2600: remove userspace /dev/bes2600 character device
interface
bes_chardev.c implemented a custom character device at /dev/bes2600 with
@@ -73,11 +76,11 @@ Follow-ups:
Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
---
drivers/staging/bes2600/bes_chardev.c | 519 --------------------------
drivers/staging/bes2600/bes_chardev.c | 519 ------------------------------------------
1 file changed, 519 deletions(-)
diff --git a/drivers/staging/bes2600/bes_chardev.c b/drivers/staging/bes2600/bes_chardev.c
index f89dcb8..455108a 100644
diff --git a/drivers/staging/bes2600/bes_chardev.c b/bes2600/bes_chardev.c
index 9038e48..e2e4f1b 100644
--- a/drivers/staging/bes2600/bes_chardev.c
+++ b/drivers/staging/bes2600/bes_chardev.c
@@ -43,12 +43,6 @@ enum bus_probe_state {
@@ -93,9 +96,9 @@ index f89dcb8..455108a 100644
atomic_t num_proc;
wait_queue_head_t open_wq;
spinlock_t status_lock;
@@ -290,351 +284,18 @@ int bes2600_chrdev_switch_subsys_glb(int wifi, int bt)
@@ -249,351 +243,18 @@ int bes2600_switch_bt(bool on)
return ret;
}
EXPORT_SYMBOL_GPL(bes2600_chrdev_switch_subsys_glb);
-static int bes2600_get_cmd_and_ifname(const char *str, char **result)
-{
@@ -119,7 +122,7 @@ index f89dcb8..455108a 100644
- if (!tmp_ptr) {
- return -2;
- }
-
- strncpy(tmp_ptr, str+7, ifname_len);
- tmp_ptr[ifname_len] = '\0';
- result[0] = tmp_ptr;
@@ -150,33 +153,33 @@ index f89dcb8..455108a 100644
-
- return 0;
-}
-
-static void bes2600_recyle_cmd_and_ifname_mem(char **info)
-{
- if (info[0]) {
- kfree(info[0]);
- info[0] = NULL;
- }
-
- if (info[1]) {
- kfree(info[1]);
- info[1] = NULL;
- }
-
-}
-
-static int bes2600_op_default_handler(const char *str)
-{
- char *info[2] = {0};
-
- if (bes2600_get_cmd_and_ifname(str, info) == 0) {
- bes_devel("cmd(%s) on %s not handled\n", info[1], info[0]);
- } else {
- bes_err("%s get command fail, the origin string is %s\n", __func__, str);
- }
-
- bes2600_recyle_cmd_and_ifname_mem(info);
-
- return 0;
-}
-
@@ -344,8 +347,8 @@ index f89dcb8..455108a 100644
- WARN_ON(status <= 0);
-
- ret = (status <= 0 || bes2600_chrdev_is_bus_error()) ? -1 : 0;
-
-
- return ret;
-}
-
@@ -360,7 +363,7 @@ index f89dcb8..455108a 100644
- return -EFAULT;
- }
- spin_unlock(&bes2600_cdev.status_lock);
-
- /* wait probe done event */
- status = wait_event_timeout(bes2600_cdev.probe_done_wq,
- bes2600_bootup_end(), HZ * 8);
@@ -384,26 +387,26 @@ index f89dcb8..455108a 100644
- return -EFAULT;
- }
- spin_unlock(&bes2600_cdev.status_lock);
-
- /* wait probe done event */
- status = wait_event_timeout(bes2600_cdev.probe_done_wq,
- bes2600_bootup_end(), HZ * 8);
- if (status <= 0 || bes2600_chrdev_is_bus_error())
- return -EFAULT;
-
- bes_devel("bes2600 allow bt sleep.\n");
- ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_OFF, SUBSYSTEM_BT_LP, false);
-
- return ret;
-}
-
-static int bes2600_op_set_wakeup_read_flag(const char *str)
-{
- bes_devel("%s is called, arg:%s\n", __func__, str);
- spin_lock(&bes2600_cdev.status_lock);
- bes2600_cdev.read_flag = BES_CDEV_READ_WAKEUP_STATE;
- spin_unlock(&bes2600_cdev.status_lock);
-
- return 0;
-}
@@ -445,7 +448,7 @@ index f89dcb8..455108a 100644
static int bes2600_chrdev_check_system_close_internal(void)
{
@@ -644,123 +305,10 @@ static int bes2600_chrdev_check_system_close_internal(void)
@@ -603,123 +264,10 @@ static int bes2600_chrdev_check_system_close_internal(void)
&& (bes2600_cdev.wifi_opened == false);
}
@@ -456,20 +459,20 @@ index f89dcb8..455108a 100644
- (atomic_read(&bes2600_cdev.num_proc) == 0),
- MAX_SCHEDULE_TIMEOUT);
- }
-
- bes_devel("bes2600 char device is opened\n");
- atomic_inc(&bes2600_cdev.num_proc);
-
- return 0;
-}
-
-static ssize_t bes2600_chrdev_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[64] = {0};
- unsigned int len;
- long status = 0;
-
- switch (bes2600_cdev.read_flag) {
- case BES_CDEV_READ_WAKEUP_STATE:
- if (bes2600_chrdev_wakeup_by_event_get() > WAKEUP_EVENT_NONE) {
@@ -546,18 +549,18 @@ index f89dcb8..455108a 100644
-
- return (ret == 0) ? count : ret;
-}
-
-static int bes2600_chrdev_release (struct inode *inode, struct file *file)
-{
- if (atomic_dec_and_test(&bes2600_cdev.num_proc)) {
- wake_up(&bes2600_cdev.open_wq);
- }
-
- bes_devel("bes2600 char device is closed\n");
-
- return 0;
-}
-
-static struct file_operations bes2600_chardev_fops =
-{
- .owner = THIS_MODULE,
@@ -569,7 +572,7 @@ index f89dcb8..455108a 100644
#ifdef BES2600_WRITE_DPD_TO_FILE
static int bes2600_chrdev_write_dpd_data_to_file(const char *path, void *buffer, int size)
@@ -1167,12 +715,6 @@ void bes2600_chrdev_update_signal_mode(void)
@@ -1124,12 +672,6 @@ void bes2600_chrdev_update_signal_mode(void)
static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work)
{
@@ -582,7 +585,7 @@ index f89dcb8..455108a 100644
if (bes2600_chrdev_is_wifi_opened()) {
bes_devel("system exeception, force wifi down\n");
@@ -1189,14 +731,6 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work)
@@ -1146,14 +688,6 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work)
bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops,
bes2600_cdev.sbus_priv);
}
@@ -597,7 +600,7 @@ index f89dcb8..455108a 100644
}
}
@@ -1290,46 +824,6 @@ int bes2600_chrdev_wakeup_by_event_get(void)
@@ -1247,46 +781,6 @@ int bes2600_chrdev_wakeup_by_event_get(void)
int bes2600_chrdev_init(struct sbus_ops *ops)
{
@@ -644,7 +647,7 @@ index f89dcb8..455108a 100644
/* initialise global variable */
atomic_set(&bes2600_cdev.num_proc, 0);
init_waitqueue_head(&bes2600_cdev.open_wq);
@@ -1361,15 +855,6 @@ int bes2600_chrdev_init(struct sbus_ops *ops)
@@ -1318,15 +812,6 @@ int bes2600_chrdev_init(struct sbus_ops *ops)
bes_devel("%s done\n", __func__);
return 0;
@@ -660,7 +663,7 @@ index f89dcb8..455108a 100644
}
void bes2600_chrdev_free(void)
@@ -1379,9 +864,5 @@ void bes2600_chrdev_free(void)
@@ -1336,9 +821,5 @@ void bes2600_chrdev_free(void)
bes2600_free_dpd_log_buffer();
#endif
bes2600_chrdev_free_dpd_data();
@@ -1,7 +1,10 @@
From f1d22ab91dbc0d12064f672300fec5ec0ff220e3 Mon Sep 17 00:00:00 2001
From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001
Message-ID: <6f13e008d21d453db486f707f47340a0a17e650b.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 14:26:43 +0200
Subject: [PATCH 6/6] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix
Date: Wed, 22 Apr 2026 13:04:27 +0200
Subject: [PATCH 6/7] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix
bit-rotted testmode plumbing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
@@ -63,11 +66,11 @@ Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
drivers/staging/bes2600/sta.c | 6 +++---
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile
index 4ea2424..aecb302 100644
diff --git a/drivers/staging/bes2600/Makefile b/bes2600/Makefile
index 2dcba09..2c1a850 100644
--- a/drivers/staging/bes2600/Makefile
+++ b/drivers/staging/bes2600/Makefile
@@ -2,7 +2,7 @@ KERN_DIR = /lib/modules/$(shell uname -r)/build
@@ -2,7 +2,7 @@ KERN_DIR = /lib/modules/$(KERNELRELEASE)/build
# feature option
BES2600 ?= m
@@ -76,7 +79,7 @@ index 4ea2424..aecb302 100644
CONFIG_BES2600_ENABLE_DEVEL_LOGS ?= n
diff --git a/drivers/staging/bes2600/bes_log.h b/drivers/staging/bes2600/bes_log.h
diff --git a/drivers/staging/bes2600/bes_log.h b/bes2600/bes_log.h
index 605cea8..65cf703 100644
--- a/drivers/staging/bes2600/bes_log.h
+++ b/drivers/staging/bes2600/bes_log.h
@@ -107,11 +110,11 @@ index 605cea8..65cf703 100644
+ if (_cond) \
+ bes_err(fmt, ##__VA_ARGS__); \
+ } while (0)
diff --git a/drivers/staging/bes2600/sta.c b/drivers/staging/bes2600/sta.c
index ca1c77c..bc6d483 100644
diff --git a/drivers/staging/bes2600/sta.c b/bes2600/sta.c
index aa69eb8..5f1a456 100644
--- a/drivers/staging/bes2600/sta.c
+++ b/drivers/staging/bes2600/sta.c
@@ -3654,7 +3654,7 @@ static int bes2600_set_power_save(struct ieee80211_hw *hw,
@@ -3633,7 +3633,7 @@ static int bes2600_set_power_save(struct ieee80211_hw *hw,
*
* Returns: 0 on success or non zero value on failure
*/
@@ -120,7 +123,7 @@ index ca1c77c..bc6d483 100644
{
struct bes_msg_start_stop_tsm *start_stop_tsm =
(struct bes_msg_start_stop_tsm *) data;
@@ -3684,7 +3684,7 @@ int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data)
@@ -3663,7 +3663,7 @@ int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data)
*
* Returns: TSM parameters collected
*/
@@ -129,7 +132,7 @@ index ca1c77c..bc6d483 100644
{
struct bes2600_common *hw_priv = hw->priv;
struct bes_tsm_stats tsm_stats;
@@ -3724,7 +3724,7 @@ int bes2600_get_tsm_params(struct ieee80211_hw *hw)
@@ -3703,7 +3703,7 @@ int bes2600_get_tsm_params(struct ieee80211_hw *hw)
*
* Returns: Returns the last measured roam delay
*/
@@ -0,0 +1,126 @@
From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001
Message-ID: <10a05d21bfe4563f963e16d65228fd7a713c143d.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Thu, 23 Apr 2026 11:58:31 +0200
Subject: [PATCH 7/7] bes2600: bounce SDIO TX buffers to avoid DMA OOB read
The SDIO TX path rounds the DMA transfer length up to the host's
current block size and hands that length to dma_map_sg() via
sg_set_buf(&sg[scatters], tx_buffer->buf, align) in sdio_tx_work().
tx_buffer->buf typically aliases into an skb linear head whose
allocated size matches tx_buffer->len, not the block-aligned
align. The DMA engine (swiotlb / dw_mci IDMAC) therefore reads up
to one block past the end of the skb. On a PineTab2 with KFENCE
enabled this fires as:
BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic
Out-of-bounds read at ... (704B right of kfence-#...):
__pi_memcpy_generic
swiotlb_tbl_map_single
swiotlb_map
dma_direct_map_sg
__dma_map_sg_attrs
dma_map_sg_attrs
dw_mci_pre_dma_transfer
__dw_mci_start_request
...
bes_sdio_memcpy_to_io_helper+0x18c/0x288 [bes2600]
sdio_tx_work+0x2b4/0x4a0 [bes2600]
allocated by ... pskb_expand_head / validate_xmit_skb / tcp_*
In addition to being undefined behavior, the padding bytes (which
come from whatever memory follows the skb) are transmitted to the
peer, leaking kernel memory on the air.
Allocate a driver-owned DMA-page bounce buffer sized to
MAX_SDIO_TRANSFER_LEN and use it as the scatter-gather backing for
sdio_tx_work. Each TX buffer is copied into its bounce slot and the
tail (align - tx_buffer->len bytes) is zeroed. This mirrors the
existing bounce pattern already used by bes2600_sdio_memcpy_toio()
via single_gathered_buffer; a separate allocation is used for the
TX path because single_gathered_buffer is only serialised via
sdio_claim_host and sdio_tx_work accumulates scatter entries before
claiming the bus.
Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
---
drivers/staging/bes2600/bes2600_sdio.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/bes2600/bes2600_sdio.c
index 371ef4f..3e04e8c 100644
--- a/drivers/staging/bes2600/bes2600_sdio.c
+++ b/drivers/staging/bes2600/bes2600_sdio.c
@@ -95,6 +95,7 @@ struct sbus_priv {
struct work_struct tx_work;
struct scatterlist tx_sg[BES_SDIO_TX_MULTIPLE_NUM + 1];
struct scatterlist tx_sg_nosignal[BES_SDIO_TX_MULTIPLE_NUM_NOSIGNAL + 1];
+ u8 *tx_bounce;
u32 tx_data_cnt;
u32 tx_xfer_cnt;
u32 tx_proc_cnt;
@@ -1136,7 +1137,26 @@ static void sdio_tx_work(struct work_struct *work)
}
}
- sg_set_buf(&sg[scatters], tx_buffer->buf, align);
+ /*
+ * The transfer length is rounded up to the SDIO block
+ * size, but tx_buffer->buf is only tx_buffer->len bytes
+ * long (it usually aliases into an skb linear head).
+ * Copy into a driver-owned bounce buffer and zero-pad
+ * to the aligned size; otherwise DMA reads past the
+ * skb and leaks adjacent kernel memory on the wire --
+ * observed as KFENCE OOB reads from
+ * bes_sdio_memcpy_to_io_helper via dma_map_sg.
+ */
+ if (WARN_ON_ONCE(total_len + align > MAX_SDIO_TRANSFER_LEN))
+ goto flush_previous;
+ memcpy(self->tx_bounce + total_len,
+ tx_buffer->buf, tx_buffer->len);
+ if (align > tx_buffer->len)
+ memset(self->tx_bounce + total_len +
+ tx_buffer->len, 0,
+ align - tx_buffer->len);
+ sg_set_buf(&sg[scatters],
+ self->tx_bounce + total_len, align);
total_len += align;
++scatters;
/*del_node:*/
@@ -1857,6 +1877,17 @@ static int bes2600_sdio_probe(struct sdio_func *func,
if (!self->single_gathered_buffer)
return -ENOMEM;
#endif
+#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
+ self->tx_bounce = (u8 *)__get_dma_pages(GFP_KERNEL,
+ get_order(MAX_SDIO_TRANSFER_LEN));
+ if (!self->tx_bounce) {
+#ifndef SDIO_HOST_ADMA_SUPPORT
+ free_pages((unsigned long)self->single_gathered_buffer,
+ get_order(MAX_SDIO_TRANSFER_LEN));
+#endif
+ return -ENOMEM;
+ }
+#endif
#ifdef BES_SDIO_RXTX_TOGGLE
self->fw_started = false;
#endif
@@ -1985,6 +2016,12 @@ static void bes2600_sdio_remove(struct sdio_func *func)
if (self->single_gathered_buffer) {
free_pages((unsigned long)self->single_gathered_buffer, get_order(MAX_SDIO_TRANSFER_LEN));
}
+#endif
+#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
+ if (self->tx_bounce) {
+ free_pages((unsigned long)self->tx_bounce,
+ get_order(MAX_SDIO_TRANSFER_LEN));
+ }
#endif
kfree(self);
}
--
2.53.0
@@ -1,7 +1,11 @@
From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001
From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001
Message-ID: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 14:15:56 +0200
Subject: [PATCH 0/6] bes2600: staging-prep cleanup for PineTab2 (BES2600WM)
Date: Thu, 23 Apr 2026 12:35:28 +0200
Subject: [PATCH 0/7] bes2600: staging-prep cleanup for PineTab2 (BES2600WM)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This series is a staging-prep cleanup for the out-of-tree Bestechnic
BES2600WM Wi-Fi/BT combo-chip driver as shipped by Mobian's bes2600-dkms
@@ -24,14 +28,14 @@ dependencies.
## What the series does
* 1/6 -- Replace filp_open() + kernel_read() in the factory-calibration
* 1/7 -- Replace filp_open() + kernel_read() in the factory-calibration
read path with request_firmware(). Repoint the FACTORY_PATH macro to
the firmware-class name (bes2600/bes2600_factory.txt, matching the
/lib/firmware/ layout). Kills a kernel-mainline anti-pattern and the
'(NULL device *): read and check /lib/firmware/bes2600_factory.txt
error' boot spam on PineTab2.
* 2/6 -- Default STANDARD_FACTORY_EFUSE_FLAG from y to n. The shipped
* 2/7 -- Default STANDARD_FACTORY_EFUSE_FLAG from y to n. The shipped
bes2600_factory.txt on PineTab2 contains 30 calibration fields; the
driver was expecting 31 (including a ##select_efuse_flag section
absent from this firmware). Also unguards the
@@ -41,12 +45,12 @@ dependencies.
ungated -- gcc -Werror=missing-prototypes broke the build with the
new default until this is fixed.
* 3/6 -- Thread struct device * through factory_section_read_file() via
* 3/7 -- Thread struct device * through factory_section_read_file() via
a module-local setter invoked at SDIO probe. request_firmware() now
receives a real device pointer; '(NULL device *):' no longer prefixes
factory-related diagnostics.
* 4/6 -- Gate the device-end of the low-power transition on successful
* 4/7 -- Gate the device-end of the low-power transition on successful
per-VIF firmware handshake. Pre-patch bes2600_pwr_enter_lp_mode()
called bes2600_pwr_device_enter_lp_mode() unconditionally even when
wait_for_completion_timeout() returned 0 (firmware never posted the
@@ -56,7 +60,7 @@ dependencies.
messages. Post-patch: -ETIMEDOUT returned cleanly, dmesg silent,
SDIO stable.
* 5/6 -- Remove the custom /dev/bes2600 character-device interface.
* 5/7 -- Remove the custom /dev/bes2600 character-device interface.
file_operations, open/read/write/release, bes2600_op_*
command-dispatch table, bes2600_load_uevent, alloc_chrdev_region /
cdev_init / cdev_add / class_create / device_create in the init
@@ -64,9 +68,9 @@ dependencies.
deleted. The in-kernel accessor functions (is_signal_mode,
get_fw_type, etc., 13 call sites) and the fw_type module parameter
are preserved; the userspace interface becomes rfkill + module_param
+ (with 6/6) nl80211 testmode.
+ (with 6/7) nl80211 testmode.
* 6/6 -- Flip CONFIG_BES2600_TESTMODE default from n to y. The driver
* 6/7 -- Flip CONFIG_BES2600_TESTMODE default from n to y. The driver
already implements a mac80211 testmode_cmd dispatcher (routing to
the firmware's patch_wifi_testMode path), already gated on the flag;
CONFIG_NL80211_TESTMODE=y is common on target kernels. Enabling the
@@ -77,6 +81,25 @@ dependencies.
bes_err / bes_warn / bes_devel family, define BES2600_DBG_* subsystem
ids as 0 constants, and mark the 3 helpers static.
* 7/7 -- Bounce SDIO TX buffers to avoid DMA out-of-bounds reads.
sdio_tx_work() rounded the transfer length up to the SDIO block size
(align = blks * cur_blksize, or 1632) and handed that length to
dma_map_sg() via sg_set_buf(..., tx_buffer->buf, align); tx_buffer->buf
typically aliases into an skb linear head allocated to tx_buffer->len,
not the block-aligned length. The DMA engine therefore read up to one
block past the end of the skb -- KFENCE on PineTab2 fires as
'out-of-bounds read in __pi_memcpy_generic ... 704B right of
kfence-#...' with sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper in
the stack and pskb_expand_head / validate_xmit_skb / tcp_write_xmit in
the allocator stack. Besides being undefined behavior, the padding
bytes are transmitted to the peer, leaking adjacent kernel memory on
the air. Allocate a driver-owned DMA-pages bounce buffer of
MAX_SDIO_TRANSFER_LEN, memcpy each TX buffer into its slot, zero the
padding tail, and point the SG entries at the bounce. Mirrors the
pattern already used for single_gathered_buffer; kept as a separate
allocation because sdio_tx_work accumulates SG entries before claiming
the bus.
## Testing
Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566,
@@ -84,21 +107,31 @@ Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566,
TelekomHotspot@ERGO @ 5 GHz ch36).
Host kernel: linux-pinetab2 6.19.10-danctnix1-1-pinetab2 with
CONFIG_NL80211_TESTMODE=y. Driver installed via
/lib/modules/<ver>/extra/ and verified loaded via modinfo srcversion.
CONFIG_NL80211_TESTMODE=y and CONFIG_KFENCE=y (for 7/7 verification).
Driver installed via /lib/modules/<ver>/extra/ and verified loaded via
modinfo srcversion.
Per-patch outcomes in post-reboot dmesg (full-stack applied):
- 1/6: 'read and check /lib/firmware/bes2600_factory.txt error' -- gone
- 2/6: 'bes2600_factory.txt parse fail' / 'factory cali data get
Per-patch outcomes in post-reboot dmesg (full-stack applied, 11+ min
soak, 245k RX packets / 365 MB traffic):
- 1/7: 'read and check /lib/firmware/bes2600_factory.txt error' -- gone
- 2/7: 'bes2600_factory.txt parse fail' / 'factory cali data get
failed.' -- gone
- 3/6: '(NULL device *):' prefix on factory lines -- gone
- 4/6: 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' (pre-patch 20-30
msgs / 5 min window) -- 0 per 5 min; 'sdio_tx_work' WARN splat
(pre-patch 2+ / 5 min) -- 0 per 5 min; '[RX] Receive failure: 4.' --
- 3/7: '(NULL device *):' prefix on factory lines -- gone
- 4/7: 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' (pre-patch 20-30
msgs / 5 min window) -- 0 per 5 min; '[RX] Receive failure: 4.' --
gone
- 5/6: /dev/bes2600 -- absent; driver continues to associate
- 6/6: 'iw phy0' lists 'testmode' under Supported commands; module
- 5/7: /dev/bes2600 -- absent; driver continues to associate
- 6/7: 'iw phy0' lists 'testmode' under Supported commands; module
builds cleanly
- 7/7: 'BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic'
(pre-patch ~65 splats per 4 h of real traffic, always via
sdio_tx_work+0x2b4 / bes_sdio_memcpy_to_io_helper+0x18c) -- 0;
'sdio_tx_work+0x2b4' WARN splat residual from 4/7's cascade -- 0
(previously recurred ~1 per reboot even with 4/7 applied);
'PS Mode Error, Reason:1' benign handshake notice at T+40s --
also gone, apparently a downstream effect of no longer DMAing
uninitialised padding bytes into firmware
Full stack: wifi associates and passes traffic across 3+ reboots.
@@ -122,14 +155,9 @@ Full stack: wifi associates and passes traffic across 3+ reboots.
those to per-hw_priv state is blocked by fw_type being a module
parameter (inherently singleton). Migrating fw_type to a per-phy
debugfs knob or nl80211 testmode command is the next step; overlaps
with 6/6's testmode plumbing.
with 6/7's testmode plumbing.
- One residual benign 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-4/6 timeout cascade; driver recovers, WiFi
stays up. Root cause not investigated.
Markus Fritsche (6):
Markus Fritsche (7):
bes2600: use request_firmware() for factory.txt read
bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2
factory.txt format
@@ -140,17 +168,18 @@ Markus Fritsche (6):
bes2600: remove userspace /dev/bes2600 character device interface
bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted
testmode plumbing
bes2600: bounce SDIO TX buffers to avoid DMA OOB read
bes2600/Makefile | 6 +-
bes2600/bes2600_factory.c | 45 ++--
bes2600/bes2600_factory.h | 3 +
bes2600/bes2600_sdio.c | 4 +
bes2600/bes2600_sdio.c | 43 +++-
bes2600/bes_chardev.c | 519 --------------------------------------
bes2600/bes_log.h | 23 ++
bes2600/bes_pwr.c | 20 +-
bes2600/sta.c | 6 +-
bes2600/wsm.h | 2 -
9 files changed, 79 insertions(+), 549 deletions(-)
9 files changed, 117 insertions(+), 550 deletions(-)
--
2.53.0
@@ -1,7 +1,10 @@
From d18aa6a9bc03a03e455434f83577892aa1a60ffe Mon Sep 17 00:00:00 2001
Message-ID: <d18aa6a9bc03a03e455434f83577892aa1a60ffe.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 10:09:44 +0200
Subject: [PATCH 1/6] bes2600: use request_firmware() for factory.txt read
Subject: [PATCH 1/7] bes2600: use request_firmware() for factory.txt read
The BES2600 factory calibration file (bes2600_factory.txt) was being read
via filp_open() + kernel_read() from a hard-coded absolute path baked in
@@ -1,7 +1,10 @@
From a826f4db7d97a3a872d92079db37dbdaf9a0cdec Mon Sep 17 00:00:00 2001
Message-ID: <a826f4db7d97a3a872d92079db37dbdaf9a0cdec.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 12:17:56 +0200
Subject: [PATCH 2/6] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for
Subject: [PATCH 2/7] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for
PineTab2 factory.txt format
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
@@ -1,7 +1,10 @@
From c7ba2044b78cc3778763737daea60c9912b710c6 Mon Sep 17 00:00:00 2001
Message-ID: <c7ba2044b78cc3778763737daea60c9912b710c6.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 13:18:38 +0200
Subject: [PATCH 3/6] bes2600: thread struct device * through factory
Subject: [PATCH 3/7] bes2600: thread struct device * through factory
request_firmware() call
Follow-up to \"bes2600: use request_firmware() for factory.txt read\".
@@ -1,7 +1,10 @@
From 108d3967eac4ba3a6e0f508d865a5f221b49079d Mon Sep 17 00:00:00 2001
Message-ID: <108d3967eac4ba3a6e0f508d865a5f221b49079d.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 12:37:45 +0200
Subject: [PATCH 4/6] bes2600: gate device LP-mode entry on successful per-VIF
Subject: [PATCH 4/7] bes2600: gate device LP-mode entry on successful per-VIF
firmware handshake
bes2600_pwr_enter_lp_mode() drives the transition to low-power for each
@@ -1,7 +1,10 @@
From 3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f Mon Sep 17 00:00:00 2001
Message-ID: <3304b13a2b2e7388ebf076c2bcb7f02cd0b6800f.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 12:55:18 +0200
Subject: [PATCH 5/6] bes2600: remove userspace /dev/bes2600 character device
Subject: [PATCH 5/7] bes2600: remove userspace /dev/bes2600 character device
interface
bes_chardev.c implemented a custom character device at /dev/bes2600 with
@@ -1,7 +1,10 @@
From 6f13e008d21d453db486f707f47340a0a17e650b Mon Sep 17 00:00:00 2001
Message-ID: <6f13e008d21d453db486f707f47340a0a17e650b.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Wed, 22 Apr 2026 13:04:27 +0200
Subject: [PATCH 6/6] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix
Subject: [PATCH 6/7] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix
bit-rotted testmode plumbing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
@@ -0,0 +1,126 @@
From 10a05d21bfe4563f963e16d65228fd7a713c143d Mon Sep 17 00:00:00 2001
Message-ID: <10a05d21bfe4563f963e16d65228fd7a713c143d.1776940528.git.fritsche.markus@gmail.com>
In-Reply-To: <cover.1776940528.git.fritsche.markus@gmail.com>
References: <cover.1776940528.git.fritsche.markus@gmail.com>
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Thu, 23 Apr 2026 11:58:31 +0200
Subject: [PATCH 7/7] bes2600: bounce SDIO TX buffers to avoid DMA OOB read
The SDIO TX path rounds the DMA transfer length up to the host's
current block size and hands that length to dma_map_sg() via
sg_set_buf(&sg[scatters], tx_buffer->buf, align) in sdio_tx_work().
tx_buffer->buf typically aliases into an skb linear head whose
allocated size matches tx_buffer->len, not the block-aligned
align. The DMA engine (swiotlb / dw_mci IDMAC) therefore reads up
to one block past the end of the skb. On a PineTab2 with KFENCE
enabled this fires as:
BUG: KFENCE: out-of-bounds read in __pi_memcpy_generic
Out-of-bounds read at ... (704B right of kfence-#...):
__pi_memcpy_generic
swiotlb_tbl_map_single
swiotlb_map
dma_direct_map_sg
__dma_map_sg_attrs
dma_map_sg_attrs
dw_mci_pre_dma_transfer
__dw_mci_start_request
...
bes_sdio_memcpy_to_io_helper+0x18c/0x288 [bes2600]
sdio_tx_work+0x2b4/0x4a0 [bes2600]
allocated by ... pskb_expand_head / validate_xmit_skb / tcp_*
In addition to being undefined behavior, the padding bytes (which
come from whatever memory follows the skb) are transmitted to the
peer, leaking kernel memory on the air.
Allocate a driver-owned DMA-page bounce buffer sized to
MAX_SDIO_TRANSFER_LEN and use it as the scatter-gather backing for
sdio_tx_work. Each TX buffer is copied into its bounce slot and the
tail (align - tx_buffer->len bytes) is zeroed. This mirrors the
existing bounce pattern already used by bes2600_sdio_memcpy_toio()
via single_gathered_buffer; a separate allocation is used for the
TX path because single_gathered_buffer is only serialised via
sdio_claim_host and sdio_tx_work accumulates scatter entries before
claiming the bus.
Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
---
bes2600/bes2600_sdio.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/bes2600/bes2600_sdio.c b/bes2600/bes2600_sdio.c
index 371ef4f..3e04e8c 100644
--- a/bes2600/bes2600_sdio.c
+++ b/bes2600/bes2600_sdio.c
@@ -95,6 +95,7 @@ struct sbus_priv {
struct work_struct tx_work;
struct scatterlist tx_sg[BES_SDIO_TX_MULTIPLE_NUM + 1];
struct scatterlist tx_sg_nosignal[BES_SDIO_TX_MULTIPLE_NUM_NOSIGNAL + 1];
+ u8 *tx_bounce;
u32 tx_data_cnt;
u32 tx_xfer_cnt;
u32 tx_proc_cnt;
@@ -1136,7 +1137,26 @@ static void sdio_tx_work(struct work_struct *work)
}
}
- sg_set_buf(&sg[scatters], tx_buffer->buf, align);
+ /*
+ * The transfer length is rounded up to the SDIO block
+ * size, but tx_buffer->buf is only tx_buffer->len bytes
+ * long (it usually aliases into an skb linear head).
+ * Copy into a driver-owned bounce buffer and zero-pad
+ * to the aligned size; otherwise DMA reads past the
+ * skb and leaks adjacent kernel memory on the wire --
+ * observed as KFENCE OOB reads from
+ * bes_sdio_memcpy_to_io_helper via dma_map_sg.
+ */
+ if (WARN_ON_ONCE(total_len + align > MAX_SDIO_TRANSFER_LEN))
+ goto flush_previous;
+ memcpy(self->tx_bounce + total_len,
+ tx_buffer->buf, tx_buffer->len);
+ if (align > tx_buffer->len)
+ memset(self->tx_bounce + total_len +
+ tx_buffer->len, 0,
+ align - tx_buffer->len);
+ sg_set_buf(&sg[scatters],
+ self->tx_bounce + total_len, align);
total_len += align;
++scatters;
/*del_node:*/
@@ -1857,6 +1877,17 @@ static int bes2600_sdio_probe(struct sdio_func *func,
if (!self->single_gathered_buffer)
return -ENOMEM;
#endif
+#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
+ self->tx_bounce = (u8 *)__get_dma_pages(GFP_KERNEL,
+ get_order(MAX_SDIO_TRANSFER_LEN));
+ if (!self->tx_bounce) {
+#ifndef SDIO_HOST_ADMA_SUPPORT
+ free_pages((unsigned long)self->single_gathered_buffer,
+ get_order(MAX_SDIO_TRANSFER_LEN));
+#endif
+ return -ENOMEM;
+ }
+#endif
#ifdef BES_SDIO_RXTX_TOGGLE
self->fw_started = false;
#endif
@@ -1985,6 +2016,12 @@ static void bes2600_sdio_remove(struct sdio_func *func)
if (self->single_gathered_buffer) {
free_pages((unsigned long)self->single_gathered_buffer, get_order(MAX_SDIO_TRANSFER_LEN));
}
+#endif
+#ifdef BES_SDIO_TX_MULTIPLE_ENABLE
+ if (self->tx_bounce) {
+ free_pages((unsigned long)self->tx_bounce,
+ get_order(MAX_SDIO_TRANSFER_LEN));
+ }
#endif
kfree(self);
}
--
2.53.0