xref: /DragonOS/kernel/src/exception/irqdomain.rs (revision ce5850adbf74ec6c6717bbb5b1749f1fbff4ca0d)
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