xref: /DragonOS/kernel/src/driver/irqchip/riscv_intc.rs (revision 4f8f484930ed3c09ecf4b5b05b1dea14f7b05d8b)
1 use alloc::{string::ToString, sync::Arc};
2 use system_error::SystemError;
3 
4 use crate::exception::{
5     handle::PerCpuDevIdIrqHandler,
6     irqchip::{IrqChip, IrqChipFlags},
7     irqdata::IrqData,
8     irqdesc::irq_desc_manager,
9     irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
10     HardwareIrqNumber, IrqNumber,
11 };
12 
13 static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
14 static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
15 
16 #[inline(always)]
17 pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
18     unsafe { &RISCV_INTC_DOMAIN }
19 }
20 
21 #[inline(always)]
22 fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
23     unsafe { RISCV_INTC_CHIP.as_ref() }
24 }
25 
26 #[derive(Debug)]
27 struct RiscvIntcChip;
28 
29 impl IrqChip for RiscvIntcChip {
30     fn name(&self) -> &'static str {
31         "RISC-V INTC"
32     }
33 
34     fn irq_disable(&self, _irq: &Arc<IrqData>) {}
35 
36     fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
37         unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) };
38         Ok(())
39     }
40 
41     fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
42         unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) };
43         Ok(())
44     }
45 
46     fn irq_ack(&self, irq: &Arc<IrqData>) {
47         todo!()
48     }
49 
50     fn can_mask_ack(&self) -> bool {
51         false
52     }
53 
54     fn irq_eoi(&self, _irq: &Arc<IrqData>) {
55         /*
56          * The RISC-V INTC driver uses handle_percpu_devid_irq() flow
57          * for the per-HART local interrupts and child irqchip drivers
58          * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement
59          * chained handlers for the per-HART local interrupts.
60          *
61          * In the absence of irq_eoi(), the chained_irq_enter() and
62          * chained_irq_exit() functions (used by child irqchip drivers)
63          * will do unnecessary mask/unmask of per-HART local interrupts
64          * at the time of handling interrupts. To avoid this, we provide
65          * an empty irq_eoi() callback for RISC-V INTC irqchip.
66          */
67     }
68 
69     fn can_set_affinity(&self) -> bool {
70         false
71     }
72 
73     fn can_set_flow_type(&self) -> bool {
74         false
75     }
76 
77     fn flags(&self) -> IrqChipFlags {
78         todo!()
79     }
80 }
81 
82 #[derive(Debug)]
83 struct RiscvIntcDomainOps;
84 
85 impl IrqDomainOps for RiscvIntcDomainOps {
86     fn map(
87         &self,
88         irq_domain: &Arc<IrqDomain>,
89         hwirq: HardwareIrqNumber,
90         virq: IrqNumber,
91     ) -> Result<(), SystemError> {
92         irq_desc_manager().set_percpu_devid_all(virq)?;
93         irq_domain_manager().domain_set_info(
94             irq_domain,
95             virq,
96             hwirq,
97             riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>,
98             irq_domain.host_data(),
99             &PerCpuDevIdIrqHandler,
100             None,
101             None,
102         );
103 
104         return Ok(());
105     }
106 
107     fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber) {
108         todo!("riscv_intc_domain_ops::unmap");
109     }
110 }
111 
112 #[inline(never)]
113 pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
114     let intc_chip = Arc::new(RiscvIntcChip);
115 
116     unsafe {
117         RISCV_INTC_CHIP = Some(intc_chip);
118     }
119 
120     let intc_domain = irq_domain_manager()
121         .create_and_add_linear("riscv-intc".to_string(), &RiscvIntcDomainOps, 64)
122         .ok_or_else(|| {
123             kerror!("Failed to create riscv-intc domain");
124             SystemError::ENXIO
125         })?;
126 
127     irq_domain_manager().set_default_domain(intc_domain.clone());
128 
129     unsafe {
130         RISCV_INTC_DOMAIN = Some(intc_domain);
131     }
132 
133     return Ok(());
134 }
135