xref: /linux/rust/kernel/irq/flags.rs (revision 746680ec6696585e30db3e18c93a63df9cbec39c)
1*746680ecSDaniel Almeida // SPDX-License-Identifier: GPL-2.0
2*746680ecSDaniel Almeida // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
3*746680ecSDaniel Almeida 
4*746680ecSDaniel Almeida use crate::bindings;
5*746680ecSDaniel Almeida use crate::prelude::*;
6*746680ecSDaniel Almeida 
7*746680ecSDaniel Almeida /// Flags to be used when registering IRQ handlers.
8*746680ecSDaniel Almeida ///
9*746680ecSDaniel Almeida /// Flags can be used to request specific behaviors when registering an IRQ
10*746680ecSDaniel Almeida /// handler, and can be combined using the `|`, `&`, and `!` operators to
11*746680ecSDaniel Almeida /// further control the system's behavior.
12*746680ecSDaniel Almeida ///
13*746680ecSDaniel Almeida /// A common use case is to register a shared interrupt, as sharing the line
14*746680ecSDaniel Almeida /// between devices is increasingly common in modern systems and is even
15*746680ecSDaniel Almeida /// required for some buses. This requires setting [`Flags::SHARED`] when
16*746680ecSDaniel Almeida /// requesting the interrupt. Other use cases include setting the trigger type
17*746680ecSDaniel Almeida /// through `Flags::TRIGGER_*`, which determines when the interrupt fires, or
18*746680ecSDaniel Almeida /// controlling whether the interrupt is masked after the handler runs by using
19*746680ecSDaniel Almeida /// [`Flags::ONESHOT`].
20*746680ecSDaniel Almeida ///
21*746680ecSDaniel Almeida /// If an invalid combination of flags is provided, the system will refuse to
22*746680ecSDaniel Almeida /// register the handler, and lower layers will enforce certain flags when
23*746680ecSDaniel Almeida /// necessary. This means, for example, that all the
24*746680ecSDaniel Almeida /// `crate::irq::Registration` for a shared interrupt have to agree on
25*746680ecSDaniel Almeida /// [`Flags::SHARED`] and on the same trigger type, if set.
26*746680ecSDaniel Almeida #[derive(Clone, Copy, PartialEq, Eq)]
27*746680ecSDaniel Almeida pub struct Flags(c_ulong);
28*746680ecSDaniel Almeida 
29*746680ecSDaniel Almeida impl Flags {
30*746680ecSDaniel Almeida     /// Use the interrupt line as already configured.
31*746680ecSDaniel Almeida     pub const TRIGGER_NONE: Flags = Flags::new(bindings::IRQF_TRIGGER_NONE);
32*746680ecSDaniel Almeida 
33*746680ecSDaniel Almeida     /// The interrupt is triggered when the signal goes from low to high.
34*746680ecSDaniel Almeida     pub const TRIGGER_RISING: Flags = Flags::new(bindings::IRQF_TRIGGER_RISING);
35*746680ecSDaniel Almeida 
36*746680ecSDaniel Almeida     /// The interrupt is triggered when the signal goes from high to low.
37*746680ecSDaniel Almeida     pub const TRIGGER_FALLING: Flags = Flags::new(bindings::IRQF_TRIGGER_FALLING);
38*746680ecSDaniel Almeida 
39*746680ecSDaniel Almeida     /// The interrupt is triggered while the signal is held high.
40*746680ecSDaniel Almeida     pub const TRIGGER_HIGH: Flags = Flags::new(bindings::IRQF_TRIGGER_HIGH);
41*746680ecSDaniel Almeida 
42*746680ecSDaniel Almeida     /// The interrupt is triggered while the signal is held low.
43*746680ecSDaniel Almeida     pub const TRIGGER_LOW: Flags = Flags::new(bindings::IRQF_TRIGGER_LOW);
44*746680ecSDaniel Almeida 
45*746680ecSDaniel Almeida     /// Allow sharing the IRQ among several devices.
46*746680ecSDaniel Almeida     pub const SHARED: Flags = Flags::new(bindings::IRQF_SHARED);
47*746680ecSDaniel Almeida 
48*746680ecSDaniel Almeida     /// Set by callers when they expect sharing mismatches to occur.
49*746680ecSDaniel Almeida     pub const PROBE_SHARED: Flags = Flags::new(bindings::IRQF_PROBE_SHARED);
50*746680ecSDaniel Almeida 
51*746680ecSDaniel Almeida     /// Flag to mark this interrupt as timer interrupt.
52*746680ecSDaniel Almeida     pub const TIMER: Flags = Flags::new(bindings::IRQF_TIMER);
53*746680ecSDaniel Almeida 
54*746680ecSDaniel Almeida     /// Interrupt is per CPU.
55*746680ecSDaniel Almeida     pub const PERCPU: Flags = Flags::new(bindings::IRQF_PERCPU);
56*746680ecSDaniel Almeida 
57*746680ecSDaniel Almeida     /// Flag to exclude this interrupt from irq balancing.
58*746680ecSDaniel Almeida     pub const NOBALANCING: Flags = Flags::new(bindings::IRQF_NOBALANCING);
59*746680ecSDaniel Almeida 
60*746680ecSDaniel Almeida     /// Interrupt is used for polling (only the interrupt that is registered
61*746680ecSDaniel Almeida     /// first in a shared interrupt is considered for performance reasons).
62*746680ecSDaniel Almeida     pub const IRQPOLL: Flags = Flags::new(bindings::IRQF_IRQPOLL);
63*746680ecSDaniel Almeida 
64*746680ecSDaniel Almeida     /// Interrupt is not re-enabled after the hardirq handler finished. Used by
65*746680ecSDaniel Almeida     /// threaded interrupts which need to keep the irq line disabled until the
66*746680ecSDaniel Almeida     /// threaded handler has been run.
67*746680ecSDaniel Almeida     pub const ONESHOT: Flags = Flags::new(bindings::IRQF_ONESHOT);
68*746680ecSDaniel Almeida 
69*746680ecSDaniel Almeida     /// Do not disable this IRQ during suspend. Does not guarantee that this
70*746680ecSDaniel Almeida     /// interrupt will wake the system from a suspended state.
71*746680ecSDaniel Almeida     pub const NO_SUSPEND: Flags = Flags::new(bindings::IRQF_NO_SUSPEND);
72*746680ecSDaniel Almeida 
73*746680ecSDaniel Almeida     /// Force enable it on resume even if [`Flags::NO_SUSPEND`] is set.
74*746680ecSDaniel Almeida     pub const FORCE_RESUME: Flags = Flags::new(bindings::IRQF_FORCE_RESUME);
75*746680ecSDaniel Almeida 
76*746680ecSDaniel Almeida     /// Interrupt cannot be threaded.
77*746680ecSDaniel Almeida     pub const NO_THREAD: Flags = Flags::new(bindings::IRQF_NO_THREAD);
78*746680ecSDaniel Almeida 
79*746680ecSDaniel Almeida     /// Resume IRQ early during syscore instead of at device resume time.
80*746680ecSDaniel Almeida     pub const EARLY_RESUME: Flags = Flags::new(bindings::IRQF_EARLY_RESUME);
81*746680ecSDaniel Almeida 
82*746680ecSDaniel Almeida     /// If the IRQ is shared with a [`Flags::NO_SUSPEND`] user, execute this
83*746680ecSDaniel Almeida     /// interrupt handler after suspending interrupts. For system wakeup devices
84*746680ecSDaniel Almeida     /// users need to implement wakeup detection in their interrupt handlers.
85*746680ecSDaniel Almeida     pub const COND_SUSPEND: Flags = Flags::new(bindings::IRQF_COND_SUSPEND);
86*746680ecSDaniel Almeida 
87*746680ecSDaniel Almeida     /// Don't enable IRQ or NMI automatically when users request it. Users will
88*746680ecSDaniel Almeida     /// enable it explicitly by `enable_irq` or `enable_nmi` later.
89*746680ecSDaniel Almeida     pub const NO_AUTOEN: Flags = Flags::new(bindings::IRQF_NO_AUTOEN);
90*746680ecSDaniel Almeida 
91*746680ecSDaniel Almeida     /// Exclude from runnaway detection for IPI and similar handlers, depends on
92*746680ecSDaniel Almeida     /// `PERCPU`.
93*746680ecSDaniel Almeida     pub const NO_DEBUG: Flags = Flags::new(bindings::IRQF_NO_DEBUG);
94*746680ecSDaniel Almeida 
95*746680ecSDaniel Almeida     #[expect(dead_code)]
96*746680ecSDaniel Almeida     pub(crate) fn into_inner(self) -> c_ulong {
97*746680ecSDaniel Almeida         self.0
98*746680ecSDaniel Almeida     }
99*746680ecSDaniel Almeida 
100*746680ecSDaniel Almeida     const fn new(value: u32) -> Self {
101*746680ecSDaniel Almeida         build_assert!(value as u64 <= c_ulong::MAX as u64);
102*746680ecSDaniel Almeida         Self(value as c_ulong)
103*746680ecSDaniel Almeida     }
104*746680ecSDaniel Almeida }
105*746680ecSDaniel Almeida 
106*746680ecSDaniel Almeida impl core::ops::BitOr for Flags {
107*746680ecSDaniel Almeida     type Output = Self;
108*746680ecSDaniel Almeida     fn bitor(self, rhs: Self) -> Self::Output {
109*746680ecSDaniel Almeida         Self(self.0 | rhs.0)
110*746680ecSDaniel Almeida     }
111*746680ecSDaniel Almeida }
112*746680ecSDaniel Almeida 
113*746680ecSDaniel Almeida impl core::ops::BitAnd for Flags {
114*746680ecSDaniel Almeida     type Output = Self;
115*746680ecSDaniel Almeida     fn bitand(self, rhs: Self) -> Self::Output {
116*746680ecSDaniel Almeida         Self(self.0 & rhs.0)
117*746680ecSDaniel Almeida     }
118*746680ecSDaniel Almeida }
119*746680ecSDaniel Almeida 
120*746680ecSDaniel Almeida impl core::ops::Not for Flags {
121*746680ecSDaniel Almeida     type Output = Self;
122*746680ecSDaniel Almeida     fn not(self) -> Self::Output {
123*746680ecSDaniel Almeida         Self(!self.0)
124*746680ecSDaniel Almeida     }
125*746680ecSDaniel Almeida }
126