sparreal_kernel/irq/
mod.rs

1use 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    // device: Box<dyn local::Interface>,
20    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        // let g = intc.lock().unwrap();
55        platform::irq_init_current_cpu(id);
56        // let Some(mut cpu_if) = g.cpu_local() else {
57        //     continue;
58        // };
59
60        // cpu_if.open().unwrap();
61        // cpu_if.set_eoi_mode(false);
62
63        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                // device: cpu_if,
75                handlers: UnsafeCell::new(BTreeMap::new()),
76            },
77        );
78        // drop(g);
79    }
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        // if self.param.cfg.is_private
112        //     && let local::Capability::ConfigLocalIrq(c) = chip.device.capability()
113        // {
114        //     if let Some(p) = self.priority {
115        //         c.set_priority(irq, p).unwrap();
116        //     } else {
117        //         c.set_priority(irq, 0).unwrap();
118        //     }
119        //     c.set_trigger(irq, self.param.cfg.trigger).unwrap();
120        //     c.irq_enable(irq).unwrap();
121        // } else {
122        //     let mut c = rdrive::get::<Intc>(irq_parent).unwrap().lock().unwrap();
123        //     if let Some(p) = self.priority {
124        //         c.set_priority(irq, p).unwrap();
125        //     } else {
126        //         c.set_priority(irq, 0).unwrap();
127        //     }
128        //     if !self.param.cfg.is_private {
129        //         c.set_target_cpu(irq, cpu_hard_id().into()).unwrap();
130        //     }
131        //     c.set_trigger(irq, self.param.cfg.trigger).unwrap();
132        //     c.irq_enable(irq).unwrap();
133        // }
134
135        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 = self.device.ack()?;
163        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        // self.device.eoi(irq);
174        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}