1
//! Under construction: This is public only for tests, please avoid using it
2
//! directly.
3

            
4
use core::sync::atomic::{Ordering, compiler_fence};
5

            
6
#[cfg(riscv)]
7
use esp_sync::raw::SingleCoreInterruptLock;
8
use esp_sync::{GenericRawMutex, RestoreState, raw::RawLock};
9

            
10
use crate::interrupt::{ElevatedRunLevel, Priority, RunLevel};
11

            
12
/// A lock that disables interrupts below a certain priority.
13
pub struct PriorityLock(pub RunLevel);
14

            
15
impl PriorityLock {
16
    fn current_priority() -> RunLevel {
17
        RunLevel::current()
18
    }
19

            
20
    /// Prevents interrupts above `level` from firing and returns the
21
    /// current run level.
22
    unsafe fn change_current_level(level: RunLevel) -> RunLevel {
23
        unsafe { RunLevel::change(level) }
24
    }
25
}
26

            
27
impl RawLock for PriorityLock {
28
4
    unsafe fn enter(&self) -> RestoreState {
29
        #[cfg(riscv)]
30
4
        if self.0 == Priority::max() {
31
            return unsafe { SingleCoreInterruptLock.enter() };
32
        }
33

            
34
        let prev_level = unsafe { Self::change_current_level(self.0) };
35
2
        assert!(prev_level <= self.0);
36

            
37
        // Ensure no subsequent memory accesses are reordered to before interrupts are
38
        // disabled.
39
        compiler_fence(Ordering::SeqCst);
40

            
41
        unsafe { RestoreState::new(u32::from(prev_level)) }
42
1
    }
43

            
44
3
    unsafe fn exit(&self, token: RestoreState) {
45
        #[cfg(riscv)]
46
3
        if self.0 == Priority::max() {
47
            return unsafe { SingleCoreInterruptLock.exit(token) };
48
        }
49
        assert!(Self::current_priority() <= self.0);
50
        // Ensure no preceeding memory accesses are reordered to after interrupts are
51
        // enabled.
52
        compiler_fence(Ordering::SeqCst);
53

            
54
2
        let level = unwrap!(RunLevel::try_from_u32(token.inner()));
55
        unsafe { Self::change_current_level(level) };
56
2
    }
57
}
58

            
59
/// A mutual exclusion primitive that only disables a limited range of
60
/// interrupts.
61
///
62
/// Trying to acquire or release the lock at a higher priority level will panic.
63
pub struct RawPriorityLimitedMutex {
64
    inner: GenericRawMutex<PriorityLock>,
65
}
66

            
67
impl RawPriorityLimitedMutex {
68
    /// Creates a new lock that is accessible at or below the given `priority`.
69
    pub const fn new(priority: Priority) -> Self {
70
        Self {
71
            inner: GenericRawMutex::new(PriorityLock(RunLevel::Interrupt(
72
                ElevatedRunLevel::from_priority(priority),
73
            ))),
74
        }
75
    }
76

            
77
    /// Runs the callback with this lock locked.
78
    pub fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
79
2
        self.inner.lock(f)
80
    }
81
}
82

            
83
unsafe impl embassy_sync::blocking_mutex::raw::RawMutex for RawPriorityLimitedMutex {
84
    #[allow(clippy::declare_interior_mutable_const)]
85
    const INIT: Self = Self::new(Priority::max());
86

            
87
    fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
88
        self.inner.lock(f)
89
    }
90
}
91

            
92
#[cfg(impl_critical_section)]
93
#[cfg(feature = "rt")]
94
mod critical_section {
95
    struct CriticalSection;
96

            
97
    critical_section::set_impl!(CriticalSection);
98

            
99
    static CRITICAL_SECTION: esp_sync::RawMutex = esp_sync::RawMutex::new();
100

            
101
    unsafe impl critical_section::Impl for CriticalSection {
102
100806
        unsafe fn acquire() -> critical_section::RawRestoreState {
103
            unsafe { CRITICAL_SECTION.acquire().inner() }
104
100806
        }
105

            
106
100805
        unsafe fn release(token: critical_section::RawRestoreState) {
107
            unsafe {
108
                CRITICAL_SECTION.release(esp_sync::RestoreState::new(token));
109
            }
110
100112
        }
111
    }
112
}