xtensa_lx/
interrupt.rs

1//! Interrupts
2
3use core::arch::asm;
4
5/// Disables all interrupts and return the previous settings
6#[inline]
7pub fn disable() -> u32 {
8    unsafe { set_mask(0) }
9}
10
11/// Enables all the interrupts
12///
13/// # Safety
14///
15/// - Do not call this function inside an `interrupt::free` critical section
16#[inline]
17pub unsafe fn enable() -> u32 {
18    set_mask(!0)
19}
20
21/// Enables specific interrupts and returns the previous setting
22///
23/// # Safety
24///
25/// - Do not call this function inside an `interrupt::free` critical section
26#[inline]
27pub unsafe fn set_mask(mut mask: u32) -> u32 {
28    asm!("
29        xsr {0}, intenable
30        rsync
31        ",
32        inout(reg) mask, options(nostack)
33    );
34    mask
35}
36
37/// Disables specific interrupts and returns the previous settings
38#[inline]
39pub fn disable_mask(mask: u32) -> u32 {
40    let mut prev: u32 = 0;
41    let _dummy: u32;
42    unsafe {
43        asm!("
44        xsr.intenable {0}  // get mask and temporarily disable interrupts
45        and {1}, {1}, {0}
46        rsync
47        wsr.intenable {1}
48        rsync
49        ", inout(reg) prev, inout(reg) !mask => _dummy, options(nostack)
50        );
51    }
52    prev
53}
54
55/// Enables specific interrupts and returns the previous setting
56///
57/// # Safety
58///
59/// - Do not call this function inside an `interrupt::free` critical section
60#[inline]
61pub unsafe fn enable_mask(mask: u32) -> u32 {
62    let mut prev: u32 = 0;
63    let _dummy: u32;
64    asm!("
65        xsr.intenable {0} // get mask and temporarily disable interrupts
66        or {1}, {1}, {0}
67        rsync
68        wsr.intenable {1}
69        rsync
70    ", inout(reg) prev, inout(reg) mask => _dummy, options(nostack));
71    prev
72}
73
74/// Get current interrupt mask
75#[inline]
76pub fn get_mask() -> u32 {
77    let mask: u32;
78    unsafe { asm!("rsr.intenable {0}", out(reg) mask) };
79    mask
80}
81
82/// Get currently active interrupts
83#[inline]
84pub fn get() -> u32 {
85    let mask: u32;
86    unsafe {
87        asm!("rsr.interrupt {0}", out(reg) mask, options(nostack));
88    }
89    mask
90}
91
92/// Set interrupt
93///
94/// # Safety
95///
96/// Only valid for software interrupts
97#[inline]
98pub unsafe fn set(mask: u32) {
99    asm!("
100         wsr.intset {0}
101         rsync
102         ",
103         in(reg) mask, options(nostack)
104    );
105}
106
107/// Clear interrupt
108///
109/// # Safety
110///
111/// Only valid for software and edge-triggered interrupts
112#[inline]
113pub unsafe fn clear(mask: u32) {
114    asm!("
115         wsr.intclear {0}
116         rsync
117         ",
118         in(reg) mask, options(nostack)
119    );
120}
121
122/// Get current interrupt level
123#[inline]
124pub fn get_level() -> u32 {
125    let ps: u32;
126    unsafe {
127        asm!("rsr.ps {0}", out(reg) ps, options(nostack));
128    };
129    ps & 0xf
130}
131
132/// Execute closure `f` in an interrupt-free context.
133///
134/// This method does not synchronise multiple cores, so it is not suitable for
135/// using as a critical section. See the `critical-section` crate for a
136/// cross-platform way to enter a critical section which provides a
137/// `CriticalSection` token.
138#[inline]
139pub fn free<F, R>(f: F) -> R
140where
141    F: FnOnce() -> R,
142{
143    // disable interrupts and store old mask
144    let old_mask = disable();
145
146    let r = f();
147
148    // enable previously disabled interrupts
149    unsafe { enable_mask(old_mask) };
150
151    r
152}