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