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