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