xref: /linux/rust/kernel/interrupt.rs (revision dfa35434d7f20142fedd7120277b1044a0a2bb64)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Interrupt controls
4 //!
5 //! This module allows Rust code to annotate areas of code where local processor interrupts should
6 //! be disabled, along with actually disabling local processor interrupts.
7 //!
8 //! # ⚠️ Warning! ⚠️
9 //!
10 //! The usage of this module can be more complicated than meets the eye, especially surrounding
11 //! [preemptible kernels]. It's recommended to take care when using the functions and types defined
12 //! here and familiarize yourself with the various documentation we have before using them, along
13 //! with the various documents we link to here.
14 //!
15 //! # Reading material
16 //!
17 //! - [Software interrupts and realtime (LWN)](https://lwn.net/Articles/520076)
18 //!
19 //! [preemptible kernels]: https://www.kernel.org/doc/html/latest/locking/preempt-locking.html
20 
21 use crate::types::NotThreadSafe;
22 
23 /// A guard that represents local processor interrupt disablement on preemptible kernels.
24 ///
25 /// [`LocalInterruptDisabled`] is a guard type that represents that local processor interrupts have
26 /// been disabled on a preemptible kernel.
27 ///
28 /// Certain functions take an immutable reference of [`LocalInterruptDisabled`] in order to require
29 /// that they may only be run in local-interrupt-disabled contexts on preemptible kernels.
30 ///
31 /// This is a marker type; it has no size, and is simply used as a compile-time guarantee that local
32 /// processor interrupts are disabled on preemptible kernels. Note that no guarantees about the
33 /// state of interrupts are made by this type on non-preemptible kernels.
34 ///
35 /// # Invariants
36 ///
37 /// Local processor interrupts are disabled on preemptible kernels for as long as an object of this
38 /// type exists.
39 pub struct LocalInterruptDisabled(NotThreadSafe);
40 
41 /// Disable local processor interrupts on a preemptible kernel.
42 ///
43 /// This function disables local processor interrupts on a preemptible kernel, and returns a
44 /// [`LocalInterruptDisabled`] token as proof of this. On non-preemptible kernels, this function is
45 /// a no-op.
46 ///
47 /// **Usage of this function is discouraged** unless you are absolutely sure you know what you are
48 /// doing, as kernel interfaces for Rust that deal with interrupt state will typically handle local
49 /// processor interrupt state management on their own and managing this by hand is quite error
50 /// prone.
51 #[inline]
52 pub fn local_interrupt_disable() -> LocalInterruptDisabled {
53     // SAFETY: It's always safe to call `local_interrupt_disable()`.
54     unsafe { bindings::local_interrupt_disable() };
55 
56     LocalInterruptDisabled(NotThreadSafe)
57 }
58 
59 impl Drop for LocalInterruptDisabled {
60     #[inline]
61     fn drop(&mut self) {
62         // SAFETY: Per type invariants, a `local_interrupt_disable()` must be called to create this
63         // object, hence calling the corresponding `local_interrupt_enable()` is safe.
64         unsafe { bindings::local_interrupt_enable() };
65     }
66 }
67 
68 impl LocalInterruptDisabled {
69     /// Assume that local processor interrupts are disabled on preemptible kernels.
70     ///
71     /// This can be used for annotating code that is known to be run in contexts where local
72     /// processor interrupts are disabled on preemptible kernels. It makes no changes to the local
73     /// interrupt state on its own.
74     ///
75     /// # Safety
76     ///
77     /// For the whole life `'a`, local interrupts must be disabled on preemptible kernels. This
78     /// could be a context like, for example, an interrupt handler.
79     #[inline]
80     pub unsafe fn assume_disabled<'a>() -> &'a LocalInterruptDisabled {
81         const ASSUME_DISABLED: &LocalInterruptDisabled = &LocalInterruptDisabled(NotThreadSafe);
82 
83         // Confirm they're actually disabled if lockdep is available
84         // SAFETY: It's always safe to call `lockdep_assert_irqs_disabled()`.
85         unsafe { bindings::lockdep_assert_irqs_disabled() };
86 
87         ASSUME_DISABLED
88     }
89 }
90