xref: /DragonOS/kernel/src/driver/irqchip/riscv_intc.rs (revision 9a0802fd2ddda39e96342997abbfc30bf65f1f0e)
1 use alloc::{string::ToString, sync::Arc};
2 use system_error::SystemError;
3 
4 use crate::{
5     arch::interrupt::TrapFrame,
6     driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer},
7     exception::{
8         handle::PerCpuDevIdIrqHandler,
9         irqchip::{IrqChip, IrqChipFlags},
10         irqdata::IrqData,
11         irqdesc::{irq_desc_manager, GenericIrqHandler},
12         irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
13         softirq::do_softirq,
14         HardwareIrqNumber, IrqNumber,
15     },
16     libs::spinlock::{SpinLock, SpinLockGuard},
17     sched::{SchedMode, __schedule},
18 };
19 
20 use super::riscv_sifive_plic::do_plic_irq;
21 
22 static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
23 static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
24 
25 #[inline(always)]
26 pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
27     unsafe { &RISCV_INTC_DOMAIN }
28 }
29 
30 #[inline(always)]
31 fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
32     unsafe { RISCV_INTC_CHIP.as_ref() }
33 }
34 
35 /// RISC-V INTC虚拟中断号的起始值(192映射物理的0)
36 pub const RISCV_INTC_VIRQ_START: u32 = 192;
37 
38 #[derive(Debug)]
39 struct RiscvIntcChip {
40     inner: SpinLock<InnerIrqChip>,
41 }
42 
43 impl IrqChip for RiscvIntcChip {
44     fn name(&self) -> &'static str {
45         "RISC-V INTC"
46     }
47 
48     fn irq_disable(&self, _irq: &Arc<IrqData>) {}
49 
50     fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
51         unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) };
52         Ok(())
53     }
54 
55     fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
56         unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) };
57         Ok(())
58     }
59 
60     fn irq_ack(&self, _irq: &Arc<IrqData>) {}
61 
62     fn can_mask_ack(&self) -> bool {
63         false
64     }
65 
66     fn irq_eoi(&self, _irq: &Arc<IrqData>) {
67         /*
68          * The RISC-V INTC driver uses handle_percpu_devid_irq() flow
69          * for the per-HART local interrupts and child irqchip drivers
70          * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement
71          * chained handlers for the per-HART local interrupts.
72          *
73          * In the absence of irq_eoi(), the chained_irq_enter() and
74          * chained_irq_exit() functions (used by child irqchip drivers)
75          * will do unnecessary mask/unmask of per-HART local interrupts
76          * at the time of handling interrupts. To avoid this, we provide
77          * an empty irq_eoi() callback for RISC-V INTC irqchip.
78          */
79     }
80 
81     fn can_set_affinity(&self) -> bool {
82         false
83     }
84 
85     fn can_set_flow_type(&self) -> bool {
86         false
87     }
88 
89     fn flags(&self) -> IrqChipFlags {
90         self.inner().flags
91     }
92 }
93 
94 impl RiscvIntcChip {
95     const IRQ_SIZE: u32 = 64;
96     fn new() -> Self {
97         Self {
98             inner: SpinLock::new(InnerIrqChip {
99                 flags: IrqChipFlags::empty(),
100             }),
101         }
102     }
103     fn inner(&self) -> SpinLockGuard<InnerIrqChip> {
104         self.inner.lock_irqsave()
105     }
106 }
107 
108 #[derive(Debug)]
109 struct InnerIrqChip {
110     flags: IrqChipFlags,
111 }
112 
113 #[derive(Debug)]
114 struct RiscvIntcDomainOps;
115 
116 impl IrqDomainOps for RiscvIntcDomainOps {
117     fn map(
118         &self,
119         irq_domain: &Arc<IrqDomain>,
120         hwirq: HardwareIrqNumber,
121         virq: IrqNumber,
122     ) -> Result<(), SystemError> {
123         irq_desc_manager().set_percpu_devid_all(virq)?;
124         irq_domain_manager().domain_set_info(
125             irq_domain,
126             virq,
127             hwirq,
128             riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>,
129             irq_domain.host_data(),
130             &PerCpuDevIdIrqHandler,
131             None,
132             None,
133         );
134 
135         return Ok(());
136     }
137 
138     fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
139         todo!("riscv_intc_domain_ops::unmap");
140     }
141 }
142 
143 #[inline(never)]
144 pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
145     let intc_chip = Arc::new(RiscvIntcChip::new());
146 
147     unsafe {
148         RISCV_INTC_CHIP = Some(intc_chip);
149     }
150 
151     let intc_domain = irq_domain_manager()
152         .create_and_add_linear(
153             "riscv-intc".to_string(),
154             &RiscvIntcDomainOps,
155             RiscvIntcChip::IRQ_SIZE,
156         )
157         .ok_or_else(|| {
158             kerror!("Failed to create riscv-intc domain");
159             SystemError::ENXIO
160         })?;
161 
162     irq_domain_manager().set_default_domain(intc_domain.clone());
163 
164     unsafe {
165         RISCV_INTC_DOMAIN = Some(intc_domain.clone());
166     }
167 
168     riscv_sbi_timer_irq_desc_init();
169 
170     return Ok(());
171 }
172 
173 /// 把硬件中断号转换为riscv intc芯片的中断域的虚拟中断号
174 pub const fn riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
175     if hwirq.data() < RiscvIntcChip::IRQ_SIZE {
176         Some(IrqNumber::new(hwirq.data() + RISCV_INTC_VIRQ_START))
177     } else {
178         None
179     }
180 }
181 
182 /// 把riscv intc芯片的的中断域的虚拟中断号转换为硬件中断号
183 #[allow(dead_code)]
184 pub const fn riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber> {
185     if virq.data() >= RISCV_INTC_VIRQ_START
186         && virq.data() < RISCV_INTC_VIRQ_START + RiscvIntcChip::IRQ_SIZE
187     {
188         Some(HardwareIrqNumber::new(virq.data() - RISCV_INTC_VIRQ_START))
189     } else {
190         None
191     }
192 }
193 
194 /// 将硬件中断号与riscv intc芯片的虚拟中断号关联
195 pub fn riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
196     let virq = riscv_intc_hwirq_to_virq(hwirq)?;
197     irq_domain_manager()
198         .domain_associate(
199             riscv_intc_domain().as_ref().or_else(|| {
200                 kerror!("riscv_intc_domain is None");
201                 None
202             })?,
203             virq,
204             hwirq,
205         )
206         .ok();
207 
208     Some(virq)
209 }
210 
211 /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
212 pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
213     let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
214     if hwirq.data() == 9 {
215         // external interrupt
216         do_plic_irq(trap_frame);
217     } else {
218         GenericIrqHandler::handle_domain_irq(
219             riscv_intc_domain().clone().unwrap(),
220             hwirq,
221             trap_frame,
222         )
223         .ok();
224     }
225     do_softirq();
226     if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
227         __schedule(SchedMode::SM_PREEMPT);
228     }
229 }
230