aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-05-26 22:18:40 +0000
committerGitHub <[email protected]>2024-05-26 22:18:40 +0000
commit8b9e2efec25ae36041038b70f608fe55f5061a1f (patch)
treefec29625eb74fb3de073643d96412d35b824d047
parentec185b2fd2ab34c24ed7e93b7e8c32ed6b346987 (diff)
parentd18a919ab9cfa1c07d339dd885d8268ab0abb7e6 (diff)
Merge pull request #3001 from embassy-rs/rp-spinlock-fix
rp: fix spinlocks staying locked after reset.
-rw-r--r--embassy-rp/src/lib.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 1c83e306d..507d42280 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -352,12 +352,60 @@ pub fn init(config: config::Config) -> Peripherals {
352 peripherals 352 peripherals
353} 353}
354 354
355#[cfg(feature = "rt")]
356#[cortex_m_rt::pre_init]
357unsafe fn pre_init() {
358 // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD.
359 // Since we're using SIO spinlock 31 for the critical-section impl, this causes random
360 // hangs if we reset in the middle of a CS, because the next boot sees the spinlock
361 // as locked and waits forever.
362 //
363 // See https://github.com/embassy-rs/embassy/issues/1736
364 // and https://github.com/rp-rs/rp-hal/issues/292
365 // and https://matrix.to/#/!vhKMWjizPZBgKeknOo:matrix.org/$VfOkQgyf1PjmaXZbtycFzrCje1RorAXd8BQFHTl4d5M
366 //
367 // According to Raspberry Pi, this is considered Working As Intended, and not an errata,
368 // even though this behavior is different from every other ARM chip (sys_reset usually resets
369 // the *system* as its name implies, not just the current core).
370 //
371 // To fix this, reset SIO on boot. We must do this in pre_init because it's unsound to do it
372 // in `embassy_rp::init`, since the user could've acquired a CS by then. pre_init is guaranteed
373 // to run before any user code.
374 //
375 // A similar thing could happen with PROC1. It is unclear whether it's possible for PROC1
376 // to stay unreset through a PROC0 reset, so we reset it anyway just in case.
377 //
378 // Important info from PSM logic (from Luke Wren in above Matrix thread)
379 //
380 // The logic is, each PSM stage is reset if either of the following is true:
381 // - The previous stage is in reset and FRCE_ON is false
382 // - FRCE_OFF is true
383 //
384 // The PSM order is SIO -> PROC0 -> PROC1.
385 // So, we have to force-on PROC0 to prevent it from getting reset when resetting SIO.
386 pac::PSM.frce_on().write_and_wait(|w| {
387 w.set_proc0(true);
388 });
389 // Then reset SIO and PROC1.
390 pac::PSM.frce_off().write_and_wait(|w| {
391 w.set_sio(true);
392 w.set_proc1(true);
393 });
394 // clear force_off first, force_on second. The other way around would reset PROC0.
395 pac::PSM.frce_off().write_and_wait(|_| {});
396 pac::PSM.frce_on().write_and_wait(|_| {});
397}
398
355/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. 399/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
400#[allow(unused)]
356trait RegExt<T: Copy> { 401trait RegExt<T: Copy> {
357 #[allow(unused)] 402 #[allow(unused)]
358 fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 403 fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
359 fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 404 fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
360 fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R; 405 fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
406 fn write_and_wait<R>(&self, f: impl FnOnce(&mut T) -> R) -> R
407 where
408 T: PartialEq;
361} 409}
362 410
363impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> { 411impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
@@ -390,4 +438,17 @@ impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T,
390 } 438 }
391 res 439 res
392 } 440 }
441
442 fn write_and_wait<R>(&self, f: impl FnOnce(&mut T) -> R) -> R
443 where
444 T: PartialEq,
445 {
446 let mut val = Default::default();
447 let res = f(&mut val);
448 unsafe {
449 self.as_ptr().write_volatile(val);
450 while self.as_ptr().read_volatile() != val {}
451 }
452 res
453 }
393} 454}