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