diff options
| author | renjie <[email protected]> | 2026-06-21 14:06:23 +0800 |
|---|---|---|
| committer | renjie <[email protected]> | 2026-06-21 17:46:26 +0800 |
| commit | f7617168e2ce2e7ea2e49cba5962b69aed04900e (patch) | |
| tree | 49de16c1b816c244e93ac0c58f75da004f680bd8 | |
| parent | c1bf19ed6cf1eaa791f221c1bc5ce4b3d069f76d (diff) | |
fix(host): release spinlock in tuh_deinit to fix multi-rebuild panic
tuh_rhport_init() calls osal_spin_init(&_usbh_spin), which under OPT_OS_PICO
claims a hardware spinlock via critical_section_init(). There was no
osal_spin_deinit(), so tuh_deinit() never released it: every host init/deinit
cycle leaked one spinlock. RP2350 has a small spinlock pool, so a few usb_host
rebuilds exhaust it and hw_claim_unused_from_range() panics (the long-standing
"crashes on the 4th rebuild" bug).
Add osal_spin_deinit() to all OSAL backends (critical_section_deinit for pico;
no-op for none/freertos) and call it in tuh_deinit(). Verified 20/20
deinit+rebuild cycles on RP2350-Zero and Waveshare RP2350-USB-A (previously
panicked on the 4th).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
| -rw-r--r-- | src/host/usbh.c | 5 | ||||
| -rw-r--r-- | src/osal/osal_freertos.h | 8 | ||||
| -rw-r--r-- | src/osal/osal_none.h | 4 | ||||
| -rw-r--r-- | src/osal/osal_pico.h | 7 |
4 files changed, 24 insertions, 0 deletions
diff --git a/src/host/usbh.c b/src/host/usbh.c index 6bafde368..d60feebb4 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -557,6 +557,11 @@ bool tuh_deinit(uint8_t rhport) { osal_mutex_delete(_usbh_mutex); _usbh_mutex = NULL; #endif + + // Release the spinlock claimed by osal_spin_init() in tuh_rhport_init(). + // Pairs with that init; without it each init/deinit cycle leaks a hardware + // spinlock and a few host rebuilds exhaust the pool (panic in claim). + osal_spin_deinit(&_usbh_spin); } return true; diff --git a/src/osal/osal_freertos.h b/src/osal/osal_freertos.h index bde5ec010..d9e084241 100644 --- a/src/osal/osal_freertos.h +++ b/src/osal/osal_freertos.h @@ -113,6 +113,10 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { spinlock_initialize(ctx); } +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_deinit(osal_spinlock_t *ctx) { + (void) ctx; +} + TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { if (!TUP_MCU_MULTIPLE_CORE && in_isr) { return; // single core MCU does not need to lock in ISR @@ -135,6 +139,10 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { (void) ctx; } +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_deinit(osal_spinlock_t *ctx) { + (void) ctx; +} + TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { if (in_isr) { if (!TUP_MCU_MULTIPLE_CORE) { diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h index 3e397ef35..0893bb55c 100644 --- a/src/osal/osal_none.h +++ b/src/osal/osal_none.h @@ -46,6 +46,10 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { (void) ctx; } +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_deinit(osal_spinlock_t *ctx) { + (void) ctx; +} + TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { if (!in_isr) { ctx->interrupt_set(false); diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h index ace5907d7..f1b48f172 100644 --- a/src/osal/osal_pico.h +++ b/src/osal/osal_pico.h @@ -54,6 +54,13 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) { critical_section_init(ctx); } +TU_ATTR_ALWAYS_INLINE static inline void osal_spin_deinit(osal_spinlock_t *ctx) { + // Release the hardware spinlock claimed by critical_section_init. Without this, + // every tuh_init()/tuh_deinit() cycle leaks one spinlock (RP2350's pool is + // small), so a few host rebuilds exhaust it and hw_claim_unused_from_range panics. + critical_section_deinit(ctx); +} + TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) { (void) in_isr; critical_section_enter_blocking(ctx); |
