sparreal_kernel/irq/
mod.rs1use core::cell::UnsafeCell;
2
3use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec};
4use log::{debug, warn};
5pub use rdrive::Phandle;
6use rdrive::{DeviceId, driver::intc::*};
7use spin::Mutex;
8
9use crate::{
10 globals::{self, cpu_global},
11 platform,
12};
13
14#[derive(Default)]
15pub struct CpuIrqChips(BTreeMap<DeviceId, Chip>);
16
17pub struct Chip {
18 mutex: Mutex<()>,
19 handlers: UnsafeCell<BTreeMap<IrqId, Box<IrqHandler>>>,
21}
22
23unsafe impl Send for Chip {}
24unsafe impl Sync for Chip {}
25
26pub type IrqHandler = dyn Fn(IrqId) -> IrqHandleResult;
27
28pub fn enable_all() {
29 platform::irq_all_enable();
30}
31
32pub fn disable_all() {
33 platform::irq_all_disable();
34}
35
36pub(crate) fn init_main_cpu() {
37 for chip in rdrive::get_list::<Intc>() {
38 debug!(
39 "[{}]({:?}) open",
40 chip.descriptor().name,
41 chip.descriptor().device_id()
42 );
43 chip.lock().unwrap().open().unwrap();
44 }
45
46 init_current_cpu();
47}
48
49pub(crate) fn init_current_cpu() {
50 let globals = unsafe { globals::cpu_global_mut() };
51
52 for intc in rdrive::get_list::<Intc>() {
53 let id = intc.descriptor().device_id();
54 platform::irq_init_current_cpu(id);
56 debug!(
64 "[{}]({:?}) init cpu: {:?}",
65 intc.descriptor().name,
66 id,
67 platform::cpu_hard_id(),
68 );
69
70 globals.irq_chips.0.insert(
71 id,
72 Chip {
73 mutex: Mutex::new(()),
74 handlers: UnsafeCell::new(BTreeMap::new()),
76 },
77 );
78 }
80}
81
82pub enum IrqHandleResult {
83 Handled,
84 None,
85}
86
87fn chip_cpu(id: DeviceId) -> &'static Chip {
88 globals::cpu_global()
89 .irq_chips
90 .0
91 .get(&id)
92 .unwrap_or_else(|| panic!("irq chip {:?} not found", id))
93}
94
95pub struct IrqRegister {
96 pub param: IrqParam,
97 pub handler: Box<IrqHandler>,
98 pub priority: Option<usize>,
99}
100
101impl IrqRegister {
102 pub fn register(self) {
103 let irq = self.param.cfg.irq;
104 let irq_parent = self.param.intc;
105
106 let chip = chip_cpu(irq_parent);
107 chip.register_handle(irq, self.handler);
108
109 platform::irq_enable(self.param.clone());
110
111 debug!("Enable irq {irq:?} on chip {irq_parent:?}");
136 }
137
138 pub fn priority(mut self, priority: usize) -> Self {
139 self.priority = Some(priority);
140 self
141 }
142}
143
144impl Chip {
145 fn register_handle(&self, irq: IrqId, handle: Box<IrqHandler>) {
146 let g = NoIrqGuard::new();
147 let gm = self.mutex.lock();
148 unsafe { &mut *self.handlers.get() }.insert(irq, handle);
149 drop(gm);
150 drop(g);
151 }
152
153 fn unregister_handle(&self, irq: IrqId) {
154 let g = NoIrqGuard::new();
155 let gm = self.mutex.lock();
156 unsafe { &mut *self.handlers.get() }.remove(&irq);
157 drop(gm);
158 drop(g);
159 }
160
161 fn handle_irq(&self) -> Option<()> {
162 let irq = platform::irq_ack();
164
165 if let Some(handler) = unsafe { &mut *self.handlers.get() }.get(&irq) {
166 let res = (handler)(irq);
167 if let IrqHandleResult::None = res {
168 return Some(());
169 }
170 } else {
171 warn!("IRQ {irq:?} no handler");
172 }
173 platform::irq_eoi(irq);
175 Some(())
176 }
177}
178
179pub struct NoIrqGuard {
180 is_enabled: bool,
181}
182
183impl NoIrqGuard {
184 pub fn new() -> Self {
185 let is_enabled = platform::irq_all_is_enabled();
186 platform::irq_all_disable();
187 Self { is_enabled }
188 }
189}
190
191impl Default for NoIrqGuard {
192 fn default() -> Self {
193 Self::new()
194 }
195}
196
197impl Drop for NoIrqGuard {
198 fn drop(&mut self) {
199 if self.is_enabled {
200 enable_all();
201 }
202 }
203}
204
205pub fn handle_irq() -> usize {
206 for chip in cpu_global().irq_chips.0.values() {
207 chip.handle_irq();
208 }
209
210 let cu = crate::task::current();
211
212 cu.sp
213}
214
215#[derive(Debug, Clone)]
216pub struct IrqInfo {
217 pub irq_parent: DeviceId,
218 pub cfgs: Vec<IrqConfig>,
219}
220
221#[derive(Debug, Clone)]
222pub struct IrqParam {
223 pub intc: DeviceId,
224 pub cfg: IrqConfig,
225}
226
227impl IrqParam {
228 pub fn register_builder(
229 &self,
230 handler: impl Fn(IrqId) -> IrqHandleResult + 'static,
231 ) -> IrqRegister {
232 IrqRegister {
233 param: self.clone(),
234 handler: Box::new(handler),
235 priority: None,
236 }
237 }
238}
239
240pub fn unregister_irq(irq: IrqId) {
241 for chip in cpu_global().irq_chips.0.values() {
242 chip.unregister_handle(irq);
243 }
244}