1
//! GPIO interrupt handling
2
//!
3
//! ## Requirements
4
//!
5
//! - On devices other than the P4, there is a single interrupt handler. GPIO interrupt handling
6
//!   must not interfere with the async API in this single handler.
7
//! - Async operations take pins by `&mut self`, so they can only be accessed after the operation is
8
//!   complete, or cancelled. They may be defined to overwrite the configuration of the manual
9
//!   interrupt API, but not affect the interrupt handler.
10
//! - Manual `listen` operations don't need to be prepared for async operations, but async
11
//!   operations need to be prepared to handle cases where the pin was configured to listen for an
12
//!   event - or even that the user unlistened the pin but left the interrupt status set.
13
//!
14
//! The user should be careful when using the async API and the manual interrupt
15
//! API together. For performance reasons, we will not prevent the user handler
16
//! from running in response to an async event.
17
//!
18
//! ## Single-shot interaction with user interrupt handlers
19
//!
20
//! The async API disables the pin's interrupt when triggered. This makes async
21
//! operations single-shot. If there is no user handler, the other GPIO
22
//! interrupts are also single-shot. This is because the user has no way to
23
//! handle multiple events in this case, the API only allows querying whether
24
//! the interrupt has fired or not. Disabling the interrupt also means that the
25
//! interrupt status bits are not cleared, so the `is_interrupt_set` works by
26
//! default as expected.
27
//!
28
//! When the user sets a custom interrupt handler, the built-in interrupt
29
//! handler will only disable the async interrupts. The user handler is
30
//! responsible for clearing the interrupt status bits or disabling the
31
//! interrupts, based on their needs. This is communicated to the user in the
32
//! documentation of the `Io::set_interrupt_handler` function.
33
//!
34
//! ## Critical sections
35
//!
36
//! The interrupt handler runs in a GPIO-specific critical section. The critical
37
//! section is required because interrupts are disabled by modifying the pin
38
//! register, which is not an atomic operation. The critical section also
39
//! ensures that a higher priority task waken by an async pin event (or the user
40
//! handler) will only run after the interrupt handler has finished.
41
//!
42
//! ## Signaling async completion
43
//!
44
//! The completion is signaled by clearing a flag in an AtomicU32. This flag is
45
//! set at the start of the async operation, and cleared when the interrupt
46
//! handler is called. The flag is not accessible by the user, so they can't
47
//! force-complete an async operation accidentally from the interrupt handler.
48
//!
49
//! We could technically use the interrupt status on single-core chips, but it
50
//! would be slightly more complicated to prevent the user from breaking things.
51
//! (If the user were to clear the interrupt status, we would need to re-enable
52
//! it, for PinFuture to detect the completion).
53

            
54
use portable_atomic::Ordering;
55
use strum::EnumCount;
56

            
57
#[cfg(feature = "rt")]
58
use crate::{
59
    gpio::low_level::disable_cpu_interrupt,
60
    handler,
61
    interrupt::{self, DEFAULT_INTERRUPT_HANDLER},
62
    peripherals::Interrupt,
63
    system::Cpu,
64
};
65
use crate::{
66
    gpio::{AnyPin, GPIO_LOCK, GpioBank, InputPin, low_level::set_int_enable},
67
    private::CFnPtr,
68
    ram,
69
};
70

            
71
pub(super) static USER_INTERRUPT_HANDLER: CFnPtr = CFnPtr::new();
72

            
73
#[cfg(feature = "rt")]
74
pub(crate) fn bind_default_interrupt_handler() {
75
    // We first check if a handler is set in the vector table.
76
    if let Some(handler) = interrupt::bound_handler(Interrupt::GPIO) {
77
        // We only allow binding the default handler if nothing else is bound.
78
        // This prevents silently overwriting RTIC's interrupt handler, if using GPIO.
79
325
        if handler != DEFAULT_INTERRUPT_HANDLER.handler() {
80
            // The user has configured an interrupt handler they wish to use.
81
            info!("Not using default GPIO interrupt handler: already bound in vector table");
82
            return;
83
        }
84
    }
85

            
86
    // The vector table doesn't contain a custom entry. Still, the
87
    // peripheral interrupt may already be bound to something else.
88
    let mut is_mapped = false;
89
    for cpu in Cpu::all() {
90
        if interrupt::mapped_to(cpu, Interrupt::GPIO).is_some() {
91
            is_mapped = true;
92
        }
93
    }
94

            
95
320
    if is_mapped {
96
        info!("Not using default GPIO interrupt handler: peripheral interrupt already in use");
97
        return;
98
    }
99

            
100
    super::low_level::enable_interrupt(default_gpio_interrupt_handler);
101
}
102

            
103
/// The default GPIO interrupt handler, used when no custom handler is set.
104
///
105
/// This handler disables all pending interrupts and leaves the interrupt
106
/// status bits unchanged. This enables functions like `is_interrupt_set` to
107
/// work correctly.
108
9
#[ram]
109
#[handler]
110
#[cfg(feature = "rt")]
111
fn default_gpio_interrupt_handler() {
112
    GPIO_LOCK.lock(|| {
113
        let banks = interrupt_status();
114

            
115
        // Handle the async interrupts
116
        for (bank, intrs) in banks {
117
            // Get the mask of active async pins and clear the relevant bits to signal
118
            // completion. This way the user may clear the interrupt status
119
            // without worrying about the async bit being cleared.
120
            let async_pins = bank.async_operations().load(Ordering::Relaxed);
121

            
122
            // Wake up the tasks
123
9
            handle_async_pins(bank, async_pins, intrs);
124

            
125
            // Disable the remaining interrupts.
126
9
            let mut intrs = intrs & !async_pins;
127
9
            while intrs != 0 {
128
                let pin_pos = intrs.trailing_zeros();
129
1
                intrs -= 1 << pin_pos;
130

            
131
                let pin_nr = pin_pos as u8 + bank.offset();
132

            
133
                // The remaining interrupts are not async, we treat them as single-shot.
134
                disable_cpu_interrupt(pin_nr);
135
            }
136
        }
137
    });
138
}
139

            
140
/// The custom GPIO interrupt handler, used when one is set.
141
///
142
/// This handler only disables interrupts associated with async pins. The custom
143
/// handler is responsible for clearing the interrupt status bits or disabling
144
/// the interrupts.
145
#[ram]
146
20
pub(super) extern "C" fn user_gpio_interrupt_handler() {
147
    GPIO_LOCK.lock(|| {
148
        // Read interrupt status before the user has a chance to modify them.
149
        let banks = interrupt_status();
150

            
151
        // Call the user handler before clearing interrupts. The user can use the enable
152
        // bits to determine which interrupts they are interested in. Clearing the
153
        // interrupt status or enable bits have no effect on the rest of the
154
        // interrupt handler.
155
        USER_INTERRUPT_HANDLER.call();
156

            
157
        process_async_banks(banks);
158
    });
159
20
}
160

            
161
/// Internal entry point for [`crate::gpio::handle_gpio_interrupt`].
162
///
163
/// Kept here (rather than at the public callsite) because this module owns
164
/// the GPIO ISR critical section and the per-bank dispatch routine, both of
165
/// which are private to this module.
166
///
167
/// # Safety
168
///
169
/// Must be called from a GPIO interrupt context.
170
#[ram]
171
5
pub(super) unsafe fn handle_gpio_interrupt_impl() {
172
    GPIO_LOCK.lock(|| {
173
        let banks = interrupt_status();
174
        process_async_banks(banks);
175
    });
176
5
}
177

            
178
#[inline]
179
pub(super) fn process_async_banks(banks: [(GpioBank, u32); GpioBank::COUNT]) {
180
    for (bank, intrs) in banks {
181
        let async_pins = bank.async_operations().load(Ordering::Relaxed);
182

            
183
20
        handle_async_pins(bank, async_pins, intrs);
184
    }
185
}
186

            
187
/// Internal entry point for [`crate::gpio::wake_pin`].
188
///
189
/// # Safety
190
///
191
/// Must be called from a GPIO interrupt context.
192
#[ram]
193
5
pub(super) unsafe fn wake_pin_impl(pin: u8) {
194
    GPIO_LOCK.lock(|| {
195
        let any = unsafe { AnyPin::steal(pin) };
196
        let bank = any.bank();
197
        let mask = any.mask();
198

            
199
        // Only act if this pin is registered as an async waiter.
200
        let async_pins = bank.async_operations().load(Ordering::Relaxed);
201
5
        if async_pins & mask == 0 {
202
            return;
203
        }
204

            
205
5
        handle_async_pins(bank, mask, mask);
206
    });
207
5
}
208

            
209
fn interrupt_status() -> [(GpioBank, u32); GpioBank::COUNT] {
210
    let intrs_bank0 = GpioBank::_0.read_interrupt_status_of_current_cpu();
211

            
212
    #[cfg(gpio_has_bank_1)]
213
    let intrs_bank1 = GpioBank::_1.read_interrupt_status_of_current_cpu();
214

            
215
    [
216
        (GpioBank::_0, intrs_bank0),
217
        #[cfg(gpio_has_bank_1)]
218
        (GpioBank::_1, intrs_bank1),
219
    ]
220
}
221

            
222
// We have separate variants for single-core and multi-core async pin handling.
223
// Single core can be much simpler because no code is running in parallel, so we
224
// don't have to be so careful with the order of operations. On multi-core,
225
// however, the order can actually break things, regardless of the critical
226
// section (because tasks on the other core may be waken in inappropriate
227
// times).
228

            
229
#[cfg(single_core)]
230
39
fn handle_async_pins(bank: GpioBank, async_pins: u32, intrs: u32) {
231
39
    let mut async_intrs = async_pins & intrs;
232
39
    while async_intrs != 0 {
233
        let pin_pos = async_intrs.trailing_zeros();
234
28
        async_intrs -= 1 << pin_pos;
235

            
236
        let pin_nr = pin_pos as u8 + bank.offset();
237

            
238
        // Disable the interrupt for this pin.
239
        set_int_enable(pin_nr, Some(0), 0, false);
240

            
241
28
        unsafe { AnyPin::steal(pin_nr) }.waker().wake();
242
    }
243

            
244
    // This is an optimization (in case multiple pin interrupts are handled at once)
245
    // so that PinFuture doesn't have to clear interrupt status bits one by one
246
    // for each pin. We need to clear after disabling the interrupt, so that a pin
247
    // event can't re-set the bit.
248
    bank.write_interrupt_status_clear(async_pins & intrs);
249

            
250
    // On a single-core chip, the lock around `handle_async_pins` ensures
251
    // that the interrupt handler will not be interrupted by other code,
252
    // so we can safely write back without an atomic CAS.
253
    bank.async_operations()
254
39
        .store(async_pins & !intrs, Ordering::Relaxed);
255
39
}
256

            
257
#[cfg(multi_core)]
258
fn handle_async_pins(bank: GpioBank, async_pins: u32, intrs: u32) {
259
    // First, disable pin interrupts. If we were to do this after clearing the async
260
    // flags, the PinFuture destructor may try to take a critical section which
261
    // isn't necessary.
262
    let mut async_intrs = async_pins & intrs;
263
    while async_intrs != 0 {
264
        let pin_pos = async_intrs.trailing_zeros();
265
        async_intrs -= 1 << pin_pos;
266

            
267
        let pin_nr = pin_pos as u8 + bank.offset();
268

            
269
        // Disable the interrupt for this pin.
270
        set_int_enable(pin_nr, Some(0), 0, false);
271
    }
272

            
273
    // This is an optimization (in case multiple pin interrupts are handled at once)
274
    // so that PinFuture doesn't have to clear interrupt status bits one by one
275
    // for each pin. We need to clear after disabling the interrupt, so that a pin
276
    // event can't re-set the bit.
277
    bank.write_interrupt_status_clear(async_pins & intrs);
278

            
279
    // Clearing the async bit needs to be the last state change, as this signals
280
    // completion.
281
    // On multi-core chips, we need to use a CAS to ensure that only
282
    // the handled async bits are cleared.
283
    bank.async_operations().fetch_and(!intrs, Ordering::Relaxed);
284

            
285
    // Now we can wake the tasks. This needs to happen after completion - waking an
286
    // already running task isn't a big issue, but not waking a waiting one is.
287
    // Doing it sooner would mean that on a multi-core chip a task could be
288
    // waken, but the Future wouldn't actually be resolved, and so it might
289
    // never wake again.
290
    let mut async_intrs = async_pins & intrs;
291
    while async_intrs != 0 {
292
        let pin_pos = async_intrs.trailing_zeros();
293
        async_intrs -= 1 << pin_pos;
294

            
295
        let pin_nr = pin_pos as u8 + bank.offset();
296

            
297
        unsafe { AnyPin::steal(pin_nr) }.waker().wake();
298
    }
299
}