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::{Device, DeviceId, IrqId, intc::*};
7use spin::Mutex;
8
9use crate::{
10 globals::{self, cpu_global},
11 platform::{self, cpu_id},
12 platform_if::PlatformImpl,
13};
14
15#[derive(Default)]
16pub struct CpuIrqChips(BTreeMap<DeviceId, Chip>);
17
18pub type IrqHandler = dyn Fn(IrqId) -> IrqHandleResult;
19
20pub struct Chip {
21 device: Device<HardwareCPU>,
22 mutex: Mutex<()>,
23 handlers: UnsafeCell<BTreeMap<IrqId, Box<IrqHandler>>>,
24}
25
26unsafe impl Send for Chip {}
27unsafe impl Sync for Chip {}
28
29pub fn enable_all() {
30 PlatformImpl::irq_all_enable();
31}
32
33pub(crate) fn init_main_cpu() {
34 for (phandle, intc) in rdrive::intc_all() {
35 debug!("[{}]({:?}) open", intc.descriptor.name, phandle,);
36 let chip = intc.upgrade().unwrap();
37 let mut g = chip.spin_try_borrow_by(0.into());
38
39 g.open().unwrap();
40 }
41
42 init_current_cpu();
43}
44
45pub(crate) fn init_current_cpu() {
46 let globals = unsafe { globals::cpu_global_mut() };
47
48 for (phandle, intc) in rdrive::intc_all() {
49 let intc = intc.upgrade().unwrap();
50 let id = intc.descriptor.device_id;
51 let g = intc.spin_try_borrow_by(0.into());
52
53 let device = g.current_cpu_setup();
54 debug!(
55 "[{}]({:?}) init cpu: {:?}",
56 intc.descriptor.name,
57 phandle,
58 platform::cpu_id(),
59 );
60
61 let device = Device::new(intc.descriptor.clone(), device);
62
63 globals.irq_chips.0.insert(
64 id,
65 Chip {
66 device,
67 mutex: Mutex::new(()),
68 handlers: UnsafeCell::new(Default::default()),
69 },
70 );
71 }
72}
73
74pub enum IrqHandleResult {
75 Handled,
76 None,
77}
78
79fn chip_cpu(id: DeviceId) -> &'static Chip {
80 globals::cpu_global()
81 .irq_chips
82 .0
83 .get(&id)
84 .unwrap_or_else(|| panic!("irq chip {:?} not found", id))
85}
86
87pub struct IrqRegister {
88 pub param: IrqParam,
89 pub handler: Box<IrqHandler>,
90 pub priority: Option<usize>,
91}
92
93impl IrqRegister {
94 pub fn register(self) {
95 let irq = self.param.cfg.irq;
96 let irq_parent = self.param.intc;
97
98 let chip = chip_cpu(irq_parent);
99 chip.register_handle(irq, self.handler);
100
101 let mut c = rdrive::edit(|m| m.intc.get(irq_parent))
102 .unwrap()
103 .upgrade()
104 .unwrap()
105 .spin_try_borrow_by(0.into());
106
107 if let Some(p) = self.priority {
108 c.set_priority(irq, p);
109 } else {
110 c.set_priority(irq, 0);
111 }
112
113 c.set_target_cpu(irq, cpu_id());
114 c.set_trigger(irq, self.param.cfg.trigger);
115 c.irq_enable(irq);
116 debug!("Enable irq {:?} on chip {:?}", irq, irq_parent);
117 }
118
119 pub fn priority(mut self, priority: usize) -> Self {
120 self.priority = Some(priority);
121 self
122 }
123}
124
125impl Chip {
126 fn register_handle(&self, irq: IrqId, handle: Box<IrqHandler>) {
127 let g = NoIrqGuard::new();
128 let gm = self.mutex.lock();
129 unsafe { &mut *self.handlers.get() }.insert(irq, handle);
130 drop(gm);
131 drop(g);
132 }
133
134 fn unregister_handle(&self, irq: IrqId) {
135 let g = NoIrqGuard::new();
136 let gm = self.mutex.lock();
137 unsafe { &mut *self.handlers.get() }.remove(&irq);
138 drop(gm);
139 drop(g);
140 }
141
142 fn handle_irq(&self) -> Option<()> {
143 let irq = self.device.get_and_acknowledge_interrupt()?;
144
145 if let Some(handler) = unsafe { &mut *self.handlers.get() }.get(&irq) {
146 let res = (handler)(irq);
147 if let IrqHandleResult::None = res {
148 return Some(());
149 }
150 } else {
151 warn!("IRQ {:?} no handler", irq);
152 }
153 self.device.end_interrupt(irq);
154 Some(())
155 }
156}
157
158pub struct NoIrqGuard {
159 is_enabled: bool,
160}
161
162impl NoIrqGuard {
163 pub fn new() -> Self {
164 let is_enabled = PlatformImpl::irq_all_is_enabled();
165 PlatformImpl::irq_all_disable();
166 Self { is_enabled }
167 }
168}
169
170impl Default for NoIrqGuard {
171 fn default() -> Self {
172 Self::new()
173 }
174}
175
176impl Drop for NoIrqGuard {
177 fn drop(&mut self) {
178 if self.is_enabled {
179 enable_all();
180 }
181 }
182}
183
184pub fn handle_irq() -> usize {
185 for chip in cpu_global().irq_chips.0.values() {
186 chip.handle_irq();
187 }
188
189 let cu = crate::task::current();
190
191 cu.sp
192}
193
194#[derive(Debug, Clone)]
195pub struct IrqInfo {
196 pub irq_parent: DeviceId,
197 pub cfgs: Vec<IrqConfig>,
198}
199
200#[derive(Debug, Clone)]
201pub struct IrqParam {
202 pub intc: DeviceId,
203 pub cfg: IrqConfig,
204}
205
206impl IrqParam {
207 pub fn register_builder(
208 &self,
209 handler: impl Fn(IrqId) -> IrqHandleResult + 'static,
210 ) -> IrqRegister {
211 IrqRegister {
212 param: self.clone(),
213 handler: Box::new(handler),
214 priority: None,
215 }
216 }
217}
218
219pub fn unregister_irq(irq: IrqId) {
220 for chip in cpu_global().irq_chips.0.values() {
221 chip.unregister_handle(irq);
222 }
223}