1 use alloc::{string::ToString, sync::Arc}; 2 use system_error::SystemError; 3 4 use crate::{ 5 arch::interrupt::TrapFrame, 6 driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer}, 7 exception::{ 8 handle::PerCpuDevIdIrqHandler, 9 irqchip::{IrqChip, IrqChipFlags}, 10 irqdata::IrqData, 11 irqdesc::{irq_desc_manager, GenericIrqHandler}, 12 irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps}, 13 HardwareIrqNumber, IrqNumber, 14 }, 15 libs::spinlock::{SpinLock, SpinLockGuard}, 16 sched::{SchedMode, __schedule}, 17 }; 18 19 static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None; 20 static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None; 21 22 #[inline(always)] 23 pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> { 24 unsafe { &RISCV_INTC_DOMAIN } 25 } 26 27 #[inline(always)] 28 fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> { 29 unsafe { RISCV_INTC_CHIP.as_ref() } 30 } 31 32 #[derive(Debug)] 33 struct RiscvIntcChip { 34 inner: SpinLock<InnerIrqChip>, 35 } 36 37 impl IrqChip for RiscvIntcChip { 38 fn name(&self) -> &'static str { 39 "RISC-V INTC" 40 } 41 42 fn irq_disable(&self, _irq: &Arc<IrqData>) {} 43 44 fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> { 45 unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) }; 46 Ok(()) 47 } 48 49 fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> { 50 unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) }; 51 Ok(()) 52 } 53 54 fn irq_ack(&self, _irq: &Arc<IrqData>) {} 55 56 fn can_mask_ack(&self) -> bool { 57 false 58 } 59 60 fn irq_eoi(&self, _irq: &Arc<IrqData>) { 61 /* 62 * The RISC-V INTC driver uses handle_percpu_devid_irq() flow 63 * for the per-HART local interrupts and child irqchip drivers 64 * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement 65 * chained handlers for the per-HART local interrupts. 66 * 67 * In the absence of irq_eoi(), the chained_irq_enter() and 68 * chained_irq_exit() functions (used by child irqchip drivers) 69 * will do unnecessary mask/unmask of per-HART local interrupts 70 * at the time of handling interrupts. To avoid this, we provide 71 * an empty irq_eoi() callback for RISC-V INTC irqchip. 72 */ 73 } 74 75 fn can_set_affinity(&self) -> bool { 76 false 77 } 78 79 fn can_set_flow_type(&self) -> bool { 80 false 81 } 82 83 fn flags(&self) -> IrqChipFlags { 84 self.inner().flags 85 } 86 } 87 88 impl RiscvIntcChip { 89 fn new() -> Self { 90 Self { 91 inner: SpinLock::new(InnerIrqChip { 92 flags: IrqChipFlags::empty(), 93 }), 94 } 95 } 96 fn inner(&self) -> SpinLockGuard<InnerIrqChip> { 97 self.inner.lock_irqsave() 98 } 99 } 100 101 #[derive(Debug)] 102 struct InnerIrqChip { 103 flags: IrqChipFlags, 104 } 105 106 #[derive(Debug)] 107 struct RiscvIntcDomainOps; 108 109 impl IrqDomainOps for RiscvIntcDomainOps { 110 fn map( 111 &self, 112 irq_domain: &Arc<IrqDomain>, 113 hwirq: HardwareIrqNumber, 114 virq: IrqNumber, 115 ) -> Result<(), SystemError> { 116 irq_desc_manager().set_percpu_devid_all(virq)?; 117 irq_domain_manager().domain_set_info( 118 irq_domain, 119 virq, 120 hwirq, 121 riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>, 122 irq_domain.host_data(), 123 &PerCpuDevIdIrqHandler, 124 None, 125 None, 126 ); 127 128 return Ok(()); 129 } 130 131 fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) { 132 todo!("riscv_intc_domain_ops::unmap"); 133 } 134 } 135 136 #[inline(never)] 137 pub unsafe fn riscv_intc_init() -> Result<(), SystemError> { 138 let intc_chip = Arc::new(RiscvIntcChip::new()); 139 140 unsafe { 141 RISCV_INTC_CHIP = Some(intc_chip); 142 } 143 144 let intc_domain = irq_domain_manager() 145 .create_and_add_linear("riscv-intc".to_string(), &RiscvIntcDomainOps, 64) 146 .ok_or_else(|| { 147 kerror!("Failed to create riscv-intc domain"); 148 SystemError::ENXIO 149 })?; 150 151 irq_domain_manager().set_default_domain(intc_domain.clone()); 152 153 unsafe { 154 RISCV_INTC_DOMAIN = Some(intc_domain); 155 } 156 157 riscv_sbi_timer_irq_desc_init(); 158 159 return Ok(()); 160 } 161 162 /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23 163 pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) { 164 let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32); 165 kdebug!("riscv64_do_irq: interrupt {hwirq:?}"); 166 GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame) 167 .ok(); 168 if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() { 169 __schedule(SchedMode::SM_PREEMPT); 170 } 171 } 172