xref: /DragonOS/kernel/src/exception/irqdata.rs (revision ce5850adbf74ec6c6717bbb5b1749f1fbff4ca0d)
1 use core::{any::Any, fmt::Debug};
2 
3 use alloc::sync::{Arc, Weak};
4 
5 use crate::libs::spinlock::SpinLock;
6 
7 use super::{
8     irqchip::{IrqChip, IrqChipData},
9     irqdomain::IrqDomain,
10     msi::MsiDesc,
11     HardwareIrqNumber, IrqNumber,
12 };
13 
14 /// per irq chip data passed down to chip functions
15 ///
16 /// 该结构体用于表示每个Irq的私有数据,且与具体的中断芯片绑定
17 ///
18 /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#179
19 #[allow(dead_code)]
20 #[derive(Debug)]
21 pub struct IrqData {
22     /// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
23     irq: IrqNumber,
24     /// 硬件中断号, 用于表示在某个IrqDomain中的中断号
25     hwirq: HardwareIrqNumber,
26     /// 涉及的所有irqchip之间共享的数据
27     common_data: Arc<IrqCommonData>,
28     /// 绑定到的中断芯片
29     chip: Arc<dyn IrqChip>,
30     /// 中断芯片的私有数据(与当前irq相关)
31     chip_data: Arc<dyn IrqChipData>,
32     /// 中断域
33     domain: Arc<IrqDomain>,
34     /// 中断的父中断(如果具有中断域继承的话)
35     parent_data: Option<Weak<IrqData>>,
36 }
37 
38 /// per irq data shared by all irqchips
39 ///
40 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147
41 #[allow(dead_code)]
42 #[derive(Debug)]
43 pub struct IrqCommonData {
44     inner: SpinLock<InnerIrqCommonData>,
45 }
46 
47 #[allow(dead_code)]
48 #[derive(Debug)]
49 struct InnerIrqCommonData {
50     /// status information for irq chip functions.
51     state: IrqStatus,
52     /// per-IRQ data for the irq_chip methods
53     handler_data: Option<Arc<dyn IrqHandlerData>>,
54     msi_desc: Option<Arc<MsiDesc>>,
55     // todo: affinity
56 }
57 
58 pub trait IrqHandlerData: Send + Sync + Any + Debug {}
59 
60 bitflags! {
61     /// 中断线状态
62     /// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h?fi=IRQ_TYPE_PROBE#77
63     pub struct IrqLineStatus: u32 {
64         /// 默认,未指明类型
65         const IRQ_TYPE_NONE     = 0x00000000;
66         /// 上升沿触发
67         const IRQ_TYPE_EDGE_RISING  = 0x00000001;
68         /// 下降沿触发
69         const IRQ_TYPE_EDGE_FALLING = 0x00000002;
70         /// 上升沿和下降沿触发
71         const IRQ_TYPE_EDGE_BOTH    = Self::IRQ_TYPE_EDGE_RISING.bits | Self::IRQ_TYPE_EDGE_FALLING.bits;
72         /// 高电平触发
73         const IRQ_TYPE_LEVEL_HIGH   = 0x00000004;
74         /// 低电平触发
75         const IRQ_TYPE_LEVEL_LOW    = 0x00000008;
76         /// 过滤掉电平位的掩码
77         const IRQ_TYPE_LEVEL_MASK   = Self::IRQ_TYPE_LEVEL_LOW.bits | Self::IRQ_TYPE_LEVEL_HIGH.bits;
78         /// 上述位掩码的掩码
79         const IRQ_TYPE_SENSE_MASK   = 0x0000000f;
80         /// 某些PICs使用此类型要求 `IrqChip::irq_set_type()` 设置硬件到一个合理的默认值
81         /// (由irqdomain的map()回调使用,以便为新分配的描述符同步硬件状态和软件标志位)。
82         const IRQ_TYPE_DEFAULT      = Self::IRQ_TYPE_SENSE_MASK.bits;
83 
84         /// 特定于探测的过程中的特殊标志
85         const IRQ_TYPE_PROBE        = 0x00000010;
86 
87         /// 中断是电平类型。当上述触发位通过`IrqChip::irq_set_type()` 修改时,也会在代码中更新
88         const IRQ_LEVEL     = 1 << 8;
89         /// 标记一个PER_CPU的中断。将保护其免受亲和性设置的影响
90         const IRQ_PER_CPU       = 1 << 9;
91         /// 中断不能被自动探测
92         const IRQ_NOPROBE       = 1 << 10;
93         /// 中断不能通过request_irq()请求
94         const IRQ_NOREQUEST     = 1 << 11;
95         /// 中断在request/setup_irq()中不会自动启用
96         const IRQ_NOAUTOEN      = 1 << 12;
97         /// 中断不能被平衡(亲和性设置)
98         const IRQ_NO_BALANCING      = 1 << 13;
99         /// 中断可以从进程上下文中迁移
100         const IRQ_MOVE_PCNTXT       = 1 << 14;
101         /// 中断嵌套在另一个线程中
102         const IRQ_NESTED_THREAD = 1 << 15;
103         /// 中断不能被线程化
104         const IRQ_NOTHREAD      = 1 << 16;
105         /// Dev_id是一个per-CPU变量
106         const IRQ_PER_CPU_DEVID = 1 << 17;
107         /// 总是由另一个中断轮询。将其从错误的中断检测机制和核心侧轮询中排除
108         const IRQ_IS_POLLED     = 1 << 18;
109         /// 禁用延迟的中断禁用 (Disable lazy irq disable)
110         const IRQ_DISABLE_UNLAZY    = 1 << 19;
111         /// 在/proc/interrupts中不显示
112         const IRQ_HIDDEN        = 1 << 20;
113         /// 从note_interrupt()调试中排除
114         const IRQ_NO_DEBUG      = 1 << 21;
115     }
116 
117 
118 
119 }
120 bitflags! {
121     /// 中断状态(存储在IrqCommonData)
122     ///
123     /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#227
124     pub struct IrqStatus: u32 {
125         /// 触发类型位的掩码
126         const IRQD_TRIGGER_MASK = 0xf;
127         /// 亲和性设置待处理
128         const IRQD_SETAFFINITY_PENDING = 1 << 8;
129         /// 中断已激活
130         const IRQD_ACTIVATED = 1 << 9;
131         /// 对此IRQ禁用平衡
132         const IRQD_NO_BALANCING = 1 << 10;
133         /// 中断是每个CPU特定的
134         const IRQD_PER_CPU = 1 << 11;
135         /// 中断亲和性已设置
136         const IRQD_AFFINITY_SET = 1 << 12;
137         /// 中断是电平触发
138         const IRQD_LEVEL = 1 << 13;
139         /// 中断配置为从挂起状态唤醒
140         const IRQD_WAKEUP_STATE = 1 << 14;
141         /// 中断可以在进程上下文中移动
142         const IRQD_MOVE_PCNTXT = 1 << 15;
143         /// 中断被禁用
144         const IRQD_IRQ_DISABLED = 1 << 16;
145         /// 中断被屏蔽
146         const IRQD_IRQ_MASKED = 1 << 17;
147         /// 中断正在处理中
148         const IRQD_IRQ_INPROGRESS = 1 << 18;
149         /// 唤醒模式已准备就绪
150         const IRQD_WAKEUP_ARMED = 1 << 19;
151         /// 中断被转发到一个虚拟CPU
152         const IRQD_FORWARDED_TO_VCPU = 1 << 20;
153         /// 亲和性由内核自动管理
154         const IRQD_AFFINITY_MANAGED = 1 << 21;
155         /// 中断已启动
156         const IRQD_IRQ_STARTED = 1 << 22;
157         /// 由于空亲和性掩码而关闭的中断。仅适用于亲和性管理的中断。
158         const IRQD_MANAGED_SHUTDOWN = 1 << 23;
159         /// IRQ只允许单个亲和性目标
160         const IRQD_SINGLE_TARGET = 1 << 24;
161         /// 预期的触发器已设置
162         const IRQD_DEFAULT_TRIGGER_SET = 1 << 25;
163         /// 可以使用保留模式
164         const IRQD_CAN_RESERVE = 1 << 26;
165         /// Non-maskable MSI quirk for affinity change required
166         const IRQD_MSI_NOMASK_QUIRK = 1 << 27;
167         /// 强制要求`handle_irq_()`只能在真实的中断上下文中调用
168         const IRQD_HANDLE_ENFORCE_IRQCTX = 1 << 28;
169         /// 激活时设置亲和性。在禁用时不要调用irq_chip::irq_set_affinity()。
170         const IRQD_AFFINITY_ON_ACTIVATE = 1 << 29;
171         /// 如果irqpm具有标志 IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,则在挂起时中断被启用。
172         const IRQD_IRQ_ENABLED_ON_SUSPEND = 1 << 30;
173     }
174 }
175 
176 #[allow(dead_code)]
177 impl IrqStatus {
178     pub const fn is_set_affinity_pending(&self) -> bool {
179         self.contains(Self::IRQD_SETAFFINITY_PENDING)
180     }
181 
182     pub const fn is_per_cpu(&self) -> bool {
183         self.contains(Self::IRQD_PER_CPU)
184     }
185 
186     pub const fn can_balance(&self) -> bool {
187         !((self.bits & (Self::IRQD_PER_CPU.bits | Self::IRQD_NO_BALANCING.bits)) != 0)
188     }
189 
190     pub const fn affinity_was_set(&self) -> bool {
191         self.contains(Self::IRQD_AFFINITY_SET)
192     }
193 
194     pub fn mark_affinity_set(&mut self) {
195         self.insert(Self::IRQD_AFFINITY_SET);
196     }
197 
198     pub const fn trigger_type_was_set(&self) -> bool {
199         self.contains(Self::IRQD_DEFAULT_TRIGGER_SET)
200     }
201 
202     pub fn mark_trigger_type_set(&mut self) {
203         self.insert(Self::IRQD_DEFAULT_TRIGGER_SET);
204     }
205 
206     pub const fn trigger_type(&self) -> IrqLineStatus {
207         IrqLineStatus::from_bits_truncate(self.bits & Self::IRQD_TRIGGER_MASK.bits)
208     }
209 
210     /// Must only be called inside irq_chip.irq_set_type() functions or
211     /// from the DT/ACPI setup code.
212     pub const fn set_trigger_type(&mut self, trigger: IrqLineStatus) {
213         self.bits &= !Self::IRQD_TRIGGER_MASK.bits;
214         self.bits |= trigger.bits & Self::IRQD_TRIGGER_MASK.bits;
215 
216         self.bits |= Self::IRQD_DEFAULT_TRIGGER_SET.bits;
217     }
218 
219     pub const fn is_level_type(&self) -> bool {
220         self.contains(Self::IRQD_LEVEL)
221     }
222 
223     /// Must only be called of irqchip.irq_set_affinity() or low level
224     /// hierarchy domain allocation functions.
225     pub fn set_single_target(&mut self) {
226         self.insert(Self::IRQD_SINGLE_TARGET);
227     }
228 
229     pub const fn is_single_target(&self) -> bool {
230         self.contains(Self::IRQD_SINGLE_TARGET)
231     }
232 
233     pub fn set_handle_enforce_irqctx(&mut self) {
234         self.insert(Self::IRQD_HANDLE_ENFORCE_IRQCTX);
235     }
236 
237     pub const fn is_handle_enforce_irqctx(&self) -> bool {
238         self.contains(Self::IRQD_HANDLE_ENFORCE_IRQCTX)
239     }
240 
241     pub const fn is_enabled_on_suspend(&self) -> bool {
242         self.contains(Self::IRQD_IRQ_ENABLED_ON_SUSPEND)
243     }
244 
245     pub const fn is_wakeup_set(&self) -> bool {
246         self.contains(Self::IRQD_WAKEUP_STATE)
247     }
248 
249     pub const fn can_move_in_process_context(&self) -> bool {
250         self.contains(Self::IRQD_MOVE_PCNTXT)
251     }
252 
253     pub const fn is_irq_disabled(&self) -> bool {
254         self.contains(Self::IRQD_IRQ_DISABLED)
255     }
256 
257     pub const fn is_irq_masked(&self) -> bool {
258         self.contains(Self::IRQD_IRQ_MASKED)
259     }
260 
261     pub const fn is_irq_in_progress(&self) -> bool {
262         self.contains(Self::IRQD_IRQ_INPROGRESS)
263     }
264 
265     pub const fn is_wakeup_armed(&self) -> bool {
266         self.contains(Self::IRQD_WAKEUP_ARMED)
267     }
268 
269     pub const fn is_forwarded_to_vcpu(&self) -> bool {
270         self.contains(Self::IRQD_FORWARDED_TO_VCPU)
271     }
272 
273     pub fn set_forwarded_to_vcpu(&mut self) {
274         self.insert(Self::IRQD_FORWARDED_TO_VCPU);
275     }
276 
277     pub const fn is_affinity_managed(&self) -> bool {
278         self.contains(Self::IRQD_AFFINITY_MANAGED)
279     }
280 
281     pub const fn is_activated(&self) -> bool {
282         self.contains(Self::IRQD_ACTIVATED)
283     }
284 
285     pub fn set_activated(&mut self) {
286         self.insert(Self::IRQD_ACTIVATED);
287     }
288 
289     pub fn clear_activated(&mut self) {
290         self.remove(Self::IRQD_ACTIVATED);
291     }
292 
293     pub const fn is_started(&self) -> bool {
294         self.contains(Self::IRQD_IRQ_STARTED)
295     }
296 
297     pub const fn is_managed_and_shutdown(&self) -> bool {
298         self.contains(Self::IRQD_MANAGED_SHUTDOWN)
299     }
300 
301     pub fn set_can_reserve(&mut self) {
302         self.insert(Self::IRQD_CAN_RESERVE);
303     }
304 
305     pub const fn can_reserve(&self) -> bool {
306         self.contains(Self::IRQD_CAN_RESERVE)
307     }
308 
309     pub fn clear_can_reserve(&mut self) {
310         self.remove(Self::IRQD_CAN_RESERVE);
311     }
312 
313     pub fn set_msi_nomask_quirk(&mut self) {
314         self.insert(Self::IRQD_MSI_NOMASK_QUIRK);
315     }
316 
317     pub fn clear_msi_nomask_quirk(&mut self) {
318         self.remove(Self::IRQD_MSI_NOMASK_QUIRK);
319     }
320 
321     pub const fn is_msi_nomask_quirk(&self) -> bool {
322         self.contains(Self::IRQD_MSI_NOMASK_QUIRK)
323     }
324 
325     pub fn set_affinity_on_activate(&mut self) {
326         self.insert(Self::IRQD_AFFINITY_ON_ACTIVATE);
327     }
328 
329     pub const fn is_affinity_on_activate(&self) -> bool {
330         self.contains(Self::IRQD_AFFINITY_ON_ACTIVATE)
331     }
332 }
333