sparreal_kernel/irq/
mod.rs

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