xref: /DragonOS/kernel/src/exception/irqdata.rs (revision fbd63a301c5648f906eeb802f10ac03518ba1264)
1 use core::{any::Any, fmt::Debug};
2 
3 use alloc::sync::{Arc, Weak};
4 use intertrait::CastFromSync;
5 
6 use crate::libs::{
7     cpumask::CpuMask,
8     rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
9     spinlock::{SpinLock, SpinLockGuard},
10 };
11 
12 use super::{
13     irqchip::{IrqChip, IrqChipData},
14     irqdesc::IrqDesc,
15     irqdomain::IrqDomain,
16     msi::MsiDesc,
17     HardwareIrqNumber, IrqNumber,
18 };
19 
20 /// per irq chip data passed down to chip functions
21 ///
22 /// 该结构体用于表示每个Irq的私有数据,且与具体的中断芯片绑定
23 ///
24 /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#179
25 #[allow(dead_code)]
26 #[derive(Debug)]
27 pub struct IrqData {
28     /// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
29     irq: IrqNumber,
30     inner: SpinLock<InnerIrqData>,
31 
32     chip_info: RwLock<InnerIrqChipInfo>,
33 }
34 
35 impl IrqData {
36     pub fn new(
37         irq: IrqNumber,
38         hwirq: HardwareIrqNumber,
39         common_data: Arc<IrqCommonData>,
40         chip: Arc<dyn IrqChip>,
41     ) -> Self {
42         return IrqData {
43             irq,
44             inner: SpinLock::new(InnerIrqData {
45                 hwirq,
46                 common_data,
47                 desc: Weak::new(),
48                 domain: None,
49                 parent_data: None,
50             }),
51             chip_info: RwLock::new(InnerIrqChipInfo {
52                 chip: Some(chip),
53                 chip_data: None,
54             }),
55         };
56     }
57 
58     pub fn irqd_set(&self, status: IrqStatus) {
59         // clone是为了释放inner锁
60         let common_data = self.inner.lock_irqsave().common_data.clone();
61         common_data.insert_status(status);
62     }
63 
64     #[allow(dead_code)]
65     pub fn irqd_clear(&self, status: IrqStatus) {
66         // clone是为了释放inner锁
67         let common_data = self.inner.lock_irqsave().common_data.clone();
68         common_data.clear_status(status);
69     }
70 
71     pub fn irq(&self) -> IrqNumber {
72         self.irq
73     }
74 
75     pub fn irq_desc(&self) -> Option<Arc<IrqDesc>> {
76         self.inner.lock_irqsave().desc.upgrade()
77     }
78 
79     pub fn set_irq_desc(&self, desc: Weak<IrqDesc>) {
80         self.inner.lock_irqsave().desc = desc;
81     }
82 
83     pub fn clear_irq_desc(&self) {
84         self.inner.lock_irqsave().desc = Weak::new();
85     }
86 
87     pub fn hardware_irq(&self) -> HardwareIrqNumber {
88         self.inner.lock_irqsave().hwirq
89     }
90 
91     /// 是否为电平触发
92     pub fn is_level_type(&self) -> bool {
93         self.inner
94             .lock_irqsave()
95             .common_data
96             .inner
97             .lock_irqsave()
98             .state
99             .is_level_type()
100     }
101 
102     pub fn is_wakeup_set(&self) -> bool {
103         self.inner
104             .lock_irqsave()
105             .common_data
106             .inner
107             .lock_irqsave()
108             .state
109             .is_wakeup_set()
110     }
111 
112     pub fn common_data(&self) -> Arc<IrqCommonData> {
113         self.inner.lock_irqsave().common_data.clone()
114     }
115 
116     pub fn domain(&self) -> Option<Arc<IrqDomain>> {
117         self.inner.lock_irqsave().domain.clone()
118     }
119 
120     pub fn inner(&self) -> SpinLockGuard<InnerIrqData> {
121         self.inner.lock_irqsave()
122     }
123 
124     pub fn chip_info_read(&self) -> RwLockReadGuard<InnerIrqChipInfo> {
125         self.chip_info.read()
126     }
127 
128     pub fn chip_info_read_irqsave(&self) -> RwLockReadGuard<InnerIrqChipInfo> {
129         self.chip_info.read_irqsave()
130     }
131 
132     pub fn chip_info_write_irqsave(&self) -> RwLockWriteGuard<InnerIrqChipInfo> {
133         self.chip_info.write_irqsave()
134     }
135 
136     pub fn parent_data(&self) -> Option<Weak<IrqData>> {
137         self.inner.lock_irqsave().parent_data.clone()
138     }
139 }
140 
141 #[allow(dead_code)]
142 #[derive(Debug)]
143 pub struct InnerIrqData {
144     /// 硬件中断号, 用于表示在某个IrqDomain中的中断号
145     hwirq: HardwareIrqNumber,
146     /// 涉及的所有irqchip之间共享的数据
147     common_data: Arc<IrqCommonData>,
148 
149     desc: Weak<IrqDesc>,
150 
151     /// 中断域
152     domain: Option<Arc<IrqDomain>>,
153     /// 中断的父中断(如果具有中断域继承的话)
154     parent_data: Option<Weak<IrqData>>,
155 }
156 
157 impl InnerIrqData {
158     pub fn set_hwirq(&mut self, hwirq: HardwareIrqNumber) {
159         self.hwirq = hwirq;
160     }
161 
162     #[allow(dead_code)]
163     pub fn domain(&self) -> Option<Arc<IrqDomain>> {
164         self.domain.clone()
165     }
166 
167     pub fn set_domain(&mut self, domain: Option<Arc<IrqDomain>>) {
168         self.domain = domain;
169     }
170 }
171 
172 #[derive(Debug)]
173 pub struct InnerIrqChipInfo {
174     /// 绑定到的中断芯片
175     chip: Option<Arc<dyn IrqChip>>,
176     /// 中断芯片的私有数据(与当前irq相关)
177     chip_data: Option<Arc<dyn IrqChipData>>,
178 }
179 
180 impl InnerIrqChipInfo {
181     pub fn set_chip(&mut self, chip: Option<Arc<dyn IrqChip>>) {
182         self.chip = chip;
183     }
184 
185     pub fn set_chip_data(&mut self, chip_data: Option<Arc<dyn IrqChipData>>) {
186         self.chip_data = chip_data;
187     }
188 
189     pub fn chip(&self) -> Arc<dyn IrqChip> {
190         self.chip.clone().unwrap()
191     }
192 
193     pub fn chip_data(&self) -> Option<Arc<dyn IrqChipData>> {
194         self.chip_data.clone()
195     }
196 }
197 
198 /// per irq data shared by all irqchips
199 ///
200 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147
201 #[derive(Debug)]
202 pub struct IrqCommonData {
203     inner: SpinLock<InnerIrqCommonData>,
204 }
205 
206 impl IrqCommonData {
207     pub fn new() -> Self {
208         let inner = InnerIrqCommonData {
209             state: IrqStatus::empty(),
210             handler_data: None,
211             msi_desc: None,
212             affinity: CpuMask::new(),
213         };
214         return IrqCommonData {
215             inner: SpinLock::new(inner),
216         };
217     }
218 
219     pub fn insert_status(&self, status: IrqStatus) {
220         self.inner.lock_irqsave().irqd_insert(status);
221     }
222 
223     pub fn clear_status(&self, status: IrqStatus) {
224         self.inner.lock_irqsave().irqd_clear(status);
225     }
226 
227     pub fn clear_managed_shutdown(&self) {
228         self.inner
229             .lock_irqsave()
230             .state
231             .remove(IrqStatus::IRQD_MANAGED_SHUTDOWN);
232     }
233 
234     #[allow(dead_code)]
235     pub fn masked(&self) -> bool {
236         self.inner.lock_irqsave().state.masked()
237     }
238 
239     pub fn set_masked(&self) {
240         self.inner
241             .lock_irqsave()
242             .state
243             .insert(IrqStatus::IRQD_IRQ_MASKED);
244     }
245 
246     pub fn clear_masked(&self) {
247         self.clear_status(IrqStatus::IRQD_IRQ_MASKED);
248     }
249 
250     pub fn set_inprogress(&self) {
251         self.inner
252             .lock_irqsave()
253             .state
254             .insert(IrqStatus::IRQD_IRQ_INPROGRESS);
255     }
256 
257     pub fn clear_inprogress(&self) {
258         self.inner
259             .lock_irqsave()
260             .state
261             .remove(IrqStatus::IRQD_IRQ_INPROGRESS);
262     }
263 
264     pub fn disabled(&self) -> bool {
265         self.inner.lock_irqsave().state.disabled()
266     }
267 
268     #[allow(dead_code)]
269     pub fn set_disabled(&self) {
270         self.inner
271             .lock_irqsave()
272             .state
273             .insert(IrqStatus::IRQD_IRQ_DISABLED);
274     }
275 
276     pub fn clear_disabled(&self) {
277         self.clear_status(IrqStatus::IRQD_IRQ_DISABLED);
278     }
279 
280     pub fn status(&self) -> IrqStatus {
281         self.inner.lock_irqsave().state
282     }
283 
284     pub fn trigger_type(&self) -> IrqLineStatus {
285         self.inner.lock_irqsave().state.trigger_type()
286     }
287 
288     pub fn set_trigger_type(&self, trigger: IrqLineStatus) {
289         self.inner.lock_irqsave().state.set_trigger_type(trigger);
290     }
291 
292     pub fn set_started(&self) {
293         self.inner
294             .lock_irqsave()
295             .state
296             .insert(IrqStatus::IRQD_IRQ_STARTED);
297     }
298 
299     pub fn affinity(&self) -> CpuMask {
300         self.inner.lock_irqsave().affinity.clone()
301     }
302 
303     pub fn set_affinity(&self, affinity: CpuMask) {
304         self.inner.lock_irqsave().affinity = affinity;
305     }
306 
307     pub fn inner(&self) -> SpinLockGuard<InnerIrqCommonData> {
308         self.inner.lock_irqsave()
309     }
310 }
311 
312 #[allow(dead_code)]
313 #[derive(Debug)]
314 pub struct InnerIrqCommonData {
315     /// status information for irq chip functions.
316     state: IrqStatus,
317     /// per-IRQ data for the irq_chip methods
318     handler_data: Option<Arc<dyn IrqHandlerData>>,
319     msi_desc: Option<Arc<MsiDesc>>,
320     affinity: CpuMask,
321 }
322 
323 impl InnerIrqCommonData {
324     pub fn irqd_insert(&mut self, status: IrqStatus) {
325         self.state.insert(status);
326     }
327 
328     pub fn irqd_clear(&mut self, status: IrqStatus) {
329         self.state.remove(status);
330     }
331 
332     #[allow(dead_code)]
333     pub fn set_handler_data(&mut self, handler_data: Option<Arc<dyn IrqHandlerData>>) {
334         self.handler_data = handler_data;
335     }
336 
337     #[allow(dead_code)]
338     pub fn handler_data(&self) -> Option<Arc<dyn IrqHandlerData>> {
339         self.handler_data.clone()
340     }
341 }
342 
343 /// 中断处理函数传入的数据
344 pub trait IrqHandlerData: Send + Sync + Any + Debug + CastFromSync {}
345 
346 bitflags! {
347     /// 中断线状态
348     /// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h?fi=IRQ_TYPE_PROBE#77
349     #[allow(clippy::bad_bit_mask)]
350     pub struct IrqLineStatus: u32 {
351         /// 默认,未指明类型
352         const IRQ_TYPE_NONE     = 0x00000000;
353         /// 上升沿触发
354         const IRQ_TYPE_EDGE_RISING  = 0x00000001;
355         /// 下降沿触发
356         const IRQ_TYPE_EDGE_FALLING = 0x00000002;
357         /// 上升沿和下降沿触发
358         const IRQ_TYPE_EDGE_BOTH    = Self::IRQ_TYPE_EDGE_RISING.bits | Self::IRQ_TYPE_EDGE_FALLING.bits;
359         /// 高电平触发
360         const IRQ_TYPE_LEVEL_HIGH   = 0x00000004;
361         /// 低电平触发
362         const IRQ_TYPE_LEVEL_LOW    = 0x00000008;
363         /// 过滤掉电平位的掩码
364         const IRQ_TYPE_LEVEL_MASK   = Self::IRQ_TYPE_LEVEL_LOW.bits | Self::IRQ_TYPE_LEVEL_HIGH.bits;
365         /// 上述位掩码的掩码
366         const IRQ_TYPE_SENSE_MASK   = 0x0000000f;
367         /// 某些PICs使用此类型要求 `IrqChip::irq_set_type()` 设置硬件到一个合理的默认值
368         /// (由irqdomain的map()回调使用,以便为新分配的描述符同步硬件状态和软件标志位)。
369         const IRQ_TYPE_DEFAULT      = Self::IRQ_TYPE_SENSE_MASK.bits;
370 
371         /// 特定于探测的过程中的特殊标志
372         const IRQ_TYPE_PROBE        = 0x00000010;
373 
374         /// 中断是电平类型。当上述触发位通过`IrqChip::irq_set_type()` 修改时,也会在代码中更新
375         const IRQ_LEVEL     = 1 << 8;
376         /// 标记一个PER_CPU的中断。将保护其免受亲和性设置的影响
377         const IRQ_PER_CPU       = 1 << 9;
378         /// 中断不能被自动探测
379         const IRQ_NOPROBE       = 1 << 10;
380         /// 中断不能通过request_irq()请求
381         const IRQ_NOREQUEST     = 1 << 11;
382         /// 中断在request/setup_irq()中不会自动启用
383         const IRQ_NOAUTOEN      = 1 << 12;
384         /// 中断不能被平衡(亲和性设置)
385         const IRQ_NO_BALANCING      = 1 << 13;
386         /// 中断可以从进程上下文中迁移
387         const IRQ_MOVE_PCNTXT       = 1 << 14;
388         /// 中断嵌套在另一个线程中
389         const IRQ_NESTED_THREAD = 1 << 15;
390         /// 中断不能被线程化
391         const IRQ_NOTHREAD      = 1 << 16;
392         /// Dev_id是一个per-CPU变量
393         const IRQ_PER_CPU_DEVID = 1 << 17;
394         /// 总是由另一个中断轮询。将其从错误的中断检测机制和核心侧轮询中排除
395         const IRQ_IS_POLLED     = 1 << 18;
396         /// 禁用延迟的中断禁用 (Disable lazy irq disable)
397         const IRQ_DISABLE_UNLAZY    = 1 << 19;
398         /// 在/proc/interrupts中不显示
399         const IRQ_HIDDEN        = 1 << 20;
400         /// 从note_interrupt()调试中排除
401         const IRQ_NO_DEBUG      = 1 << 21;
402     }
403 
404 
405 
406 }
407 
408 impl IrqLineStatus {
409     pub const fn trigger_bits(&self) -> u32 {
410         self.bits & Self::IRQ_TYPE_SENSE_MASK.bits
411     }
412 
413     pub fn trigger_type(&self) -> Self {
414         *self & Self::IRQ_TYPE_SENSE_MASK
415     }
416 
417     pub fn is_level_type(&self) -> bool {
418         self.contains(Self::IRQ_LEVEL)
419     }
420 
421     /// 是否为高电平触发
422     ///
423     /// ## 返回
424     ///
425     /// - 如果不是电平触发类型,则返回None
426     /// - 如果是电平触发类型,则返回Some(bool),当为true时表示高电平触发
427     #[allow(dead_code)]
428     pub fn is_level_high(&self) -> Option<bool> {
429         if !self.is_level_type() {
430             return None;
431         }
432         return Some(self.contains(Self::IRQ_TYPE_LEVEL_HIGH));
433     }
434 
435     #[allow(dead_code)]
436     pub fn is_per_cpu_devid(&self) -> bool {
437         self.contains(Self::IRQ_PER_CPU_DEVID)
438     }
439 }
440 
441 bitflags! {
442     /// 中断状态(存储在IrqCommonData)
443     ///
444     /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#227
445     #[allow(clippy::bad_bit_mask)]
446     pub struct IrqStatus: u32 {
447         const IRQD_TRIGGER_NONE = IrqLineStatus::IRQ_TYPE_NONE.bits();
448         const IRQD_TRIGGER_RISING = IrqLineStatus::IRQ_TYPE_EDGE_RISING.bits();
449         const IRQD_TRIGGER_FALLING = IrqLineStatus::IRQ_TYPE_EDGE_FALLING.bits();
450         const IRQD_TRIGGER_HIGH = IrqLineStatus::IRQ_TYPE_LEVEL_HIGH.bits();
451         const IRQD_TRIGGER_LOW = IrqLineStatus::IRQ_TYPE_LEVEL_LOW.bits();
452 
453         /// 触发类型位的掩码
454         const IRQD_TRIGGER_MASK = 0xf;
455         /// 亲和性设置待处理
456         const IRQD_SETAFFINITY_PENDING = 1 << 8;
457         /// 中断已激活
458         const IRQD_ACTIVATED = 1 << 9;
459         /// 对此IRQ禁用平衡
460         const IRQD_NO_BALANCING = 1 << 10;
461         /// 中断是每个CPU特定的
462         const IRQD_PER_CPU = 1 << 11;
463         /// 中断亲和性已设置
464         const IRQD_AFFINITY_SET = 1 << 12;
465         /// 中断是电平触发
466         const IRQD_LEVEL = 1 << 13;
467         /// 中断配置为从挂起状态唤醒
468         const IRQD_WAKEUP_STATE = 1 << 14;
469         /// 中断可以在进程上下文中移动
470         const IRQD_MOVE_PCNTXT = 1 << 15;
471         /// 中断被禁用
472         const IRQD_IRQ_DISABLED = 1 << 16;
473         /// 中断被屏蔽
474         const IRQD_IRQ_MASKED = 1 << 17;
475         /// 中断正在处理中
476         const IRQD_IRQ_INPROGRESS = 1 << 18;
477         /// 唤醒模式已准备就绪
478         const IRQD_WAKEUP_ARMED = 1 << 19;
479         /// 中断被转发到一个虚拟CPU
480         const IRQD_FORWARDED_TO_VCPU = 1 << 20;
481         /// 亲和性由内核自动管理
482         const IRQD_AFFINITY_MANAGED = 1 << 21;
483         /// 中断已启动
484         const IRQD_IRQ_STARTED = 1 << 22;
485         /// 由于空亲和性掩码而关闭的中断。仅适用于亲和性管理的中断。
486         const IRQD_MANAGED_SHUTDOWN = 1 << 23;
487         /// IRQ只允许单个亲和性目标
488         const IRQD_SINGLE_TARGET = 1 << 24;
489         /// 默认的触发器已设置
490         const IRQD_DEFAULT_TRIGGER_SET = 1 << 25;
491         /// 可以使用保留模式
492         const IRQD_CAN_RESERVE = 1 << 26;
493         /// Non-maskable MSI quirk for affinity change required
494         const IRQD_MSI_NOMASK_QUIRK = 1 << 27;
495         /// 强制要求`handle_irq_()`只能在真实的中断上下文中调用
496         const IRQD_HANDLE_ENFORCE_IRQCTX = 1 << 28;
497         /// 激活时设置亲和性。在禁用时不要调用irq_chip::irq_set_affinity()。
498         const IRQD_AFFINITY_ON_ACTIVATE = 1 << 29;
499         /// 如果irqpm具有标志 IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,则在挂起时中断被启用。
500         const IRQD_IRQ_ENABLED_ON_SUSPEND = 1 << 30;
501     }
502 }
503 
504 #[allow(dead_code)]
505 impl IrqStatus {
506     pub const fn is_set_affinity_pending(&self) -> bool {
507         self.contains(Self::IRQD_SETAFFINITY_PENDING)
508     }
509 
510     pub const fn is_per_cpu(&self) -> bool {
511         self.contains(Self::IRQD_PER_CPU)
512     }
513 
514     pub const fn can_balance(&self) -> bool {
515         (self.bits & (Self::IRQD_PER_CPU.bits | Self::IRQD_NO_BALANCING.bits)) == 0
516     }
517 
518     pub const fn affinity_was_set(&self) -> bool {
519         self.contains(Self::IRQD_AFFINITY_SET)
520     }
521 
522     pub fn masked(&self) -> bool {
523         self.contains(Self::IRQD_IRQ_MASKED)
524     }
525 
526     pub fn disabled(&self) -> bool {
527         self.contains(Self::IRQD_IRQ_DISABLED)
528     }
529 
530     pub fn mark_affinity_set(&mut self) {
531         self.insert(Self::IRQD_AFFINITY_SET);
532     }
533 
534     pub const fn trigger_type_was_set(&self) -> bool {
535         self.contains(Self::IRQD_DEFAULT_TRIGGER_SET)
536     }
537 
538     pub fn mark_trigger_type_set(&mut self) {
539         self.insert(Self::IRQD_DEFAULT_TRIGGER_SET);
540     }
541 
542     pub const fn trigger_type(&self) -> IrqLineStatus {
543         IrqLineStatus::from_bits_truncate(self.bits & Self::IRQD_TRIGGER_MASK.bits)
544     }
545 
546     /// Must only be called inside irq_chip.irq_set_type() functions or
547     /// from the DT/ACPI setup code.
548     pub const fn set_trigger_type(&mut self, trigger: IrqLineStatus) {
549         self.bits &= !Self::IRQD_TRIGGER_MASK.bits;
550         self.bits |= trigger.bits & Self::IRQD_TRIGGER_MASK.bits;
551 
552         self.bits |= Self::IRQD_DEFAULT_TRIGGER_SET.bits;
553     }
554 
555     pub const fn is_level_type(&self) -> bool {
556         self.contains(Self::IRQD_LEVEL)
557     }
558 
559     /// Must only be called of irqchip.irq_set_affinity() or low level
560     /// hierarchy domain allocation functions.
561     pub fn set_single_target(&mut self) {
562         self.insert(Self::IRQD_SINGLE_TARGET);
563     }
564 
565     pub const fn is_single_target(&self) -> bool {
566         self.contains(Self::IRQD_SINGLE_TARGET)
567     }
568 
569     pub fn set_handle_enforce_irqctx(&mut self) {
570         self.insert(Self::IRQD_HANDLE_ENFORCE_IRQCTX);
571     }
572 
573     pub const fn is_handle_enforce_irqctx(&self) -> bool {
574         self.contains(Self::IRQD_HANDLE_ENFORCE_IRQCTX)
575     }
576 
577     pub const fn is_enabled_on_suspend(&self) -> bool {
578         self.contains(Self::IRQD_IRQ_ENABLED_ON_SUSPEND)
579     }
580 
581     pub const fn is_wakeup_set(&self) -> bool {
582         self.contains(Self::IRQD_WAKEUP_STATE)
583     }
584 
585     pub const fn can_move_in_process_context(&self) -> bool {
586         self.contains(Self::IRQD_MOVE_PCNTXT)
587     }
588 
589     pub const fn is_irq_in_progress(&self) -> bool {
590         self.contains(Self::IRQD_IRQ_INPROGRESS)
591     }
592 
593     pub const fn is_wakeup_armed(&self) -> bool {
594         self.contains(Self::IRQD_WAKEUP_ARMED)
595     }
596 
597     pub const fn is_forwarded_to_vcpu(&self) -> bool {
598         self.contains(Self::IRQD_FORWARDED_TO_VCPU)
599     }
600 
601     pub fn set_forwarded_to_vcpu(&mut self) {
602         self.insert(Self::IRQD_FORWARDED_TO_VCPU);
603     }
604 
605     pub const fn affinity_managed(&self) -> bool {
606         self.contains(Self::IRQD_AFFINITY_MANAGED)
607     }
608 
609     pub const fn is_activated(&self) -> bool {
610         self.contains(Self::IRQD_ACTIVATED)
611     }
612 
613     pub fn set_activated(&mut self) {
614         self.insert(Self::IRQD_ACTIVATED);
615     }
616 
617     pub fn clear_activated(&mut self) {
618         self.remove(Self::IRQD_ACTIVATED);
619     }
620 
621     pub const fn is_started(&self) -> bool {
622         self.contains(Self::IRQD_IRQ_STARTED)
623     }
624 
625     pub const fn is_managed_and_shutdown(&self) -> bool {
626         self.contains(Self::IRQD_MANAGED_SHUTDOWN)
627     }
628 
629     pub fn set_can_reserve(&mut self) {
630         self.insert(Self::IRQD_CAN_RESERVE);
631     }
632 
633     pub const fn can_reserve(&self) -> bool {
634         self.contains(Self::IRQD_CAN_RESERVE)
635     }
636 
637     pub fn clear_can_reserve(&mut self) {
638         self.remove(Self::IRQD_CAN_RESERVE);
639     }
640 
641     pub fn set_msi_nomask_quirk(&mut self) {
642         self.insert(Self::IRQD_MSI_NOMASK_QUIRK);
643     }
644 
645     pub fn clear_msi_nomask_quirk(&mut self) {
646         self.remove(Self::IRQD_MSI_NOMASK_QUIRK);
647     }
648 
649     pub const fn is_msi_nomask_quirk(&self) -> bool {
650         self.contains(Self::IRQD_MSI_NOMASK_QUIRK)
651     }
652 
653     pub fn set_affinity_on_activate(&mut self) {
654         self.insert(Self::IRQD_AFFINITY_ON_ACTIVATE);
655     }
656 
657     pub const fn is_affinity_on_activate(&self) -> bool {
658         self.contains(Self::IRQD_AFFINITY_ON_ACTIVATE)
659     }
660 
661     pub const fn started(&self) -> bool {
662         self.contains(Self::IRQD_IRQ_STARTED)
663     }
664 }
665