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