1 use core::fmt::Debug; 2 3 use alloc::{ 4 string::String, 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 libs::{rwlock::RwLock, spinlock::SpinLock}, 14 }; 15 16 use super::{ 17 irqchip::{IrqChipGeneric, IrqGcFlags}, 18 HardwareIrqNumber, IrqNumber, 19 }; 20 21 /// 中断域 22 /// 23 /// 用于把硬件中断号翻译为软件中断号的映射的对象 24 /// 25 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#164 26 #[allow(dead_code)] 27 #[derive(Debug)] 28 pub struct IrqDomain { 29 /// 中断域的名字 (二选一) 30 name: Option<&'static str>, 31 allocated_name: Option<String>, 32 /// 中断域的操作 33 ops: &'static dyn IrqDomainOps, 34 inner: SpinLock<InnerIrqDomain>, 35 /// 中断号反向映射 36 revmap: RwLock<IrqDomainRevMap>, 37 } 38 39 #[allow(dead_code)] 40 #[derive(Debug)] 41 struct InnerIrqDomain { 42 /// host per irq_domain flags 43 flags: IrqDomainFlags, 44 /// The number of mapped interrupts 45 mapcount: u32, 46 bus_token: IrqDomainBusToken, 47 /// 指向 generic chip 列表的指针。 48 /// 有一个辅助函数用于为中断控制器驱动程序设置一个或 49 /// 多个 generic chip,该函数使用此指针并依赖于 generic chip 库。 50 generic_chip: Option<Arc<IrqDomainChipGeneric>>, 51 /// Pointer to a device that the domain represent, and that will be 52 /// used for power management purposes. 53 device: Option<Arc<dyn Device>>, 54 /// Pointer to parent irq_domain to support hierarchy irq_domains 55 parent: Option<Weak<IrqDomain>>, 56 } 57 58 impl IrqDomain { 59 #[allow(dead_code)] 60 pub fn new( 61 name: Option<&'static str>, 62 allocated_name: Option<String>, 63 ops: &'static dyn IrqDomainOps, 64 flags: IrqDomainFlags, 65 bus_token: IrqDomainBusToken, 66 ) -> Option<Arc<Self>> { 67 if name.is_none() && allocated_name.is_none() { 68 return None; 69 } 70 71 let x = IrqDomain { 72 name, 73 allocated_name, 74 ops, 75 inner: SpinLock::new(InnerIrqDomain { 76 flags, 77 mapcount: 0, 78 bus_token, 79 generic_chip: None, 80 device: None, 81 parent: None, 82 }), 83 revmap: RwLock::new(IrqDomainRevMap { 84 map: HashMap::new(), 85 hwirq_max: HardwareIrqNumber::new(0), 86 }), 87 }; 88 89 return Some(Arc::new(x)); 90 } 91 } 92 93 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190 94 #[allow(dead_code)] 95 #[derive(Debug)] 96 struct IrqDomainRevMap { 97 map: HashMap<HardwareIrqNumber, IrqNumber>, 98 hwirq_max: HardwareIrqNumber, 99 } 100 101 bitflags! { 102 pub struct IrqDomainFlags: u32 { 103 /// Irq domain is hierarchical 104 const HIERARCHY = (1 << 0); 105 /// Irq domain name was allocated dynamically 106 const NAME_ALLOCATED = (1 << 1); 107 /// Irq domain is an IPI domain with virq per cpu 108 const IPI_PER_CPU = (1 << 2); 109 /// Irq domain is an IPI domain with single virq 110 const IPI_SINGLE = (1 << 3); 111 /// Irq domain implements MSIs 112 const MSI = (1 << 4); 113 /// Irq domain implements MSI remapping 114 const MSI_REMAP = (1 << 5); 115 /// Quirk to handle MSI implementations which do not provide masking 116 const MSI_NOMASK_QUIRK = (1 << 6); 117 /// Irq domain doesn't translate anything 118 const NO_MAP = (1 << 7); 119 /// Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved 120 /// for implementation specific purposes and ignored by the core code 121 const NONCORE = (1 << 16); 122 } 123 } 124 125 /// 如果多个域有相同的设备节点,但服务于不同的目的(例如,一个域用于PCI/MSI,另一个用于有线IRQs), 126 /// 它们可以使用特定于总线的token进行区分。预计大多数域只会携带`DomainBusAny`。 127 /// 128 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#78 129 #[allow(dead_code)] 130 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 131 pub enum IrqDomainBusToken { 132 Any = 0, 133 Wired, 134 GenericMsi, 135 PciMsi, 136 PlatformMsi, 137 Nexus, 138 Ipi, 139 FslMcMsi, 140 TiSciIntaMsi, 141 Wakeup, 142 VmdMsi, 143 } 144 145 /// IrqDomain的操作方法 146 /// 147 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107 148 pub trait IrqDomainOps: Debug + Send + Sync { 149 /// 匹配一个中断控制器设备节点到一个主机。 150 fn match_node( 151 &self, 152 irq_domain: &Arc<IrqDomain>, 153 device_node: &Arc<DeviceNode>, 154 bus_token: IrqDomainBusToken, 155 ) -> bool; 156 157 /// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。 158 /// 对于给定的映射,这只会被调用一次。 159 fn map( 160 &self, 161 irq_domain: &Arc<IrqDomain>, 162 hwirq: HardwareIrqNumber, 163 virq: IrqNumber, 164 ) -> Result<(), SystemError>; 165 166 /// 删除一个虚拟中断号与一个硬件中断号之间的映射。 167 fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber); 168 } 169 170 #[allow(dead_code)] 171 #[derive(Debug)] 172 pub struct IrqDomainChipGeneric { 173 inner: SpinLock<InnerIrqDomainChipGeneric>, 174 } 175 176 #[allow(dead_code)] 177 #[derive(Debug)] 178 struct InnerIrqDomainChipGeneric { 179 irqs_per_chip: u32, 180 flags_to_clear: IrqGcFlags, 181 flags_to_set: IrqGcFlags, 182 gc_flags: IrqGcFlags, 183 gc: Vec<Arc<IrqChipGeneric>>, 184 } 185