xref: /DragonOS/kernel/src/driver/irqchip/riscv_intc.rs (revision 0102d69fdd231e472d7bb3d609a41ae56a3799ee)
1338f6903SLoGin use alloc::{string::ToString, sync::Arc};
2338f6903SLoGin use system_error::SystemError;
3338f6903SLoGin 
4f049d1afSLoGin use crate::{
5f049d1afSLoGin     arch::interrupt::TrapFrame,
6f049d1afSLoGin     driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer},
7f049d1afSLoGin     exception::{
8338f6903SLoGin         handle::PerCpuDevIdIrqHandler,
9338f6903SLoGin         irqchip::{IrqChip, IrqChipFlags},
10338f6903SLoGin         irqdata::IrqData,
11f049d1afSLoGin         irqdesc::{irq_desc_manager, GenericIrqHandler},
12338f6903SLoGin         irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
130722a06aSLoGin         softirq::do_softirq,
14338f6903SLoGin         HardwareIrqNumber, IrqNumber,
15f049d1afSLoGin     },
16f049d1afSLoGin     libs::spinlock::{SpinLock, SpinLockGuard},
17f049d1afSLoGin     sched::{SchedMode, __schedule},
18338f6903SLoGin };
19338f6903SLoGin 
20*0102d69fSLoGin use super::riscv_sifive_plic::do_plic_irq;
21*0102d69fSLoGin 
22338f6903SLoGin static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
23338f6903SLoGin static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
24338f6903SLoGin 
25338f6903SLoGin #[inline(always)]
26338f6903SLoGin pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
27338f6903SLoGin     unsafe { &RISCV_INTC_DOMAIN }
28338f6903SLoGin }
29338f6903SLoGin 
30338f6903SLoGin #[inline(always)]
31338f6903SLoGin fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
32338f6903SLoGin     unsafe { RISCV_INTC_CHIP.as_ref() }
33338f6903SLoGin }
34338f6903SLoGin 
35*0102d69fSLoGin /// RISC-V INTC虚拟中断号的起始值(192映射物理的0)
36*0102d69fSLoGin pub const RISCV_INTC_VIRQ_START: u32 = 192;
37*0102d69fSLoGin 
38338f6903SLoGin #[derive(Debug)]
39f049d1afSLoGin struct RiscvIntcChip {
40f049d1afSLoGin     inner: SpinLock<InnerIrqChip>,
41f049d1afSLoGin }
42338f6903SLoGin 
43338f6903SLoGin impl IrqChip for RiscvIntcChip {
44338f6903SLoGin     fn name(&self) -> &'static str {
45338f6903SLoGin         "RISC-V INTC"
46338f6903SLoGin     }
47338f6903SLoGin 
48338f6903SLoGin     fn irq_disable(&self, _irq: &Arc<IrqData>) {}
49338f6903SLoGin 
50338f6903SLoGin     fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
51338f6903SLoGin         unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) };
52338f6903SLoGin         Ok(())
53338f6903SLoGin     }
54338f6903SLoGin 
55338f6903SLoGin     fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
56338f6903SLoGin         unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) };
57338f6903SLoGin         Ok(())
58338f6903SLoGin     }
59338f6903SLoGin 
60f049d1afSLoGin     fn irq_ack(&self, _irq: &Arc<IrqData>) {}
61338f6903SLoGin 
62338f6903SLoGin     fn can_mask_ack(&self) -> bool {
63338f6903SLoGin         false
64338f6903SLoGin     }
65338f6903SLoGin 
66338f6903SLoGin     fn irq_eoi(&self, _irq: &Arc<IrqData>) {
67338f6903SLoGin         /*
68338f6903SLoGin          * The RISC-V INTC driver uses handle_percpu_devid_irq() flow
69338f6903SLoGin          * for the per-HART local interrupts and child irqchip drivers
70338f6903SLoGin          * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement
71338f6903SLoGin          * chained handlers for the per-HART local interrupts.
72338f6903SLoGin          *
73338f6903SLoGin          * In the absence of irq_eoi(), the chained_irq_enter() and
74338f6903SLoGin          * chained_irq_exit() functions (used by child irqchip drivers)
75338f6903SLoGin          * will do unnecessary mask/unmask of per-HART local interrupts
76338f6903SLoGin          * at the time of handling interrupts. To avoid this, we provide
77338f6903SLoGin          * an empty irq_eoi() callback for RISC-V INTC irqchip.
78338f6903SLoGin          */
79338f6903SLoGin     }
80338f6903SLoGin 
81338f6903SLoGin     fn can_set_affinity(&self) -> bool {
82338f6903SLoGin         false
83338f6903SLoGin     }
84338f6903SLoGin 
85338f6903SLoGin     fn can_set_flow_type(&self) -> bool {
86338f6903SLoGin         false
87338f6903SLoGin     }
88338f6903SLoGin 
89338f6903SLoGin     fn flags(&self) -> IrqChipFlags {
90f049d1afSLoGin         self.inner().flags
91338f6903SLoGin     }
92338f6903SLoGin }
93338f6903SLoGin 
94f049d1afSLoGin impl RiscvIntcChip {
95*0102d69fSLoGin     const IRQ_SIZE: u32 = 64;
96f049d1afSLoGin     fn new() -> Self {
97f049d1afSLoGin         Self {
98f049d1afSLoGin             inner: SpinLock::new(InnerIrqChip {
99f049d1afSLoGin                 flags: IrqChipFlags::empty(),
100f049d1afSLoGin             }),
101f049d1afSLoGin         }
102f049d1afSLoGin     }
103f049d1afSLoGin     fn inner(&self) -> SpinLockGuard<InnerIrqChip> {
104f049d1afSLoGin         self.inner.lock_irqsave()
105f049d1afSLoGin     }
106f049d1afSLoGin }
107f049d1afSLoGin 
108f049d1afSLoGin #[derive(Debug)]
109f049d1afSLoGin struct InnerIrqChip {
110f049d1afSLoGin     flags: IrqChipFlags,
111f049d1afSLoGin }
112f049d1afSLoGin 
113338f6903SLoGin #[derive(Debug)]
114338f6903SLoGin struct RiscvIntcDomainOps;
115338f6903SLoGin 
116338f6903SLoGin impl IrqDomainOps for RiscvIntcDomainOps {
117338f6903SLoGin     fn map(
118338f6903SLoGin         &self,
119338f6903SLoGin         irq_domain: &Arc<IrqDomain>,
120338f6903SLoGin         hwirq: HardwareIrqNumber,
121338f6903SLoGin         virq: IrqNumber,
122338f6903SLoGin     ) -> Result<(), SystemError> {
123338f6903SLoGin         irq_desc_manager().set_percpu_devid_all(virq)?;
124338f6903SLoGin         irq_domain_manager().domain_set_info(
125338f6903SLoGin             irq_domain,
126338f6903SLoGin             virq,
127338f6903SLoGin             hwirq,
128338f6903SLoGin             riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>,
129338f6903SLoGin             irq_domain.host_data(),
130338f6903SLoGin             &PerCpuDevIdIrqHandler,
131338f6903SLoGin             None,
132338f6903SLoGin             None,
133338f6903SLoGin         );
134338f6903SLoGin 
135338f6903SLoGin         return Ok(());
136338f6903SLoGin     }
137338f6903SLoGin 
138f049d1afSLoGin     fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
139338f6903SLoGin         todo!("riscv_intc_domain_ops::unmap");
140338f6903SLoGin     }
141338f6903SLoGin }
142338f6903SLoGin 
143338f6903SLoGin #[inline(never)]
144338f6903SLoGin pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
145f049d1afSLoGin     let intc_chip = Arc::new(RiscvIntcChip::new());
146338f6903SLoGin 
147338f6903SLoGin     unsafe {
148338f6903SLoGin         RISCV_INTC_CHIP = Some(intc_chip);
149338f6903SLoGin     }
150338f6903SLoGin 
151338f6903SLoGin     let intc_domain = irq_domain_manager()
152*0102d69fSLoGin         .create_and_add_linear(
153*0102d69fSLoGin             "riscv-intc".to_string(),
154*0102d69fSLoGin             &RiscvIntcDomainOps,
155*0102d69fSLoGin             RiscvIntcChip::IRQ_SIZE,
156*0102d69fSLoGin         )
157338f6903SLoGin         .ok_or_else(|| {
158338f6903SLoGin             kerror!("Failed to create riscv-intc domain");
159338f6903SLoGin             SystemError::ENXIO
160338f6903SLoGin         })?;
161338f6903SLoGin 
162338f6903SLoGin     irq_domain_manager().set_default_domain(intc_domain.clone());
163338f6903SLoGin 
164338f6903SLoGin     unsafe {
165*0102d69fSLoGin         RISCV_INTC_DOMAIN = Some(intc_domain.clone());
166338f6903SLoGin     }
167338f6903SLoGin 
168f049d1afSLoGin     riscv_sbi_timer_irq_desc_init();
169f049d1afSLoGin 
170338f6903SLoGin     return Ok(());
171338f6903SLoGin }
172f049d1afSLoGin 
173*0102d69fSLoGin /// 把硬件中断号转换为riscv intc芯片的中断域的虚拟中断号
174*0102d69fSLoGin pub const fn riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
175*0102d69fSLoGin     if hwirq.data() < RiscvIntcChip::IRQ_SIZE {
176*0102d69fSLoGin         Some(IrqNumber::new(hwirq.data() + RISCV_INTC_VIRQ_START))
177*0102d69fSLoGin     } else {
178*0102d69fSLoGin         None
179*0102d69fSLoGin     }
180*0102d69fSLoGin }
181*0102d69fSLoGin 
182*0102d69fSLoGin /// 把riscv intc芯片的的中断域的虚拟中断号转换为硬件中断号
183*0102d69fSLoGin #[allow(dead_code)]
184*0102d69fSLoGin pub const fn riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber> {
185*0102d69fSLoGin     if virq.data() >= RISCV_INTC_VIRQ_START
186*0102d69fSLoGin         && virq.data() < RISCV_INTC_VIRQ_START + RiscvIntcChip::IRQ_SIZE
187*0102d69fSLoGin     {
188*0102d69fSLoGin         Some(HardwareIrqNumber::new(virq.data() - RISCV_INTC_VIRQ_START))
189*0102d69fSLoGin     } else {
190*0102d69fSLoGin         None
191*0102d69fSLoGin     }
192*0102d69fSLoGin }
193*0102d69fSLoGin 
194*0102d69fSLoGin /// 将硬件中断号与riscv intc芯片的虚拟中断号关联
195*0102d69fSLoGin pub fn riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
196*0102d69fSLoGin     let virq = riscv_intc_hwirq_to_virq(hwirq)?;
197*0102d69fSLoGin     irq_domain_manager()
198*0102d69fSLoGin         .domain_associate(
199*0102d69fSLoGin             riscv_intc_domain().as_ref().or_else(|| {
200*0102d69fSLoGin                 kerror!("riscv_intc_domain is None");
201*0102d69fSLoGin                 None
202*0102d69fSLoGin             })?,
203*0102d69fSLoGin             virq,
204*0102d69fSLoGin             hwirq,
205*0102d69fSLoGin         )
206*0102d69fSLoGin         .ok();
207*0102d69fSLoGin 
208*0102d69fSLoGin     Some(virq)
209*0102d69fSLoGin }
210*0102d69fSLoGin 
211f049d1afSLoGin /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
212f049d1afSLoGin pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
213f049d1afSLoGin     let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
214*0102d69fSLoGin     if hwirq.data() == 9 {
215*0102d69fSLoGin         // external interrupt
216*0102d69fSLoGin         do_plic_irq(trap_frame);
217*0102d69fSLoGin     } else {
218*0102d69fSLoGin         GenericIrqHandler::handle_domain_irq(
219*0102d69fSLoGin             riscv_intc_domain().clone().unwrap(),
220*0102d69fSLoGin             hwirq,
221*0102d69fSLoGin             trap_frame,
222*0102d69fSLoGin         )
223f049d1afSLoGin         .ok();
224*0102d69fSLoGin     }
2250722a06aSLoGin     do_softirq();
226f049d1afSLoGin     if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
227f049d1afSLoGin         __schedule(SchedMode::SM_PREEMPT);
228f049d1afSLoGin     }
229f049d1afSLoGin }
230