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