xref: /linux/rust/kernel/irq/flags.rs (revision eb3289fc474f74105e0627bf508e3f9742fd3b63)
1746680ecSDaniel Almeida // SPDX-License-Identifier: GPL-2.0
2746680ecSDaniel Almeida // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd.
3746680ecSDaniel Almeida 
4746680ecSDaniel Almeida use crate::bindings;
5746680ecSDaniel Almeida use crate::prelude::*;
6746680ecSDaniel Almeida 
7746680ecSDaniel Almeida /// Flags to be used when registering IRQ handlers.
8746680ecSDaniel Almeida ///
9746680ecSDaniel Almeida /// Flags can be used to request specific behaviors when registering an IRQ
10746680ecSDaniel Almeida /// handler, and can be combined using the `|`, `&`, and `!` operators to
11746680ecSDaniel Almeida /// further control the system's behavior.
12746680ecSDaniel Almeida ///
13746680ecSDaniel Almeida /// A common use case is to register a shared interrupt, as sharing the line
14746680ecSDaniel Almeida /// between devices is increasingly common in modern systems and is even
15746680ecSDaniel Almeida /// required for some buses. This requires setting [`Flags::SHARED`] when
16746680ecSDaniel Almeida /// requesting the interrupt. Other use cases include setting the trigger type
17746680ecSDaniel Almeida /// through `Flags::TRIGGER_*`, which determines when the interrupt fires, or
18746680ecSDaniel Almeida /// controlling whether the interrupt is masked after the handler runs by using
19746680ecSDaniel Almeida /// [`Flags::ONESHOT`].
20746680ecSDaniel Almeida ///
21746680ecSDaniel Almeida /// If an invalid combination of flags is provided, the system will refuse to
22746680ecSDaniel Almeida /// register the handler, and lower layers will enforce certain flags when
23746680ecSDaniel Almeida /// necessary. This means, for example, that all the
24*0851d34aSDaniel Almeida /// [`crate::irq::Registration`] for a shared interrupt have to agree on
25746680ecSDaniel Almeida /// [`Flags::SHARED`] and on the same trigger type, if set.
26746680ecSDaniel Almeida #[derive(Clone, Copy, PartialEq, Eq)]
27746680ecSDaniel Almeida pub struct Flags(c_ulong);
28746680ecSDaniel Almeida 
29746680ecSDaniel Almeida impl Flags {
30746680ecSDaniel Almeida     /// Use the interrupt line as already configured.
31746680ecSDaniel Almeida     pub const TRIGGER_NONE: Flags = Flags::new(bindings::IRQF_TRIGGER_NONE);
32746680ecSDaniel Almeida 
33746680ecSDaniel Almeida     /// The interrupt is triggered when the signal goes from low to high.
34746680ecSDaniel Almeida     pub const TRIGGER_RISING: Flags = Flags::new(bindings::IRQF_TRIGGER_RISING);
35746680ecSDaniel Almeida 
36746680ecSDaniel Almeida     /// The interrupt is triggered when the signal goes from high to low.
37746680ecSDaniel Almeida     pub const TRIGGER_FALLING: Flags = Flags::new(bindings::IRQF_TRIGGER_FALLING);
38746680ecSDaniel Almeida 
39746680ecSDaniel Almeida     /// The interrupt is triggered while the signal is held high.
40746680ecSDaniel Almeida     pub const TRIGGER_HIGH: Flags = Flags::new(bindings::IRQF_TRIGGER_HIGH);
41746680ecSDaniel Almeida 
42746680ecSDaniel Almeida     /// The interrupt is triggered while the signal is held low.
43746680ecSDaniel Almeida     pub const TRIGGER_LOW: Flags = Flags::new(bindings::IRQF_TRIGGER_LOW);
44746680ecSDaniel Almeida 
45746680ecSDaniel Almeida     /// Allow sharing the IRQ among several devices.
46746680ecSDaniel Almeida     pub const SHARED: Flags = Flags::new(bindings::IRQF_SHARED);
47746680ecSDaniel Almeida 
48746680ecSDaniel Almeida     /// Set by callers when they expect sharing mismatches to occur.
49746680ecSDaniel Almeida     pub const PROBE_SHARED: Flags = Flags::new(bindings::IRQF_PROBE_SHARED);
50746680ecSDaniel Almeida 
51746680ecSDaniel Almeida     /// Flag to mark this interrupt as timer interrupt.
52746680ecSDaniel Almeida     pub const TIMER: Flags = Flags::new(bindings::IRQF_TIMER);
53746680ecSDaniel Almeida 
54746680ecSDaniel Almeida     /// Interrupt is per CPU.
55746680ecSDaniel Almeida     pub const PERCPU: Flags = Flags::new(bindings::IRQF_PERCPU);
56746680ecSDaniel Almeida 
57746680ecSDaniel Almeida     /// Flag to exclude this interrupt from irq balancing.
58746680ecSDaniel Almeida     pub const NOBALANCING: Flags = Flags::new(bindings::IRQF_NOBALANCING);
59746680ecSDaniel Almeida 
60746680ecSDaniel Almeida     /// Interrupt is used for polling (only the interrupt that is registered
61746680ecSDaniel Almeida     /// first in a shared interrupt is considered for performance reasons).
62746680ecSDaniel Almeida     pub const IRQPOLL: Flags = Flags::new(bindings::IRQF_IRQPOLL);
63746680ecSDaniel Almeida 
64746680ecSDaniel Almeida     /// Interrupt is not re-enabled after the hardirq handler finished. Used by
65746680ecSDaniel Almeida     /// threaded interrupts which need to keep the irq line disabled until the
66746680ecSDaniel Almeida     /// threaded handler has been run.
67746680ecSDaniel Almeida     pub const ONESHOT: Flags = Flags::new(bindings::IRQF_ONESHOT);
68746680ecSDaniel Almeida 
69746680ecSDaniel Almeida     /// Do not disable this IRQ during suspend. Does not guarantee that this
70746680ecSDaniel Almeida     /// interrupt will wake the system from a suspended state.
71746680ecSDaniel Almeida     pub const NO_SUSPEND: Flags = Flags::new(bindings::IRQF_NO_SUSPEND);
72746680ecSDaniel Almeida 
73746680ecSDaniel Almeida     /// Force enable it on resume even if [`Flags::NO_SUSPEND`] is set.
74746680ecSDaniel Almeida     pub const FORCE_RESUME: Flags = Flags::new(bindings::IRQF_FORCE_RESUME);
75746680ecSDaniel Almeida 
76746680ecSDaniel Almeida     /// Interrupt cannot be threaded.
77746680ecSDaniel Almeida     pub const NO_THREAD: Flags = Flags::new(bindings::IRQF_NO_THREAD);
78746680ecSDaniel Almeida 
79746680ecSDaniel Almeida     /// Resume IRQ early during syscore instead of at device resume time.
80746680ecSDaniel Almeida     pub const EARLY_RESUME: Flags = Flags::new(bindings::IRQF_EARLY_RESUME);
81746680ecSDaniel Almeida 
82746680ecSDaniel Almeida     /// If the IRQ is shared with a [`Flags::NO_SUSPEND`] user, execute this
83746680ecSDaniel Almeida     /// interrupt handler after suspending interrupts. For system wakeup devices
84746680ecSDaniel Almeida     /// users need to implement wakeup detection in their interrupt handlers.
85746680ecSDaniel Almeida     pub const COND_SUSPEND: Flags = Flags::new(bindings::IRQF_COND_SUSPEND);
86746680ecSDaniel Almeida 
87746680ecSDaniel Almeida     /// Don't enable IRQ or NMI automatically when users request it. Users will
88746680ecSDaniel Almeida     /// enable it explicitly by `enable_irq` or `enable_nmi` later.
89746680ecSDaniel Almeida     pub const NO_AUTOEN: Flags = Flags::new(bindings::IRQF_NO_AUTOEN);
90746680ecSDaniel Almeida 
91746680ecSDaniel Almeida     /// Exclude from runnaway detection for IPI and similar handlers, depends on
92746680ecSDaniel Almeida     /// `PERCPU`.
93746680ecSDaniel Almeida     pub const NO_DEBUG: Flags = Flags::new(bindings::IRQF_NO_DEBUG);
94746680ecSDaniel Almeida 
95746680ecSDaniel Almeida     pub(crate) fn into_inner(self) -> c_ulong {
96746680ecSDaniel Almeida         self.0
97746680ecSDaniel Almeida     }
98746680ecSDaniel Almeida 
99746680ecSDaniel Almeida     const fn new(value: u32) -> Self {
100746680ecSDaniel Almeida         build_assert!(value as u64 <= c_ulong::MAX as u64);
101746680ecSDaniel Almeida         Self(value as c_ulong)
102746680ecSDaniel Almeida     }
103746680ecSDaniel Almeida }
104746680ecSDaniel Almeida 
105746680ecSDaniel Almeida impl core::ops::BitOr for Flags {
106746680ecSDaniel Almeida     type Output = Self;
107746680ecSDaniel Almeida     fn bitor(self, rhs: Self) -> Self::Output {
108746680ecSDaniel Almeida         Self(self.0 | rhs.0)
109746680ecSDaniel Almeida     }
110746680ecSDaniel Almeida }
111746680ecSDaniel Almeida 
112746680ecSDaniel Almeida impl core::ops::BitAnd for Flags {
113746680ecSDaniel Almeida     type Output = Self;
114746680ecSDaniel Almeida     fn bitand(self, rhs: Self) -> Self::Output {
115746680ecSDaniel Almeida         Self(self.0 & rhs.0)
116746680ecSDaniel Almeida     }
117746680ecSDaniel Almeida }
118746680ecSDaniel Almeida 
119746680ecSDaniel Almeida impl core::ops::Not for Flags {
120746680ecSDaniel Almeida     type Output = Self;
121746680ecSDaniel Almeida     fn not(self) -> Self::Output {
122746680ecSDaniel Almeida         Self(!self.0)
123746680ecSDaniel Almeida     }
124746680ecSDaniel Almeida }
125