1 use core::fmt::Debug; 2 3 use alloc::{ 4 string::{String, ToString}, 5 sync::{Arc, Weak}, 6 vec::Vec, 7 }; 8 use hashbrown::HashMap; 9 use system_error::SystemError; 10 11 use crate::{ 12 driver::{base::device::Device, open_firmware::device_node::DeviceNode}, 13 exception::{irqdata::IrqLineStatus, irqdesc::irq_desc_manager, manage::irq_manager}, 14 libs::{ 15 rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, 16 spinlock::SpinLock, 17 }, 18 }; 19 20 use super::{ 21 dummychip::no_irq_chip, 22 irqchip::{IrqChip, IrqChipData, IrqChipGeneric, IrqGcFlags}, 23 irqdata::{IrqData, IrqHandlerData}, 24 irqdesc::{IrqDesc, IrqFlowHandler}, 25 HardwareIrqNumber, IrqNumber, 26 }; 27 28 static mut IRQ_DOMAIN_MANAGER: Option<Arc<IrqDomainManager>> = None; 29 30 /// 获取中断域管理器的引用 31 #[inline(always)] 32 pub fn irq_domain_manager() -> &'static Arc<IrqDomainManager> { 33 unsafe { IRQ_DOMAIN_MANAGER.as_ref().unwrap() } 34 } 35 36 pub(super) fn irq_domain_manager_init() { 37 unsafe { 38 IRQ_DOMAIN_MANAGER = Some(Arc::new(IrqDomainManager::new())); 39 } 40 } 41 /// 中断域管理器 42 pub struct IrqDomainManager { 43 domains: SpinLock<Vec<Arc<IrqDomain>>>, 44 inner: RwLock<InnerIrqDomainManager>, 45 } 46 47 impl IrqDomainManager { 48 pub fn new() -> IrqDomainManager { 49 IrqDomainManager { 50 domains: SpinLock::new(Vec::new()), 51 inner: RwLock::new(InnerIrqDomainManager { 52 default_domain: None, 53 }), 54 } 55 } 56 57 /// 创建一个新的线性映射的irqdomain, 并将其添加到irqdomain管理器中 58 /// 59 /// 创建的irqdomain,中断号是线性的,即从0开始,依次递增 60 /// 61 /// ## 参数 62 /// 63 /// - `name` - 中断域的名字 64 /// - `ops` - 中断域的操作 65 /// - `irq_size` - 中断号的数量 66 #[allow(dead_code)] 67 pub fn create_and_add_linear( 68 &self, 69 name: String, 70 ops: &'static dyn IrqDomainOps, 71 irq_size: u32, 72 ) -> Option<Arc<IrqDomain>> { 73 self.create_and_add( 74 name, 75 ops, 76 IrqNumber::new(0), 77 HardwareIrqNumber::new(0), 78 irq_size, 79 ) 80 } 81 82 /// 创建一个新的irqdomain, 并将其添加到irqdomain管理器中 83 /// 84 /// ## 参数 85 /// 86 /// - `name` - 中断域的名字 87 /// - `ops` - 中断域的操作 88 /// - `first_irq` - 起始软件中断号 89 /// - `first_hwirq` - 起始硬件中断号 90 /// - `irq_size` - 中断号的数量 91 /// 92 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdomain.c?fi=__irq_domain_add#139 93 pub fn create_and_add( 94 &self, 95 name: String, 96 ops: &'static dyn IrqDomainOps, 97 first_irq: IrqNumber, 98 first_hwirq: HardwareIrqNumber, 99 irq_size: u32, 100 ) -> Option<Arc<IrqDomain>> { 101 let domain = IrqDomain::new( 102 None, 103 Some(name), 104 ops, 105 IrqDomainFlags::NAME_ALLOCATED, 106 IrqDomainBusToken::Any, 107 first_irq + irq_size, 108 first_hwirq + irq_size, 109 )?; 110 111 self.add_domain(domain.clone()); 112 113 return Some(domain); 114 } 115 116 fn add_domain(&self, domain: Arc<IrqDomain>) { 117 self.domains.lock_irqsave().push(domain); 118 } 119 120 #[allow(dead_code)] 121 pub fn remove_domain(&self, domain: &Arc<IrqDomain>) { 122 let mut domains = self.domains.lock_irqsave(); 123 let index = domains 124 .iter() 125 .position(|x| Arc::ptr_eq(x, domain)) 126 .expect("domain not found"); 127 domains.remove(index); 128 } 129 130 /// 获取默认的中断域 131 #[allow(dead_code)] 132 pub fn default_domain(&self) -> Option<Arc<IrqDomain>> { 133 self.inner.read().default_domain.clone() 134 } 135 136 /// 设置默认的中断域 137 /// 138 /// 在创建IRQ映射的时候,如果没有指定中断域,就会使用默认的中断域 139 pub fn set_default_domain(&self, domain: Arc<IrqDomain>) { 140 self.inner.write_irqsave().default_domain = Some(domain); 141 } 142 143 /// 将指定范围的硬件中断号与软件中断号一一对应的关联起来 144 /// 145 /// ## 参数 146 /// 147 /// - `domain` - 中断域 148 /// - `first_irq` - 起始软件中断号 149 /// - `first_hwirq` - 起始硬件中断号 150 /// - `count` - 数量 151 pub fn domain_associate_many( 152 &self, 153 domain: &Arc<IrqDomain>, 154 first_irq: IrqNumber, 155 first_hwirq: HardwareIrqNumber, 156 count: u32, 157 ) { 158 for i in 0..count { 159 if let Err(e) = self.domain_associate(domain, first_irq + i, first_hwirq + i) { 160 kwarn!("domain associate failed: {:?}, domain '{:?}' didn't like hwirq {} to virq {} mapping.", e, domain.name(), (first_hwirq + i).data(), (first_irq + i).data()); 161 } 162 } 163 } 164 165 /// 将一个硬件中断号与一个软件中断号关联起来 166 /// 167 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdomain.c#562 168 pub fn domain_associate( 169 &self, 170 domain: &Arc<IrqDomain>, 171 irq: IrqNumber, 172 hwirq: HardwareIrqNumber, 173 ) -> Result<(), SystemError> { 174 if hwirq >= domain.revmap.read_irqsave().hwirq_max { 175 kwarn!( 176 "hwirq {} is out of range for domain {:?}", 177 hwirq.data(), 178 domain.name() 179 ); 180 return Err(SystemError::EINVAL); 181 } 182 let irq_data = irq_desc_manager() 183 .lookup(irq) 184 .ok_or_else(|| { 185 kwarn!("irq_desc not found for irq {}", irq.data()); 186 SystemError::EINVAL 187 })? 188 .irq_data(); 189 if irq_data.domain().is_some() { 190 kwarn!( 191 "irq {} is already associated with domain {:?}", 192 irq.data(), 193 irq_data.domain().unwrap().name() 194 ); 195 return Err(SystemError::EINVAL); 196 } 197 198 let mut irq_data_guard = irq_data.inner(); 199 irq_data_guard.set_hwirq(hwirq); 200 irq_data_guard.set_domain(Some(domain.clone())); 201 drop(irq_data_guard); 202 let r = domain.ops.map(domain, hwirq, irq); 203 if let Err(e) = r { 204 if e != SystemError::ENOSYS { 205 if e != SystemError::EPERM { 206 kinfo!("domain associate failed: {:?}, domain '{:?}' didn't like hwirq {} to virq {} mapping.", e, domain.name(), hwirq.data(), irq.data()); 207 } 208 let mut irq_data_guard = irq_data.inner(); 209 irq_data_guard.set_domain(None); 210 irq_data_guard.set_hwirq(HardwareIrqNumber::new(0)); 211 return Err(e); 212 } 213 } 214 215 if domain.name().is_none() { 216 let chip = irq_data.chip_info_read_irqsave().chip(); 217 domain.set_name(chip.name().to_string()); 218 } 219 220 self.irq_domain_set_mapping(domain, hwirq, irq_data); 221 222 irq_manager().irq_clear_status_flags(irq, IrqLineStatus::IRQ_NOREQUEST)?; 223 224 return Ok(()); 225 } 226 227 fn irq_domain_set_mapping( 228 &self, 229 domain: &Arc<IrqDomain>, 230 hwirq: HardwareIrqNumber, 231 irq_data: Arc<IrqData>, 232 ) { 233 if domain.no_map() { 234 return; 235 } 236 237 domain.revmap.write_irqsave().insert(hwirq, irq_data); 238 } 239 /// 递归调用 domain_ops->activate 以激活中断 240 /// 241 /// ## 参数 242 /// 243 /// - irq_data: 与中断关联的最外层 irq_data 244 /// - reserve: 如果为true,则仅预留一个中断向量,而不是分配一个 245 /// 246 /// 这是调用 domain_ops->activate 以编程中断控制器的第二步,以便中断实际上可以被传递。 247 pub fn activate_irq(&self, irq_data: &Arc<IrqData>, reserve: bool) -> Result<(), SystemError> { 248 let mut r = Ok(()); 249 // kdebug!( 250 // "activate_irq: irq_data.common_data().status().is_activated()={}", 251 // irq_data.common_data().status().is_activated() 252 // ); 253 if !irq_data.common_data().status().is_activated() { 254 r = self.do_activate_irq(Some(irq_data.clone()), reserve); 255 } 256 257 if r.is_err() { 258 irq_data.common_data().status().set_activated(); 259 } 260 261 return r; 262 } 263 264 #[inline(never)] 265 fn do_activate_irq( 266 &self, 267 irq_data: Option<Arc<IrqData>>, 268 reserve: bool, 269 ) -> Result<(), SystemError> { 270 let mut r = Ok(()); 271 272 if let Some(irq_data) = irq_data { 273 // kdebug!("do_activate_irq: irq_data={:?}", irq_data); 274 if let Some(domain) = irq_data.domain() { 275 // kdebug!("do_activate_irq: domain={:?}", domain.name()); 276 let parent_data = irq_data.parent_data().and_then(|x| x.upgrade()); 277 if let Some(parent_data) = parent_data.clone() { 278 r = self.do_activate_irq(Some(parent_data), reserve); 279 } 280 281 if r.is_err() { 282 let tmpr = domain.ops.activate(&domain, &irq_data, reserve); 283 if let Err(e) = tmpr { 284 if e != SystemError::ENOSYS && parent_data.is_some() { 285 self.do_deactivate_irq(parent_data); 286 } 287 } 288 } 289 } 290 } 291 292 return r; 293 } 294 #[allow(clippy::only_used_in_recursion)] 295 fn do_deactivate_irq(&self, irq_data: Option<Arc<IrqData>>) { 296 if let Some(irq_data) = irq_data { 297 if let Some(domain) = irq_data.domain() { 298 domain.ops.deactivate(&domain, &irq_data); 299 let pp = irq_data.parent_data().and_then(|x| x.upgrade()); 300 301 if pp.is_some() { 302 self.do_deactivate_irq(pp); 303 } 304 } 305 } 306 } 307 308 /// `irq_domain_set_info` - 在 @domain 中为 @virq 设置完整的数据 309 /// 310 /// ## 参数 311 /// 312 /// - `domain`: 要匹配的中断域 313 /// - `virq`: IRQ号 314 /// - `hwirq`: 硬件中断号 315 /// - `chip`: 相关的中断芯片 316 /// - `chip_data`: 相关的中断芯片数据 317 /// - `handler`: 中断流处理器 318 /// - `handler_data`: 中断流处理程序数据 319 /// - `handler_name`: 中断处理程序名称 320 #[allow(clippy::too_many_arguments)] 321 pub fn domain_set_info( 322 &self, 323 domain: &Arc<IrqDomain>, 324 virq: IrqNumber, 325 hwirq: HardwareIrqNumber, 326 chip: Arc<dyn IrqChip>, 327 chip_data: Option<Arc<dyn IrqChipData>>, 328 flow_handler: &'static dyn IrqFlowHandler, 329 handler_data: Option<Arc<dyn IrqHandlerData>>, 330 handler_name: Option<String>, 331 ) { 332 let r = self.domain_set_hwirq_and_chip(domain, virq, hwirq, Some(chip), chip_data); 333 if r.is_err() { 334 return; 335 } 336 irq_manager().__irq_set_handler(virq, flow_handler, false, handler_name); 337 irq_manager().irq_set_handler_data(virq, handler_data).ok(); 338 } 339 340 /// `domain_set_hwirq_and_chip` - 在 @domain 中为 @virq 设置 hwirq 和 irqchip 341 /// 342 /// ## 参数 343 /// 344 /// - `domain`: 要匹配的中断域 345 /// - `virq`: IRQ号 346 /// - `hwirq`: hwirq号 347 /// - `chip`: 相关的中断芯片 348 /// - `chip_data`: 相关的芯片数据 349 pub fn domain_set_hwirq_and_chip( 350 &self, 351 domain: &Arc<IrqDomain>, 352 virq: IrqNumber, 353 hwirq: HardwareIrqNumber, 354 chip: Option<Arc<dyn IrqChip>>, 355 chip_data: Option<Arc<dyn IrqChipData>>, 356 ) -> Result<(), SystemError> { 357 let irq_data: Arc<IrqData> = self 358 .domain_get_irq_data(domain, virq) 359 .ok_or(SystemError::ENOENT)?; 360 let mut inner = irq_data.inner(); 361 let mut chip_info = irq_data.chip_info_write_irqsave(); 362 363 inner.set_hwirq(hwirq); 364 if let Some(chip) = chip { 365 chip_info.set_chip(Some(chip)); 366 } else { 367 chip_info.set_chip(Some(no_irq_chip())); 368 }; 369 370 chip_info.set_chip_data(chip_data); 371 372 return Ok(()); 373 } 374 375 /// `irq_domain_get_irq_data` - 获取与 @virq 和 @domain 关联的 irq_data 376 /// 377 /// ## 参数 378 /// 379 /// - `domain`: 要匹配的域 380 /// - `virq`: 要获取 irq_data 的IRQ号 381 pub fn domain_get_irq_data( 382 &self, 383 domain: &Arc<IrqDomain>, 384 virq: IrqNumber, 385 ) -> Option<Arc<IrqData>> { 386 let desc = irq_desc_manager().lookup(virq)?; 387 let mut irq_data = Some(desc.irq_data()); 388 389 while irq_data.is_some() { 390 let dt = irq_data.unwrap(); 391 if dt.domain().is_some() && Arc::ptr_eq(dt.domain().as_ref().unwrap(), domain) { 392 return Some(dt); 393 } 394 irq_data = dt.parent_data().and_then(|x| x.upgrade()); 395 } 396 397 return None; 398 } 399 400 /// `resolve_irq_mapping` - 从硬件中断号找到中断号。 401 /// 402 /// ## 参数 403 /// 404 /// - `domain`: 拥有此硬件中断的域 405 /// - `hwirq`: 该域空间中的硬件中断号 406 /// - `irq`: 如果需要,可选的指针以返回Linux中断 407 /// 408 /// ## 返回 409 /// 410 /// 返回一个元组,包含中断描述符和中断号 411 pub fn resolve_irq_mapping( 412 &self, 413 mut domain: Option<Arc<IrqDomain>>, 414 hwirq: HardwareIrqNumber, 415 ) -> Result<(Arc<IrqDesc>, IrqNumber), SystemError> { 416 if domain.is_none() { 417 domain = Some(self.default_domain().ok_or(SystemError::EINVAL)?); 418 } 419 420 let domain = domain.unwrap(); 421 422 if domain.no_map() { 423 if hwirq < domain.revmap_read_irqsave().hwirq_max { 424 let irq_desc = irq_desc_manager() 425 .lookup(IrqNumber::new(hwirq.data())) 426 .ok_or(SystemError::EINVAL)?; 427 if irq_desc.irq_data().hardware_irq() == hwirq { 428 let irq = irq_desc.irq_data().irq(); 429 return Ok((irq_desc, irq)); 430 } 431 } 432 433 return Err(SystemError::EINVAL); 434 } 435 436 let revmap = domain.revmap_read_irqsave(); 437 let irq_data = revmap.lookup(hwirq).ok_or(SystemError::EINVAL)?; 438 let irq_desc = irq_data.irq_desc().unwrap(); 439 return Ok((irq_desc, irq_data.irq())); 440 } 441 } 442 443 struct InnerIrqDomainManager { 444 default_domain: Option<Arc<IrqDomain>>, 445 } 446 447 /// 中断域 448 /// 449 /// 用于把硬件中断号翻译为软件中断号的映射的对象 450 /// 451 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#164 452 #[allow(dead_code)] 453 #[derive(Debug)] 454 pub struct IrqDomain { 455 /// 中断域的名字 (二选一) 456 name: Option<&'static str>, 457 allocated_name: SpinLock<Option<String>>, 458 /// 中断域的操作 459 ops: &'static dyn IrqDomainOps, 460 inner: SpinLock<InnerIrqDomain>, 461 /// 中断号反向映射 462 revmap: RwLock<IrqDomainRevMap>, 463 } 464 465 #[allow(dead_code)] 466 #[derive(Debug)] 467 struct InnerIrqDomain { 468 /// this field not touched by the core code 469 host_data: Option<Arc<dyn IrqChipData>>, 470 /// host per irq_domain flags 471 flags: IrqDomainFlags, 472 /// The number of mapped interrupts 473 mapcount: u32, 474 bus_token: IrqDomainBusToken, 475 /// 指向 generic chip 列表的指针。 476 /// 有一个辅助函数用于为中断控制器驱动程序设置一个或 477 /// 多个 generic chip,该函数使用此指针并依赖于 generic chip 库。 478 generic_chip: Option<Arc<IrqDomainChipGeneric>>, 479 /// Pointer to a device that the domain represent, and that will be 480 /// used for power management purposes. 481 device: Option<Arc<dyn Device>>, 482 /// Pointer to parent irq_domain to support hierarchy irq_domains 483 parent: Option<Weak<IrqDomain>>, 484 } 485 486 impl IrqDomain { 487 #[allow(dead_code)] 488 pub fn new( 489 name: Option<&'static str>, 490 allocated_name: Option<String>, 491 ops: &'static dyn IrqDomainOps, 492 flags: IrqDomainFlags, 493 bus_token: IrqDomainBusToken, 494 irq_max: IrqNumber, 495 hwirq_max: HardwareIrqNumber, 496 ) -> Option<Arc<Self>> { 497 if name.is_none() && allocated_name.is_none() { 498 return None; 499 } 500 501 let x = IrqDomain { 502 name, 503 allocated_name: SpinLock::new(allocated_name), 504 ops, 505 inner: SpinLock::new(InnerIrqDomain { 506 host_data: None, 507 flags, 508 mapcount: 0, 509 bus_token, 510 generic_chip: None, 511 device: None, 512 parent: None, 513 }), 514 revmap: RwLock::new(IrqDomainRevMap { 515 map: HashMap::new(), 516 hwirq_max, 517 irq_max, 518 }), 519 }; 520 521 return Some(Arc::new(x)); 522 } 523 524 /// 中断域是否不对中断号进行转换 525 pub fn no_map(&self) -> bool { 526 self.inner 527 .lock_irqsave() 528 .flags 529 .contains(IrqDomainFlags::NO_MAP) 530 } 531 532 #[allow(dead_code)] 533 fn revmap_read_irqsave(&self) -> RwLockReadGuard<IrqDomainRevMap> { 534 self.revmap.read_irqsave() 535 } 536 537 #[allow(dead_code)] 538 fn revmap_write_irqsave(&self) -> RwLockWriteGuard<IrqDomainRevMap> { 539 self.revmap.write_irqsave() 540 } 541 542 #[allow(dead_code)] 543 fn set_hwirq_max(&self, hwirq_max: HardwareIrqNumber) { 544 self.revmap_write_irqsave().hwirq_max = hwirq_max; 545 } 546 547 pub fn name(&self) -> Option<String> { 548 if let Some(name) = self.name { 549 return Some(name.to_string()); 550 } 551 return self.allocated_name.lock_irqsave().clone(); 552 } 553 554 pub fn set_name(&self, name: String) { 555 *self.allocated_name.lock_irqsave() = Some(name); 556 } 557 558 /// The number of mapped interrupts 559 pub fn map_count(&self) -> u32 { 560 self.revmap_read_irqsave().map.len() as u32 561 } 562 563 pub fn host_data(&self) -> Option<Arc<dyn IrqChipData>> { 564 self.inner.lock_irqsave().host_data.clone() 565 } 566 567 pub fn set_host_data(&self, host_data: Option<Arc<dyn IrqChipData>>) { 568 self.inner.lock_irqsave().host_data = host_data; 569 } 570 } 571 572 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190 573 #[allow(dead_code)] 574 #[derive(Debug)] 575 struct IrqDomainRevMap { 576 map: HashMap<HardwareIrqNumber, Arc<IrqData>>, 577 hwirq_max: HardwareIrqNumber, 578 irq_max: IrqNumber, 579 } 580 581 impl IrqDomainRevMap { 582 fn insert(&mut self, hwirq: HardwareIrqNumber, irq_data: Arc<IrqData>) { 583 self.map.insert(hwirq, irq_data); 584 } 585 586 #[allow(dead_code)] 587 fn remove(&mut self, hwirq: HardwareIrqNumber) { 588 self.map.remove(&hwirq); 589 } 590 591 #[allow(dead_code)] 592 fn lookup(&self, hwirq: HardwareIrqNumber) -> Option<Arc<IrqData>> { 593 self.map.get(&hwirq).cloned() 594 } 595 } 596 597 bitflags! { 598 pub struct IrqDomainFlags: u32 { 599 /// Irq domain is hierarchical 600 const HIERARCHY = (1 << 0); 601 /// Irq domain name was allocated dynamically 602 const NAME_ALLOCATED = (1 << 1); 603 /// Irq domain is an IPI domain with virq per cpu 604 const IPI_PER_CPU = (1 << 2); 605 /// Irq domain is an IPI domain with single virq 606 const IPI_SINGLE = (1 << 3); 607 /// Irq domain implements MSIs 608 const MSI = (1 << 4); 609 /// Irq domain implements MSI remapping 610 const MSI_REMAP = (1 << 5); 611 /// Quirk to handle MSI implementations which do not provide masking 612 const MSI_NOMASK_QUIRK = (1 << 6); 613 /// Irq domain doesn't translate anything 614 const NO_MAP = (1 << 7); 615 /// Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved 616 /// for implementation specific purposes and ignored by the core code 617 const NONCORE = (1 << 16); 618 } 619 } 620 621 /// 如果多个域有相同的设备节点,但服务于不同的目的(例如,一个域用于PCI/MSI,另一个用于有线IRQs), 622 /// 它们可以使用特定于总线的token进行区分。预计大多数域只会携带`DomainBusAny`。 623 /// 624 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#78 625 #[allow(dead_code)] 626 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 627 pub enum IrqDomainBusToken { 628 Any = 0, 629 Wired, 630 GenericMsi, 631 PciMsi, 632 PlatformMsi, 633 Nexus, 634 Ipi, 635 FslMcMsi, 636 TiSciIntaMsi, 637 Wakeup, 638 VmdMsi, 639 } 640 641 /// IrqDomain的操作方法 642 /// 643 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107 644 pub trait IrqDomainOps: Debug + Send + Sync { 645 /// 匹配一个中断控制器设备节点到一个主机。 646 fn match_node( 647 &self, 648 _irq_domain: &Arc<IrqDomain>, 649 _device_node: &Arc<DeviceNode>, 650 _bus_token: IrqDomainBusToken, 651 ) -> bool { 652 false 653 } 654 655 /// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。 656 /// 对于给定的映射,这只会被调用一次。 657 /// 658 /// 如果没有实现这个方法,那么就会返回`ENOSYS` 659 fn map( 660 &self, 661 _irq_domain: &Arc<IrqDomain>, 662 _hwirq: HardwareIrqNumber, 663 _virq: IrqNumber, 664 ) -> Result<(), SystemError> { 665 Err(SystemError::ENOSYS) 666 } 667 668 /// 删除一个虚拟中断号与一个硬件中断号之间的映射。 669 fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber); 670 671 fn activate( 672 &self, 673 _domain: &Arc<IrqDomain>, 674 _irq_data: &Arc<IrqData>, 675 _reserve: bool, 676 ) -> Result<(), SystemError> { 677 Err(SystemError::ENOSYS) 678 } 679 680 fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {} 681 } 682 683 #[allow(dead_code)] 684 #[derive(Debug)] 685 pub struct IrqDomainChipGeneric { 686 inner: SpinLock<InnerIrqDomainChipGeneric>, 687 } 688 689 #[allow(dead_code)] 690 #[derive(Debug)] 691 struct InnerIrqDomainChipGeneric { 692 irqs_per_chip: u32, 693 flags_to_clear: IrqGcFlags, 694 flags_to_set: IrqGcFlags, 695 gc_flags: IrqGcFlags, 696 gc: Vec<Arc<IrqChipGeneric>>, 697 } 698