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_err() { 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 let Some(irq_data) = irq_data { 268 if let Some(domain) = irq_data.domain() { 269 let parent_data = irq_data.parent_data().and_then(|x| x.upgrade()); 270 if let Some(parent_data) = parent_data.clone() { 271 r = self.do_activate_irq(Some(parent_data), reserve); 272 } 273 274 if r.is_err() { 275 let tmpr = domain.ops.activate(&domain, &irq_data, reserve); 276 if let Err(e) = tmpr { 277 if e != SystemError::ENOSYS && parent_data.is_some() { 278 self.do_deactivate_irq(parent_data); 279 } 280 } 281 } 282 } 283 } 284 285 return r; 286 } 287 #[allow(clippy::only_used_in_recursion)] 288 fn do_deactivate_irq(&self, irq_data: Option<Arc<IrqData>>) { 289 if let Some(irq_data) = irq_data { 290 if let Some(domain) = irq_data.domain() { 291 domain.ops.deactivate(&domain, &irq_data); 292 let pp = irq_data.parent_data().and_then(|x| x.upgrade()); 293 294 if pp.is_some() { 295 self.do_deactivate_irq(pp); 296 } 297 } 298 } 299 } 300 301 /// `irq_domain_set_info` - 在 @domain 中为 @virq 设置完整的数据 302 /// 303 /// ## 参数 304 /// 305 /// - `domain`: 要匹配的中断域 306 /// - `virq`: IRQ号 307 /// - `hwirq`: 硬件中断号 308 /// - `chip`: 相关的中断芯片 309 /// - `chip_data`: 相关的中断芯片数据 310 /// - `handler`: 中断流处理器 311 /// - `handler_data`: 中断流处理程序数据 312 /// - `handler_name`: 中断处理程序名称 313 #[allow(clippy::too_many_arguments)] 314 pub fn domain_set_info( 315 &self, 316 domain: &Arc<IrqDomain>, 317 virq: IrqNumber, 318 hwirq: HardwareIrqNumber, 319 chip: Arc<dyn IrqChip>, 320 chip_data: Option<Arc<dyn IrqChipData>>, 321 flow_handler: &'static dyn IrqFlowHandler, 322 handler_data: Option<Arc<dyn IrqHandlerData>>, 323 handler_name: Option<String>, 324 ) { 325 let r = self.domain_set_hwirq_and_chip(domain, virq, hwirq, Some(chip), chip_data); 326 if r.is_err() { 327 return; 328 } 329 irq_manager().__irq_set_handler(virq, flow_handler, false, handler_name); 330 irq_manager().irq_set_handler_data(virq, handler_data).ok(); 331 } 332 333 /// `domain_set_hwirq_and_chip` - 在 @domain 中为 @virq 设置 hwirq 和 irqchip 334 /// 335 /// ## 参数 336 /// 337 /// - `domain`: 要匹配的中断域 338 /// - `virq`: IRQ号 339 /// - `hwirq`: hwirq号 340 /// - `chip`: 相关的中断芯片 341 /// - `chip_data`: 相关的芯片数据 342 pub fn domain_set_hwirq_and_chip( 343 &self, 344 domain: &Arc<IrqDomain>, 345 virq: IrqNumber, 346 hwirq: HardwareIrqNumber, 347 chip: Option<Arc<dyn IrqChip>>, 348 chip_data: Option<Arc<dyn IrqChipData>>, 349 ) -> Result<(), SystemError> { 350 let irq_data: Arc<IrqData> = self 351 .domain_get_irq_data(domain, virq) 352 .ok_or(SystemError::ENOENT)?; 353 let mut inner = irq_data.inner(); 354 let mut chip_info = irq_data.chip_info_write_irqsave(); 355 356 inner.set_hwirq(hwirq); 357 if let Some(chip) = chip { 358 chip_info.set_chip(Some(chip)); 359 } else { 360 chip_info.set_chip(Some(no_irq_chip())); 361 }; 362 363 chip_info.set_chip_data(chip_data); 364 365 return Ok(()); 366 } 367 368 /// `irq_domain_get_irq_data` - 获取与 @virq 和 @domain 关联的 irq_data 369 /// 370 /// ## 参数 371 /// 372 /// - `domain`: 要匹配的域 373 /// - `virq`: 要获取 irq_data 的IRQ号 374 pub fn domain_get_irq_data( 375 &self, 376 domain: &Arc<IrqDomain>, 377 virq: IrqNumber, 378 ) -> Option<Arc<IrqData>> { 379 let desc = irq_desc_manager().lookup(virq)?; 380 let mut irq_data = Some(desc.irq_data()); 381 382 while irq_data.is_some() { 383 let dt = irq_data.unwrap(); 384 if dt.domain().is_some() && Arc::ptr_eq(dt.domain().as_ref().unwrap(), domain) { 385 return Some(dt); 386 } 387 irq_data = dt.parent_data().and_then(|x| x.upgrade()); 388 } 389 390 return None; 391 } 392 } 393 394 struct InnerIrqDomainManager { 395 default_domain: Option<Arc<IrqDomain>>, 396 } 397 398 /// 中断域 399 /// 400 /// 用于把硬件中断号翻译为软件中断号的映射的对象 401 /// 402 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#164 403 #[allow(dead_code)] 404 #[derive(Debug)] 405 pub struct IrqDomain { 406 /// 中断域的名字 (二选一) 407 name: Option<&'static str>, 408 allocated_name: SpinLock<Option<String>>, 409 /// 中断域的操作 410 ops: &'static dyn IrqDomainOps, 411 inner: SpinLock<InnerIrqDomain>, 412 /// 中断号反向映射 413 revmap: RwLock<IrqDomainRevMap>, 414 } 415 416 #[allow(dead_code)] 417 #[derive(Debug)] 418 struct InnerIrqDomain { 419 /// this field not touched by the core code 420 host_data: Option<Arc<dyn IrqChipData>>, 421 /// host per irq_domain flags 422 flags: IrqDomainFlags, 423 /// The number of mapped interrupts 424 mapcount: u32, 425 bus_token: IrqDomainBusToken, 426 /// 指向 generic chip 列表的指针。 427 /// 有一个辅助函数用于为中断控制器驱动程序设置一个或 428 /// 多个 generic chip,该函数使用此指针并依赖于 generic chip 库。 429 generic_chip: Option<Arc<IrqDomainChipGeneric>>, 430 /// Pointer to a device that the domain represent, and that will be 431 /// used for power management purposes. 432 device: Option<Arc<dyn Device>>, 433 /// Pointer to parent irq_domain to support hierarchy irq_domains 434 parent: Option<Weak<IrqDomain>>, 435 } 436 437 impl IrqDomain { 438 #[allow(dead_code)] 439 pub fn new( 440 name: Option<&'static str>, 441 allocated_name: Option<String>, 442 ops: &'static dyn IrqDomainOps, 443 flags: IrqDomainFlags, 444 bus_token: IrqDomainBusToken, 445 irq_max: IrqNumber, 446 hwirq_max: HardwareIrqNumber, 447 ) -> Option<Arc<Self>> { 448 if name.is_none() && allocated_name.is_none() { 449 return None; 450 } 451 452 let x = IrqDomain { 453 name, 454 allocated_name: SpinLock::new(allocated_name), 455 ops, 456 inner: SpinLock::new(InnerIrqDomain { 457 host_data: None, 458 flags, 459 mapcount: 0, 460 bus_token, 461 generic_chip: None, 462 device: None, 463 parent: None, 464 }), 465 revmap: RwLock::new(IrqDomainRevMap { 466 map: HashMap::new(), 467 hwirq_max, 468 irq_max, 469 }), 470 }; 471 472 return Some(Arc::new(x)); 473 } 474 475 /// 中断域是否不对中断号进行转换 476 pub fn no_map(&self) -> bool { 477 self.inner 478 .lock_irqsave() 479 .flags 480 .contains(IrqDomainFlags::NO_MAP) 481 } 482 483 #[allow(dead_code)] 484 fn set_hwirq_max(&self, hwirq_max: HardwareIrqNumber) { 485 self.revmap.write_irqsave().hwirq_max = hwirq_max; 486 } 487 488 pub fn name(&self) -> Option<String> { 489 if let Some(name) = self.name { 490 return Some(name.to_string()); 491 } 492 return self.allocated_name.lock_irqsave().clone(); 493 } 494 495 pub fn set_name(&self, name: String) { 496 *self.allocated_name.lock_irqsave() = Some(name); 497 } 498 499 /// The number of mapped interrupts 500 pub fn map_count(&self) -> u32 { 501 self.revmap.read().map.len() as u32 502 } 503 504 pub fn host_data(&self) -> Option<Arc<dyn IrqChipData>> { 505 self.inner.lock_irqsave().host_data.clone() 506 } 507 508 pub fn set_host_data(&self, host_data: Option<Arc<dyn IrqChipData>>) { 509 self.inner.lock_irqsave().host_data = host_data; 510 } 511 } 512 513 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190 514 #[allow(dead_code)] 515 #[derive(Debug)] 516 struct IrqDomainRevMap { 517 map: HashMap<HardwareIrqNumber, Arc<IrqData>>, 518 hwirq_max: HardwareIrqNumber, 519 irq_max: IrqNumber, 520 } 521 522 impl IrqDomainRevMap { 523 fn insert(&mut self, hwirq: HardwareIrqNumber, irq_data: Arc<IrqData>) { 524 self.map.insert(hwirq, irq_data); 525 } 526 527 #[allow(dead_code)] 528 fn remove(&mut self, hwirq: HardwareIrqNumber) { 529 self.map.remove(&hwirq); 530 } 531 532 #[allow(dead_code)] 533 fn lookup(&self, hwirq: HardwareIrqNumber) -> Option<Arc<IrqData>> { 534 self.map.get(&hwirq).cloned() 535 } 536 } 537 538 bitflags! { 539 pub struct IrqDomainFlags: u32 { 540 /// Irq domain is hierarchical 541 const HIERARCHY = (1 << 0); 542 /// Irq domain name was allocated dynamically 543 const NAME_ALLOCATED = (1 << 1); 544 /// Irq domain is an IPI domain with virq per cpu 545 const IPI_PER_CPU = (1 << 2); 546 /// Irq domain is an IPI domain with single virq 547 const IPI_SINGLE = (1 << 3); 548 /// Irq domain implements MSIs 549 const MSI = (1 << 4); 550 /// Irq domain implements MSI remapping 551 const MSI_REMAP = (1 << 5); 552 /// Quirk to handle MSI implementations which do not provide masking 553 const MSI_NOMASK_QUIRK = (1 << 6); 554 /// Irq domain doesn't translate anything 555 const NO_MAP = (1 << 7); 556 /// Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved 557 /// for implementation specific purposes and ignored by the core code 558 const NONCORE = (1 << 16); 559 } 560 } 561 562 /// 如果多个域有相同的设备节点,但服务于不同的目的(例如,一个域用于PCI/MSI,另一个用于有线IRQs), 563 /// 它们可以使用特定于总线的token进行区分。预计大多数域只会携带`DomainBusAny`。 564 /// 565 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#78 566 #[allow(dead_code)] 567 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 568 pub enum IrqDomainBusToken { 569 Any = 0, 570 Wired, 571 GenericMsi, 572 PciMsi, 573 PlatformMsi, 574 Nexus, 575 Ipi, 576 FslMcMsi, 577 TiSciIntaMsi, 578 Wakeup, 579 VmdMsi, 580 } 581 582 /// IrqDomain的操作方法 583 /// 584 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107 585 pub trait IrqDomainOps: Debug + Send + Sync { 586 /// 匹配一个中断控制器设备节点到一个主机。 587 fn match_node( 588 &self, 589 _irq_domain: &Arc<IrqDomain>, 590 _device_node: &Arc<DeviceNode>, 591 _bus_token: IrqDomainBusToken, 592 ) -> bool { 593 false 594 } 595 596 /// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。 597 /// 对于给定的映射,这只会被调用一次。 598 /// 599 /// 如果没有实现这个方法,那么就会返回`ENOSYS` 600 fn map( 601 &self, 602 _irq_domain: &Arc<IrqDomain>, 603 _hwirq: HardwareIrqNumber, 604 _virq: IrqNumber, 605 ) -> Result<(), SystemError> { 606 Err(SystemError::ENOSYS) 607 } 608 609 /// 删除一个虚拟中断号与一个硬件中断号之间的映射。 610 fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber); 611 612 fn activate( 613 &self, 614 _domain: &Arc<IrqDomain>, 615 _irq_data: &Arc<IrqData>, 616 _reserve: bool, 617 ) -> Result<(), SystemError> { 618 Err(SystemError::ENOSYS) 619 } 620 621 fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {} 622 } 623 624 #[allow(dead_code)] 625 #[derive(Debug)] 626 pub struct IrqDomainChipGeneric { 627 inner: SpinLock<InnerIrqDomainChipGeneric>, 628 } 629 630 #[allow(dead_code)] 631 #[derive(Debug)] 632 struct InnerIrqDomainChipGeneric { 633 irqs_per_chip: u32, 634 flags_to_clear: IrqGcFlags, 635 flags_to_set: IrqGcFlags, 636 gc_flags: IrqGcFlags, 637 gc: Vec<Arc<IrqChipGeneric>>, 638 } 639