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 use super::riscv_sifive_plic::do_plic_irq; 21 22 static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None; 23 static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None; 24 25 #[inline(always)] 26 pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> { 27 unsafe { &RISCV_INTC_DOMAIN } 28 } 29 30 #[inline(always)] 31 fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> { 32 unsafe { RISCV_INTC_CHIP.as_ref() } 33 } 34 35 /// RISC-V INTC虚拟中断号的起始值(192映射物理的0) 36 pub const RISCV_INTC_VIRQ_START: u32 = 192; 37 38 #[derive(Debug)] 39 struct RiscvIntcChip { 40 inner: SpinLock<InnerIrqChip>, 41 } 42 43 impl IrqChip for RiscvIntcChip { 44 fn name(&self) -> &'static str { 45 "RISC-V INTC" 46 } 47 48 fn irq_disable(&self, _irq: &Arc<IrqData>) {} 49 50 fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> { 51 unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) }; 52 Ok(()) 53 } 54 55 fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> { 56 unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) }; 57 Ok(()) 58 } 59 60 fn irq_ack(&self, _irq: &Arc<IrqData>) {} 61 62 fn can_mask_ack(&self) -> bool { 63 false 64 } 65 66 fn irq_eoi(&self, _irq: &Arc<IrqData>) { 67 /* 68 * The RISC-V INTC driver uses handle_percpu_devid_irq() flow 69 * for the per-HART local interrupts and child irqchip drivers 70 * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement 71 * chained handlers for the per-HART local interrupts. 72 * 73 * In the absence of irq_eoi(), the chained_irq_enter() and 74 * chained_irq_exit() functions (used by child irqchip drivers) 75 * will do unnecessary mask/unmask of per-HART local interrupts 76 * at the time of handling interrupts. To avoid this, we provide 77 * an empty irq_eoi() callback for RISC-V INTC irqchip. 78 */ 79 } 80 81 fn can_set_affinity(&self) -> bool { 82 false 83 } 84 85 fn can_set_flow_type(&self) -> bool { 86 false 87 } 88 89 fn flags(&self) -> IrqChipFlags { 90 self.inner().flags 91 } 92 } 93 94 impl RiscvIntcChip { 95 const IRQ_SIZE: u32 = 64; 96 fn new() -> Self { 97 Self { 98 inner: SpinLock::new(InnerIrqChip { 99 flags: IrqChipFlags::empty(), 100 }), 101 } 102 } 103 fn inner(&self) -> SpinLockGuard<InnerIrqChip> { 104 self.inner.lock_irqsave() 105 } 106 } 107 108 #[derive(Debug)] 109 struct InnerIrqChip { 110 flags: IrqChipFlags, 111 } 112 113 #[derive(Debug)] 114 struct RiscvIntcDomainOps; 115 116 impl IrqDomainOps for RiscvIntcDomainOps { 117 fn map( 118 &self, 119 irq_domain: &Arc<IrqDomain>, 120 hwirq: HardwareIrqNumber, 121 virq: IrqNumber, 122 ) -> Result<(), SystemError> { 123 irq_desc_manager().set_percpu_devid_all(virq)?; 124 irq_domain_manager().domain_set_info( 125 irq_domain, 126 virq, 127 hwirq, 128 riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>, 129 irq_domain.host_data(), 130 &PerCpuDevIdIrqHandler, 131 None, 132 None, 133 ); 134 135 return Ok(()); 136 } 137 138 fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) { 139 todo!("riscv_intc_domain_ops::unmap"); 140 } 141 } 142 143 #[inline(never)] 144 pub unsafe fn riscv_intc_init() -> Result<(), SystemError> { 145 let intc_chip = Arc::new(RiscvIntcChip::new()); 146 147 unsafe { 148 RISCV_INTC_CHIP = Some(intc_chip); 149 } 150 151 let intc_domain = irq_domain_manager() 152 .create_and_add_linear( 153 "riscv-intc".to_string(), 154 &RiscvIntcDomainOps, 155 RiscvIntcChip::IRQ_SIZE, 156 ) 157 .ok_or_else(|| { 158 kerror!("Failed to create riscv-intc domain"); 159 SystemError::ENXIO 160 })?; 161 162 irq_domain_manager().set_default_domain(intc_domain.clone()); 163 164 unsafe { 165 RISCV_INTC_DOMAIN = Some(intc_domain.clone()); 166 } 167 168 riscv_sbi_timer_irq_desc_init(); 169 170 return Ok(()); 171 } 172 173 /// 把硬件中断号转换为riscv intc芯片的中断域的虚拟中断号 174 pub const fn riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> { 175 if hwirq.data() < RiscvIntcChip::IRQ_SIZE { 176 Some(IrqNumber::new(hwirq.data() + RISCV_INTC_VIRQ_START)) 177 } else { 178 None 179 } 180 } 181 182 /// 把riscv intc芯片的的中断域的虚拟中断号转换为硬件中断号 183 #[allow(dead_code)] 184 pub const fn riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber> { 185 if virq.data() >= RISCV_INTC_VIRQ_START 186 && virq.data() < RISCV_INTC_VIRQ_START + RiscvIntcChip::IRQ_SIZE 187 { 188 Some(HardwareIrqNumber::new(virq.data() - RISCV_INTC_VIRQ_START)) 189 } else { 190 None 191 } 192 } 193 194 /// 将硬件中断号与riscv intc芯片的虚拟中断号关联 195 pub fn riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> { 196 let virq = riscv_intc_hwirq_to_virq(hwirq)?; 197 irq_domain_manager() 198 .domain_associate( 199 riscv_intc_domain().as_ref().or_else(|| { 200 kerror!("riscv_intc_domain is None"); 201 None 202 })?, 203 virq, 204 hwirq, 205 ) 206 .ok(); 207 208 Some(virq) 209 } 210 211 /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23 212 pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) { 213 let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32); 214 if hwirq.data() == 9 { 215 // external interrupt 216 do_plic_irq(trap_frame); 217 } else { 218 GenericIrqHandler::handle_domain_irq( 219 riscv_intc_domain().clone().unwrap(), 220 hwirq, 221 trap_frame, 222 ) 223 .ok(); 224 } 225 do_softirq(); 226 if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() { 227 __schedule(SchedMode::SM_PREEMPT); 228 } 229 } 230