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