Skip to content

raspberrypi: keep core1's mutex-contention wait path out of flash#11120

Open
mikeysklar wants to merge 1 commit into
adafruit:mainfrom
mikeysklar:core1-ram-mutex-path
Open

raspberrypi: keep core1's mutex-contention wait path out of flash#11120
mikeysklar wants to merge 1 commit into
adafruit:mainfrom
mikeysklar:core1-ram-mutex-path

Conversation

@mikeysklar

Copy link
Copy Markdown
Collaborator

Fixes #11116, the last bug found by the checker in #11115.

When core1 posts a USB event while core0 holds the TinyUSB queue mutex, core1 falls into the pico-sdk blocking wait, which lived in flash. Core1 cannot run flash code, so one contended moment hard faults core1 and USB host goes silent.

Fix: on USB host builds only, --wrap the two flash functions on that path (best_effort_wfe_or_timeout, time_us_64) with RAM implementations in usb_host/Port.c. The best_effort replacement is the SDK's own documented no-alarm-pool fallback (poll the clock, early return allowed), so nothing else gets dragged into RAM. Also moves the 50-byte __aeabi_lmul helper to RAM next to divider.o in the linker scripts, since the SDK already wraps that symbol.

Cost: +64 bytes RAM on USB host builds, 50 bytes otherwise (measured on Pico: 70320 -> 70384). Earlier drafts of this fix cost 1.2-3.4 kB on every board; --wrap was chosen because this port already uses it for 150+ libgcc symbols and the shims are tiny and contract-stable.

With this, the #11115 checker passes on Feather RP2040 USB Host, Fruit Jam, and Pico builds, so every known core1 flash hazard is fixed and the checker can become a CI gate. Smoke tested on the Feather: 20 SCSI read/write cycles to a flash drive.

When core1 posts a USB event while core0 holds the TinyUSB queue mutex,
core1 falls into the pico-sdk blocking wait, which lived in flash.
Core1 cannot execute from flash, so a contended moment hard faults
core1 and USB host goes silent. Fixes adafruit#11116.

On USB host builds only, --wrap best_effort_wfe_or_timeout and
time_us_64 with RAM-resident implementations in usb_host/Port.c. The
best_effort replacement mirrors the SDK's own documented
PICO_TIME_DEFAULT_ALARM_POOL_DISABLED fallback (poll the clock, allow
early return), so no alarm pool machinery is pulled into RAM. The
time_us_64 replacement keeps the SDK's hi/lo/hi rollover re-read loop.

Also RAM-place pico_int64_ops_aeabi.o (50 bytes) next to divider.o in
the linker scripts: mutex_enter_timeout_ms multiplies ms to us through
__aeabi_lmul, and the SDK already wraps that symbol so it cannot be
wrapped again per-feature.

Cost: +64 bytes RAM on USB host builds, 50 bytes on builds with
CIRCUITPY_USB_HOST=0 (Pico baseline 70320 -> 70384). The previous
approach in this branch cost 1216 bytes on every build.

With this, the core1 flash-call checker (adafruit#11115) passes on Feather
RP2040 USB Host, Fruit Jam, and Raspberry Pi Pico builds. Smoke tested
on the Feather: 20 SCSI read/write cycles to a flash drive.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mikeysklar

mikeysklar commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

@dhalbert - Initially this fix was up to 3.4kB of RAM, but I knew nobody would allow that so the LLM used linker --wrap and kept memory usage under 64 bytes.

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.

rp2 USB host: core1 can fault in flash via TinyUSB queue mutex contention

1 participant