Skip to main content

irq_framework/
types.rs

1use core::ptr::NonNull;
2
3/// A platform IRQ number.
4#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
5pub struct IrqNumber(pub usize);
6
7/// A logical CPU id.
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
9pub struct CpuId(pub usize);
10
11/// A compact CPU mask for low-level IRQ affinity.
12#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
13pub struct CpuMask {
14    bits: u128,
15}
16
17impl CpuMask {
18    /// Creates an empty CPU mask.
19    pub const fn empty() -> Self {
20        Self { bits: 0 }
21    }
22
23    /// Creates a CPU mask containing a single CPU.
24    pub fn from_cpu(cpu: CpuId) -> Self {
25        let mut mask = Self::empty();
26        mask.insert(cpu);
27        mask
28    }
29
30    /// Creates a CPU mask containing CPUs in the range `0..cpu_count`.
31    pub fn first_n(cpu_count: usize) -> Self {
32        let mut mask = Self::empty();
33        let end = cpu_count.min(u128::BITS as usize);
34        for cpu in 0..end {
35            mask.insert(CpuId(cpu));
36        }
37        mask
38    }
39
40    /// Adds a CPU to this mask.
41    pub fn insert(&mut self, cpu: CpuId) {
42        if cpu.0 < u128::BITS as usize {
43            self.bits |= 1u128 << cpu.0;
44        }
45    }
46
47    /// Removes a CPU from this mask.
48    pub fn remove(&mut self, cpu: CpuId) {
49        if cpu.0 < u128::BITS as usize {
50            self.bits &= !(1u128 << cpu.0);
51        }
52    }
53
54    /// Returns whether the CPU is present in this mask.
55    pub const fn contains(self, cpu: CpuId) -> bool {
56        cpu.0 < u128::BITS as usize && (self.bits & (1u128 << cpu.0)) != 0
57    }
58
59    /// Returns whether no CPU is present in this mask.
60    pub const fn is_empty(self) -> bool {
61        self.bits == 0
62    }
63
64    /// Iterates over the CPUs in this mask.
65    pub fn iter(self) -> CpuMaskIter {
66        CpuMaskIter { bits: self.bits }
67    }
68}
69
70/// Iterator over [`CpuMask`].
71pub struct CpuMaskIter {
72    bits: u128,
73}
74
75impl Iterator for CpuMaskIter {
76    type Item = CpuId;
77
78    fn next(&mut self) -> Option<Self::Item> {
79        if self.bits == 0 {
80            return None;
81        }
82        let cpu = self.bits.trailing_zeros() as usize;
83        self.bits &= !(1u128 << cpu);
84        Some(CpuId(cpu))
85    }
86}
87
88/// IRQ registration scope.
89#[derive(Clone, Copy, Debug, Eq, PartialEq)]
90pub enum IrqScope {
91    /// The action is visible on every CPU.
92    Global,
93    /// The action is CPU-local and only visible to matching CPUs.
94    PerCpu {
95        /// Target CPUs.
96        cpus: CpuMask,
97    },
98}
99
100/// Whether an IRQ line is exclusive or shared.
101#[derive(Clone, Copy, Debug, Eq, PartialEq)]
102pub enum ShareMode {
103    /// No other action can share the IRQ.
104    Exclusive,
105    /// Multiple actions can share the IRQ.
106    Shared,
107}
108
109/// Whether an IRQ action should be enabled after registration.
110#[derive(Clone, Copy, Debug, Eq, PartialEq)]
111pub enum AutoEnable {
112    /// Register the action but leave it disabled.
113    No,
114    /// Enable the action after registration.
115    Yes,
116}
117
118/// Return value from a raw IRQ handler.
119#[derive(Clone, Copy, Debug, Eq, PartialEq)]
120pub enum IrqReturn {
121    /// This action did not handle the IRQ.
122    Unhandled,
123    /// This action handled the IRQ.
124    Handled,
125    /// This action handled the IRQ and asks the OS adapter to wake deferred work.
126    Wake,
127}
128
129/// Aggregated dispatch result.
130#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
131pub struct IrqOutcome {
132    /// At least one action handled the IRQ.
133    pub handled: bool,
134    /// At least one action requested a wakeup.
135    pub wake: bool,
136    /// Number of handlers called by this dispatch.
137    pub called: usize,
138}
139
140/// IRQ status snapshot.
141#[derive(Clone, Copy, Debug, Eq, PartialEq)]
142pub struct IrqStatus {
143    /// Whether this action is enabled in the framework.
144    pub action_enabled: bool,
145    /// Whether the platform line is enabled.
146    pub line_enabled: bool,
147    /// Whether the platform reports the IRQ pending.
148    pub pending: bool,
149    /// Whether the platform reports the IRQ in service.
150    pub in_service: bool,
151    /// Number of in-flight dispatches for this descriptor.
152    pub in_flight: usize,
153}
154
155/// IRQ framework errors.
156#[derive(Clone, Copy, Debug, Eq, PartialEq)]
157pub enum IrqError {
158    /// Invalid IRQ number.
159    InvalidIrq,
160    /// Invalid CPU id.
161    InvalidCpu,
162    /// The target CPU is offline.
163    CpuOffline,
164    /// IRQ line/action sharing rules reject the operation.
165    Busy,
166    /// Allocation failed.
167    NoMemory,
168    /// The requested descriptor or action does not exist.
169    NotFound,
170    /// This operation is not legal from IRQ context.
171    InIrqContext,
172    /// The platform adapter does not support this operation.
173    Unsupported,
174    /// The platform controller reported an error.
175    Controller,
176}
177
178/// Context passed to IRQ handlers.
179#[derive(Clone, Copy, Debug, Eq, PartialEq)]
180pub struct IrqContext {
181    /// IRQ number being dispatched.
182    pub irq: IrqNumber,
183    /// CPU handling the IRQ.
184    pub cpu: CpuId,
185}
186
187/// Raw IRQ handler ABI.
188pub type RawIrqHandler = unsafe fn(ctx: IrqContext, data: NonNull<()>) -> IrqReturn;
189
190/// External capabilities supplied by the OS/platform adapter.
191pub trait IrqOps {
192    /// Saved local IRQ state.
193    type LocalIrqState: Copy;
194
195    /// Returns the current CPU.
196    fn current_cpu(&self) -> CpuId;
197
198    /// Returns whether the CPU is online.
199    fn cpu_online(&self, cpu: CpuId) -> bool;
200
201    /// Returns whether the current execution context is an IRQ context.
202    fn in_irq_context(&self) -> bool;
203
204    /// Saves and disables local IRQs for metadata lock acquisition.
205    fn local_irq_save(&self) -> Self::LocalIrqState;
206
207    /// Restores local IRQ state saved by [`IrqOps::local_irq_save`].
208    fn local_irq_restore(&self, state: Self::LocalIrqState);
209
210    /// Runs a thunk synchronously on the target CPU.
211    fn run_on_cpu_sync(
212        &self,
213        cpu: CpuId,
214        f: unsafe fn(*mut ()),
215        arg: *mut (),
216    ) -> Result<(), IrqError>;
217
218    /// Enables or disables an IRQ line.
219    fn set_enabled(
220        &self,
221        irq: IrqNumber,
222        cpu: Option<CpuId>,
223        enabled: bool,
224    ) -> Result<(), IrqError>;
225
226    /// Returns whether the IRQ line is enabled.
227    fn is_enabled(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
228
229    /// Returns whether the IRQ line is pending.
230    fn is_pending(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
231
232    /// Returns whether the IRQ line is in service.
233    fn is_in_service(&self, irq: IrqNumber, cpu: Option<CpuId>) -> Result<bool, IrqError>;
234
235    /// Relaxes a spin wait.
236    fn relax(&self);
237}
238
239/// Request parameters for an IRQ action.
240#[derive(Clone, Copy, Debug)]
241pub struct IrqRequest {
242    pub(crate) handler: RawIrqHandler,
243    pub(crate) data: NonNull<()>,
244    pub(crate) scope: IrqScope,
245    pub(crate) share_mode: ShareMode,
246    pub(crate) auto_enable: AutoEnable,
247}
248
249impl IrqRequest {
250    /// Creates a new exclusive, global, auto-enabled IRQ request.
251    pub const fn new(handler: RawIrqHandler, data: NonNull<()>) -> Self {
252        Self {
253            handler,
254            data,
255            scope: IrqScope::Global,
256            share_mode: ShareMode::Exclusive,
257            auto_enable: AutoEnable::Yes,
258        }
259    }
260
261    /// Sets the IRQ scope.
262    pub const fn scope(mut self, scope: IrqScope) -> Self {
263        self.scope = scope;
264        self
265    }
266
267    /// Sets the sharing mode.
268    pub const fn share_mode(mut self, share_mode: ShareMode) -> Self {
269        self.share_mode = share_mode;
270        self
271    }
272
273    /// Sets whether the action should be enabled after request.
274    pub const fn auto_enable(mut self, auto_enable: AutoEnable) -> Self {
275        self.auto_enable = auto_enable;
276        self
277    }
278}
279
280/// Token returned from request and used for later lifecycle operations.
281#[derive(Clone, Copy, Debug, Eq, PartialEq)]
282pub struct IrqHandle {
283    pub(crate) irq: IrqNumber,
284    pub(crate) id: u64,
285}
286
287impl IrqHandle {
288    /// Returns the IRQ number associated with this handle.
289    pub const fn irq(self) -> IrqNumber {
290        self.irq
291    }
292
293    /// Returns the framework-local action id.
294    pub const fn id(self) -> u64 {
295        self.id
296    }
297}