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