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