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)]
riscv_intc_domain() -> &'static Option<Arc<IrqDomain>>17 pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
18 unsafe { &RISCV_INTC_DOMAIN }
19 }
20
21 #[inline(always)]
riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>>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 {
name(&self) -> &'static str30 fn name(&self) -> &'static str {
31 "RISC-V INTC"
32 }
33
irq_disable(&self, _irq: &Arc<IrqData>)34 fn irq_disable(&self, _irq: &Arc<IrqData>) {}
35
irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError>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
irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError>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
irq_ack(&self, irq: &Arc<IrqData>)46 fn irq_ack(&self, irq: &Arc<IrqData>) {
47 todo!()
48 }
49
can_mask_ack(&self) -> bool50 fn can_mask_ack(&self) -> bool {
51 false
52 }
53
irq_eoi(&self, _irq: &Arc<IrqData>)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
can_set_affinity(&self) -> bool69 fn can_set_affinity(&self) -> bool {
70 false
71 }
72
can_set_flow_type(&self) -> bool73 fn can_set_flow_type(&self) -> bool {
74 false
75 }
76
flags(&self) -> IrqChipFlags77 fn flags(&self) -> IrqChipFlags {
78 todo!()
79 }
80 }
81
82 #[derive(Debug)]
83 struct RiscvIntcDomainOps;
84
85 impl IrqDomainOps for RiscvIntcDomainOps {
map( &self, irq_domain: &Arc<IrqDomain>, hwirq: HardwareIrqNumber, virq: IrqNumber, ) -> Result<(), SystemError>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
unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber)107 fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber) {
108 todo!("riscv_intc_domain_ops::unmap");
109 }
110 }
111
112 #[inline(never)]
riscv_intc_init() -> Result<(), SystemError>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