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::{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}