xref: /DragonOS/kernel/src/exception/irqchip.rs (revision ce5850adbf74ec6c6717bbb5b1749f1fbff4ca0d)
1*ce5850adSLoGin use core::{any::Any, fmt::Debug};
2*ce5850adSLoGin 
3*ce5850adSLoGin use alloc::{
4*ce5850adSLoGin     sync::{Arc, Weak},
5*ce5850adSLoGin     vec::Vec,
6*ce5850adSLoGin };
7*ce5850adSLoGin use system_error::SystemError;
8*ce5850adSLoGin 
9*ce5850adSLoGin use crate::{libs::spinlock::SpinLock, mm::VirtAddr};
10*ce5850adSLoGin 
11*ce5850adSLoGin use super::{
12*ce5850adSLoGin     irqdata::{IrqData, IrqLineStatus},
13*ce5850adSLoGin     irqdomain::IrqDomain,
14*ce5850adSLoGin     msi::MsiMsg,
15*ce5850adSLoGin };
16*ce5850adSLoGin 
17*ce5850adSLoGin /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#506
18*ce5850adSLoGin pub trait IrqChip: Sync + Send + Any + Debug {
19*ce5850adSLoGin     fn name(&self) -> &'static str;
20*ce5850adSLoGin     /// start up the interrupt (defaults to ->enable if ENOSYS)
21*ce5850adSLoGin     fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
22*ce5850adSLoGin         Err(SystemError::ENOSYS)
23*ce5850adSLoGin     }
24*ce5850adSLoGin 
25*ce5850adSLoGin     /// shut down the interrupt (defaults to ->disable if ENOSYS)
26*ce5850adSLoGin     fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
27*ce5850adSLoGin         Err(SystemError::ENOSYS)
28*ce5850adSLoGin     }
29*ce5850adSLoGin 
30*ce5850adSLoGin     /// enable the interrupt
31*ce5850adSLoGin     ///
32*ce5850adSLoGin     /// (defaults to ->unmask if ENOSYS)
33*ce5850adSLoGin     fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
34*ce5850adSLoGin         Err(SystemError::ENOSYS)
35*ce5850adSLoGin     }
36*ce5850adSLoGin 
37*ce5850adSLoGin     /// disable the interrupt
38*ce5850adSLoGin     fn irq_disable(&self, irq: &Arc<IrqData>);
39*ce5850adSLoGin 
40*ce5850adSLoGin     /// start of a new interrupt
41*ce5850adSLoGin     fn irq_ack(&self, irq: &Arc<IrqData>);
42*ce5850adSLoGin 
43*ce5850adSLoGin     /// mask an interrupt source
44*ce5850adSLoGin     fn irq_mask(&self, irq: &Arc<IrqData>);
45*ce5850adSLoGin     /// ack and mask an interrupt source
46*ce5850adSLoGin     fn irq_mask_ack(&self, irq: &Arc<IrqData>);
47*ce5850adSLoGin     /// unmask an interrupt source
48*ce5850adSLoGin     fn irq_unmask(&self, irq: &Arc<IrqData>);
49*ce5850adSLoGin     /// end of interrupt
50*ce5850adSLoGin     fn irq_eoi(&self, irq: &Arc<IrqData>);
51*ce5850adSLoGin 
52*ce5850adSLoGin     // todo: set affinity
53*ce5850adSLoGin 
54*ce5850adSLoGin     /// retrigger an IRQ to the CPU
55*ce5850adSLoGin     fn retrigger(&self, irq: &Arc<IrqData>);
56*ce5850adSLoGin 
57*ce5850adSLoGin     /// set the flow type of an interrupt
58*ce5850adSLoGin     ///
59*ce5850adSLoGin     /// flow_type: the flow type to set
60*ce5850adSLoGin     ///
61*ce5850adSLoGin     fn irq_set_type(
62*ce5850adSLoGin         &self,
63*ce5850adSLoGin         _irq: &Arc<IrqData>,
64*ce5850adSLoGin         _flow_type: IrqLineStatus,
65*ce5850adSLoGin     ) -> Result<(), SystemError> {
66*ce5850adSLoGin         Err(SystemError::ENOSYS)
67*ce5850adSLoGin     }
68*ce5850adSLoGin 
69*ce5850adSLoGin     /// enable/disable power management wake-on of an interrupt
70*ce5850adSLoGin     fn irq_set_wake(&self, _irq: &Arc<IrqData>, _on: bool) -> Result<(), SystemError> {
71*ce5850adSLoGin         Err(SystemError::ENOSYS)
72*ce5850adSLoGin     }
73*ce5850adSLoGin 
74*ce5850adSLoGin     /// function to lock access to slow bus (i2c) chips
75*ce5850adSLoGin     fn irq_bus_lock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
76*ce5850adSLoGin         Ok(())
77*ce5850adSLoGin     }
78*ce5850adSLoGin 
79*ce5850adSLoGin     /// function to sync and unlock slow bus (i2c) chips
80*ce5850adSLoGin     fn irq_bus_sync_unlock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
81*ce5850adSLoGin         Ok(())
82*ce5850adSLoGin     }
83*ce5850adSLoGin 
84*ce5850adSLoGin     /// function called from core code on suspend once per
85*ce5850adSLoGin     /// chip, when one or more interrupts are installed
86*ce5850adSLoGin     fn irq_suspend(&self, irq: &Arc<IrqData>);
87*ce5850adSLoGin 
88*ce5850adSLoGin     /// function called from core code on resume once per chip,
89*ce5850adSLoGin     /// when one ore more interrupts are installed
90*ce5850adSLoGin     fn irq_resume(&self, irq: &Arc<IrqData>);
91*ce5850adSLoGin 
92*ce5850adSLoGin     /// function called from core code on shutdown once per chip
93*ce5850adSLoGin     fn irq_pm_shutdown(&self, irq: &Arc<IrqData>);
94*ce5850adSLoGin 
95*ce5850adSLoGin     /// Optional function to set irq_data.mask for special cases
96*ce5850adSLoGin     fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
97*ce5850adSLoGin 
98*ce5850adSLoGin     // todo: print chip
99*ce5850adSLoGin 
100*ce5850adSLoGin     /// optional to request resources before calling
101*ce5850adSLoGin     /// any other callback related to this irq
102*ce5850adSLoGin     fn irq_request_resources(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
103*ce5850adSLoGin         Ok(())
104*ce5850adSLoGin     }
105*ce5850adSLoGin 
106*ce5850adSLoGin     /// optional to release resources acquired with
107*ce5850adSLoGin     /// irq_request_resources
108*ce5850adSLoGin     fn irq_release_resources(&self, _irq: &Arc<IrqData>) {}
109*ce5850adSLoGin 
110*ce5850adSLoGin     /// optional to compose message content for MSI
111*ce5850adSLoGin     fn irq_compose_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &mut MsiMsg) {}
112*ce5850adSLoGin 
113*ce5850adSLoGin     /// optional to write message content for MSI
114*ce5850adSLoGin     fn irq_write_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &MsiMsg) {}
115*ce5850adSLoGin 
116*ce5850adSLoGin     /// return the internal state of an interrupt
117*ce5850adSLoGin     fn irqchip_state(
118*ce5850adSLoGin         &self,
119*ce5850adSLoGin         _irq: &Arc<IrqData>,
120*ce5850adSLoGin         _which: IrqChipState,
121*ce5850adSLoGin     ) -> Result<bool, SystemError> {
122*ce5850adSLoGin         Err(SystemError::ENOSYS)
123*ce5850adSLoGin     }
124*ce5850adSLoGin 
125*ce5850adSLoGin     /// set the internal state of an interrupt
126*ce5850adSLoGin     fn set_irqchip_state(
127*ce5850adSLoGin         &self,
128*ce5850adSLoGin         _irq: &Arc<IrqData>,
129*ce5850adSLoGin         _which: IrqChipState,
130*ce5850adSLoGin         _state: bool,
131*ce5850adSLoGin     ) -> Result<(), SystemError> {
132*ce5850adSLoGin         Err(SystemError::ENOSYS)
133*ce5850adSLoGin     }
134*ce5850adSLoGin 
135*ce5850adSLoGin     // todo: set vcpu affinity
136*ce5850adSLoGin 
137*ce5850adSLoGin     /// send a single IPI to destination cpus
138*ce5850adSLoGin     fn send_single_ipi(&self, irq: &Arc<IrqData>, cpu: u32);
139*ce5850adSLoGin 
140*ce5850adSLoGin     // todo: send ipi with cpu mask
141*ce5850adSLoGin 
142*ce5850adSLoGin     /// function called from core code before enabling an NMI
143*ce5850adSLoGin     fn irq_nmi_setup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
144*ce5850adSLoGin         Err(SystemError::ENOSYS)
145*ce5850adSLoGin     }
146*ce5850adSLoGin 
147*ce5850adSLoGin     /// function called from core code after disabling an NMI
148*ce5850adSLoGin     fn irq_nmi_teardown(&self, irq: &Arc<IrqData>);
149*ce5850adSLoGin }
150*ce5850adSLoGin 
151*ce5850adSLoGin #[allow(dead_code)]
152*ce5850adSLoGin #[derive(Debug, Clone, Copy)]
153*ce5850adSLoGin pub enum IrqChipState {
154*ce5850adSLoGin     /// Is the interrupt pending?
155*ce5850adSLoGin     Pending,
156*ce5850adSLoGin     /// Is the interrupt in progress?
157*ce5850adSLoGin     Active,
158*ce5850adSLoGin     /// Is the interrupt masked?
159*ce5850adSLoGin     Masked,
160*ce5850adSLoGin     /// Is Irq line high?
161*ce5850adSLoGin     LineLevel,
162*ce5850adSLoGin }
163*ce5850adSLoGin 
164*ce5850adSLoGin pub trait IrqChipData: Sync + Send + Any + Debug {}
165*ce5850adSLoGin 
166*ce5850adSLoGin bitflags! {
167*ce5850adSLoGin     /// 定义 IrqGcFlags 位标志
168*ce5850adSLoGin     pub struct IrqGcFlags: u32 {
169*ce5850adSLoGin         /// 通过读取mask reg来初始化mask_cache
170*ce5850adSLoGin         const IRQ_GC_INIT_MASK_CACHE = 1 << 0;
171*ce5850adSLoGin         /// 对于需要在父irq上调用irq_set_wake()的irq芯片, 将irqs的锁类设置为嵌套。Usually GPIO implementations
172*ce5850adSLoGin         const IRQ_GC_INIT_NESTED_LOCK = 1 << 1;
173*ce5850adSLoGin         /// Mask cache是芯片类型私有的
174*ce5850adSLoGin         const IRQ_GC_MASK_CACHE_PER_TYPE = 1 << 2;
175*ce5850adSLoGin         /// 不计算irqData->mask
176*ce5850adSLoGin         const IRQ_GC_NO_MASK = 1 << 3;
177*ce5850adSLoGin         /// 使用大端字节序的寄存器访问(默认:小端LE)
178*ce5850adSLoGin         const IRQ_GC_BE_IO = 1 << 4;
179*ce5850adSLoGin     }
180*ce5850adSLoGin }
181*ce5850adSLoGin 
182*ce5850adSLoGin #[allow(dead_code)]
183*ce5850adSLoGin #[derive(Debug)]
184*ce5850adSLoGin pub struct IrqChipGeneric {
185*ce5850adSLoGin     inner: SpinLock<InnerIrqChipGeneric>,
186*ce5850adSLoGin }
187*ce5850adSLoGin 
188*ce5850adSLoGin #[allow(dead_code)]
189*ce5850adSLoGin #[derive(Debug)]
190*ce5850adSLoGin struct InnerIrqChipGeneric {
191*ce5850adSLoGin     /// Register base address
192*ce5850adSLoGin     reg_base: VirtAddr,
193*ce5850adSLoGin     ops: &'static dyn IrqChipGenericOps,
194*ce5850adSLoGin     /// Interrupt base num for this chip
195*ce5850adSLoGin     irq_base: u32,
196*ce5850adSLoGin     /// Number of interrupts handled by this chip
197*ce5850adSLoGin     irq_cnt: u32,
198*ce5850adSLoGin     /// Cached mask register shared between all chip types
199*ce5850adSLoGin     mask_cache: u32,
200*ce5850adSLoGin     /// Cached type register
201*ce5850adSLoGin     type_cache: u32,
202*ce5850adSLoGin     /// Cached polarity register
203*ce5850adSLoGin     polarity_cache: u32,
204*ce5850adSLoGin     /// Interrupt can wakeup from suspend
205*ce5850adSLoGin     wake_enabled: bool,
206*ce5850adSLoGin     /// Interrupt is marked as an wakeup from suspend source
207*ce5850adSLoGin     wake_active: bool,
208*ce5850adSLoGin     /// Number of available irq_chip_type instances (usually 1)
209*ce5850adSLoGin     num_chip_type: u32,
210*ce5850adSLoGin     private_data: Option<Arc<dyn IrqChipGenericPrivateData>>,
211*ce5850adSLoGin     installed: u64,
212*ce5850adSLoGin     unused: u64,
213*ce5850adSLoGin     domain: Weak<IrqDomain>,
214*ce5850adSLoGin     chip_types: Vec<IrqChipType>,
215*ce5850adSLoGin }
216*ce5850adSLoGin 
217*ce5850adSLoGin pub trait IrqChipGenericOps: Debug {
218*ce5850adSLoGin     /// Alternate I/O accessor (defaults to readl if NULL)
219*ce5850adSLoGin     unsafe fn reg_readl(&self, addr: VirtAddr) -> u32;
220*ce5850adSLoGin 
221*ce5850adSLoGin     /// Alternate I/O accessor (defaults to writel if NULL)
222*ce5850adSLoGin     unsafe fn reg_writel(&self, addr: VirtAddr, val: u32);
223*ce5850adSLoGin 
224*ce5850adSLoGin     /// Function called from core code on suspend once per
225*ce5850adSLoGin     /// chip; can be useful instead of irq_chip::suspend to
226*ce5850adSLoGin     /// handle chip details even when no interrupts are in use
227*ce5850adSLoGin     fn suspend(&self, gc: &Arc<IrqChipGeneric>);
228*ce5850adSLoGin     /// Function called from core code on resume once per chip;
229*ce5850adSLoGin     /// can be useful instead of irq_chip::resume to handle chip
230*ce5850adSLoGin     /// details even when no interrupts are in use
231*ce5850adSLoGin     fn resume(&self, gc: &Arc<IrqChipGeneric>);
232*ce5850adSLoGin }
233*ce5850adSLoGin 
234*ce5850adSLoGin pub trait IrqChipGenericPrivateData: Sync + Send + Any + Debug {}
235*ce5850adSLoGin 
236*ce5850adSLoGin #[derive(Debug)]
237*ce5850adSLoGin pub struct IrqChipType {
238*ce5850adSLoGin     // todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024
239*ce5850adSLoGin }
240