xref: /DragonOS/kernel/src/driver/irqchip/riscv_intc.rs (revision f049d1af01da7b92f312245ed411b22475b76065)
1338f6903SLoGin use alloc::{string::ToString, sync::Arc};
2338f6903SLoGin use system_error::SystemError;
3338f6903SLoGin 
4*f049d1afSLoGin use crate::{
5*f049d1afSLoGin     arch::interrupt::TrapFrame,
6*f049d1afSLoGin     driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer},
7*f049d1afSLoGin     exception::{
8338f6903SLoGin         handle::PerCpuDevIdIrqHandler,
9338f6903SLoGin         irqchip::{IrqChip, IrqChipFlags},
10338f6903SLoGin         irqdata::IrqData,
11*f049d1afSLoGin         irqdesc::{irq_desc_manager, GenericIrqHandler},
12338f6903SLoGin         irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
13338f6903SLoGin         HardwareIrqNumber, IrqNumber,
14*f049d1afSLoGin     },
15*f049d1afSLoGin     libs::spinlock::{SpinLock, SpinLockGuard},
16*f049d1afSLoGin     sched::{SchedMode, __schedule},
17338f6903SLoGin };
18338f6903SLoGin 
19338f6903SLoGin static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
20338f6903SLoGin static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
21338f6903SLoGin 
22338f6903SLoGin #[inline(always)]
23338f6903SLoGin pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
24338f6903SLoGin     unsafe { &RISCV_INTC_DOMAIN }
25338f6903SLoGin }
26338f6903SLoGin 
27338f6903SLoGin #[inline(always)]
28338f6903SLoGin fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
29338f6903SLoGin     unsafe { RISCV_INTC_CHIP.as_ref() }
30338f6903SLoGin }
31338f6903SLoGin 
32338f6903SLoGin #[derive(Debug)]
33*f049d1afSLoGin struct RiscvIntcChip {
34*f049d1afSLoGin     inner: SpinLock<InnerIrqChip>,
35*f049d1afSLoGin }
36338f6903SLoGin 
37338f6903SLoGin impl IrqChip for RiscvIntcChip {
38338f6903SLoGin     fn name(&self) -> &'static str {
39338f6903SLoGin         "RISC-V INTC"
40338f6903SLoGin     }
41338f6903SLoGin 
42338f6903SLoGin     fn irq_disable(&self, _irq: &Arc<IrqData>) {}
43338f6903SLoGin 
44338f6903SLoGin     fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
45338f6903SLoGin         unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) };
46338f6903SLoGin         Ok(())
47338f6903SLoGin     }
48338f6903SLoGin 
49338f6903SLoGin     fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
50338f6903SLoGin         unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) };
51338f6903SLoGin         Ok(())
52338f6903SLoGin     }
53338f6903SLoGin 
54*f049d1afSLoGin     fn irq_ack(&self, _irq: &Arc<IrqData>) {}
55338f6903SLoGin 
56338f6903SLoGin     fn can_mask_ack(&self) -> bool {
57338f6903SLoGin         false
58338f6903SLoGin     }
59338f6903SLoGin 
60338f6903SLoGin     fn irq_eoi(&self, _irq: &Arc<IrqData>) {
61338f6903SLoGin         /*
62338f6903SLoGin          * The RISC-V INTC driver uses handle_percpu_devid_irq() flow
63338f6903SLoGin          * for the per-HART local interrupts and child irqchip drivers
64338f6903SLoGin          * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement
65338f6903SLoGin          * chained handlers for the per-HART local interrupts.
66338f6903SLoGin          *
67338f6903SLoGin          * In the absence of irq_eoi(), the chained_irq_enter() and
68338f6903SLoGin          * chained_irq_exit() functions (used by child irqchip drivers)
69338f6903SLoGin          * will do unnecessary mask/unmask of per-HART local interrupts
70338f6903SLoGin          * at the time of handling interrupts. To avoid this, we provide
71338f6903SLoGin          * an empty irq_eoi() callback for RISC-V INTC irqchip.
72338f6903SLoGin          */
73338f6903SLoGin     }
74338f6903SLoGin 
75338f6903SLoGin     fn can_set_affinity(&self) -> bool {
76338f6903SLoGin         false
77338f6903SLoGin     }
78338f6903SLoGin 
79338f6903SLoGin     fn can_set_flow_type(&self) -> bool {
80338f6903SLoGin         false
81338f6903SLoGin     }
82338f6903SLoGin 
83338f6903SLoGin     fn flags(&self) -> IrqChipFlags {
84*f049d1afSLoGin         self.inner().flags
85338f6903SLoGin     }
86338f6903SLoGin }
87338f6903SLoGin 
88*f049d1afSLoGin impl RiscvIntcChip {
89*f049d1afSLoGin     fn new() -> Self {
90*f049d1afSLoGin         Self {
91*f049d1afSLoGin             inner: SpinLock::new(InnerIrqChip {
92*f049d1afSLoGin                 flags: IrqChipFlags::empty(),
93*f049d1afSLoGin             }),
94*f049d1afSLoGin         }
95*f049d1afSLoGin     }
96*f049d1afSLoGin     fn inner(&self) -> SpinLockGuard<InnerIrqChip> {
97*f049d1afSLoGin         self.inner.lock_irqsave()
98*f049d1afSLoGin     }
99*f049d1afSLoGin }
100*f049d1afSLoGin 
101*f049d1afSLoGin #[derive(Debug)]
102*f049d1afSLoGin struct InnerIrqChip {
103*f049d1afSLoGin     flags: IrqChipFlags,
104*f049d1afSLoGin }
105*f049d1afSLoGin 
106338f6903SLoGin #[derive(Debug)]
107338f6903SLoGin struct RiscvIntcDomainOps;
108338f6903SLoGin 
109338f6903SLoGin impl IrqDomainOps for RiscvIntcDomainOps {
110338f6903SLoGin     fn map(
111338f6903SLoGin         &self,
112338f6903SLoGin         irq_domain: &Arc<IrqDomain>,
113338f6903SLoGin         hwirq: HardwareIrqNumber,
114338f6903SLoGin         virq: IrqNumber,
115338f6903SLoGin     ) -> Result<(), SystemError> {
116338f6903SLoGin         irq_desc_manager().set_percpu_devid_all(virq)?;
117338f6903SLoGin         irq_domain_manager().domain_set_info(
118338f6903SLoGin             irq_domain,
119338f6903SLoGin             virq,
120338f6903SLoGin             hwirq,
121338f6903SLoGin             riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>,
122338f6903SLoGin             irq_domain.host_data(),
123338f6903SLoGin             &PerCpuDevIdIrqHandler,
124338f6903SLoGin             None,
125338f6903SLoGin             None,
126338f6903SLoGin         );
127338f6903SLoGin 
128338f6903SLoGin         return Ok(());
129338f6903SLoGin     }
130338f6903SLoGin 
131*f049d1afSLoGin     fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
132338f6903SLoGin         todo!("riscv_intc_domain_ops::unmap");
133338f6903SLoGin     }
134338f6903SLoGin }
135338f6903SLoGin 
136338f6903SLoGin #[inline(never)]
137338f6903SLoGin pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
138*f049d1afSLoGin     let intc_chip = Arc::new(RiscvIntcChip::new());
139338f6903SLoGin 
140338f6903SLoGin     unsafe {
141338f6903SLoGin         RISCV_INTC_CHIP = Some(intc_chip);
142338f6903SLoGin     }
143338f6903SLoGin 
144338f6903SLoGin     let intc_domain = irq_domain_manager()
145338f6903SLoGin         .create_and_add_linear("riscv-intc".to_string(), &RiscvIntcDomainOps, 64)
146338f6903SLoGin         .ok_or_else(|| {
147338f6903SLoGin             kerror!("Failed to create riscv-intc domain");
148338f6903SLoGin             SystemError::ENXIO
149338f6903SLoGin         })?;
150338f6903SLoGin 
151338f6903SLoGin     irq_domain_manager().set_default_domain(intc_domain.clone());
152338f6903SLoGin 
153338f6903SLoGin     unsafe {
154338f6903SLoGin         RISCV_INTC_DOMAIN = Some(intc_domain);
155338f6903SLoGin     }
156338f6903SLoGin 
157*f049d1afSLoGin     riscv_sbi_timer_irq_desc_init();
158*f049d1afSLoGin 
159338f6903SLoGin     return Ok(());
160338f6903SLoGin }
161*f049d1afSLoGin 
162*f049d1afSLoGin /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
163*f049d1afSLoGin pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
164*f049d1afSLoGin     let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
165*f049d1afSLoGin     kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
166*f049d1afSLoGin     GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
167*f049d1afSLoGin         .ok();
168*f049d1afSLoGin     if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
169*f049d1afSLoGin         __schedule(SchedMode::SM_PREEMPT);
170*f049d1afSLoGin     }
171*f049d1afSLoGin }
172