Skip to content

src/cyw43_ctrl: Lock the bus across BT HCI read/write#153

Open
beriberikix wants to merge 1 commit into
georgerobotics:mainfrom
beriberikix:bt-hci-thread-lock
Open

src/cyw43_ctrl: Lock the bus across BT HCI read/write#153
beriberikix wants to merge 1 commit into
georgerobotics:mainfrom
beriberikix:bt-hci-thread-lock

Conversation

@beriberikix

Copy link
Copy Markdown

What

cyw43_bluetooth_hci_read() and cyw43_bluetooth_hci_write() call cyw43_btbus_read() / cyw43_btbus_write() without holding the cyw43 bus lock. The BT shared bus runs over the same gSPI/SDIO backplane as WiFi, so a caller that does not already serialise against WiFi will interleave WiFi and BT transfers on the bus.

This change takes CYW43_THREAD_ENTER across the whole transfer so the two functions are self-serialising.

Why

The btstack HCI transport in pico-sdk happens to wrap these calls in CYW43_THREAD_ENTER/CYW43_THREAD_EXIT itself (btstack_hci_transport_cyw43.c), so the stock pico-sdk + BTstack path is unaffected by this change. But any other consumer that calls the BT HCI API directly — a non-btstack integration, or a multi-threaded port where WiFi and BT run on separate threads — is left unprotected and can interleave bus transfers.

The lock is recursive, so the existing wrapping in the btstack transport and the nested cyw43_ensure_bt_up() continue to work unchanged. Behaviour is identical on the happy path; this only adds serialisation for direct callers.

Context

This came out of a downstream Zephyr WiFi+BLE coexistence effort on the CYW43439 (gSPI), where WiFi and BT run as separate threads. The missing lock here let BT HCI transfers race the WiFi poll thread on the shared bus. Discussion and a related transport-robustness fix (re-read of transiently corrupt ring indices) are in raspberrypi/pico-sdk#3027; the broader effort is tracked in the Zephyr RFC zephyrproject-rtos/zephyr#111811.

Suggested by @peterharperuk in raspberrypi/pico-sdk#3027.

Testing

Builds clean under the repo host tests (tests/sdio compiles cyw43_ctrl.c) and -Werror -fsyntax-only with CYW43_ENABLE_BLUETOOTH=1. Functionally verified on hardware (Pico 2 W) as part of the Zephyr coex port: with the bus held across BT transfers, WiFi+BLE ran a 2-hour soak with zero faults.

cyw43_bluetooth_hci_read() and cyw43_bluetooth_hci_write() call
cyw43_btbus_read()/cyw43_btbus_write() without holding the cyw43 bus
lock. The BT shared bus runs over the same gSPI/SDIO backplane as WiFi,
so a caller that does not already serialise against WiFi will interleave
WiFi and BT transfers on the bus.

The btstack HCI transport in pico-sdk already wraps these calls in
CYW43_THREAD_ENTER/EXIT, so it is unaffected. But any other consumer
that calls the BT HCI API directly (e.g. a non-btstack or multi-threaded
port) is left unprotected. Take CYW43_THREAD_ENTER across the whole
transfer so the functions are self-serialising. The lock is recursive,
so the existing wrapping in the btstack transport and the nested
cyw43_ensure_bt_up() continue to work unchanged.

Signed-off-by: Jonathan Beri <jmberi@gmail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@beriberikix

Copy link
Copy Markdown
Author

Smoke-tested on a Pico 2 W (RP2350): a patched georgerobotics-backend build brings up BT over the HCI path (reads the controller's BD_ADDR + HCI/LMP version through cyw43_bluetooth_hci_read/write) and holds a 60s BLE notification stream — 560 notifications @ 9.3/s, 0 stalls, no unexpected disconnect — under concurrent bidirectional WiFi load (host↔device pinging). The board stayed alive afterward (shell + WiFi responsive, no fault/assert).

This exercises the recursive-lock nesting on real silicon (the BT HCI caller already holds the bus lock, so the added CYW43_THREAD_ENTER nests); behaviour is unchanged on the happy path.

@peterharperuk

Copy link
Copy Markdown
Collaborator

looks good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants