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