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