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