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