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)]
riscv_intc_domain() -> &'static Option<Arc<IrqDomain>>27 pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
28 unsafe { &RISCV_INTC_DOMAIN }
29 }
30
31 #[inline(always)]
riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>>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 {
name(&self) -> &'static str45 fn name(&self) -> &'static str {
46 "RISC-V INTC"
47 }
48
irq_disable(&self, _irq: &Arc<IrqData>)49 fn irq_disable(&self, _irq: &Arc<IrqData>) {}
50
irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError>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
irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError>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
irq_ack(&self, _irq: &Arc<IrqData>)61 fn irq_ack(&self, _irq: &Arc<IrqData>) {}
62
can_mask_ack(&self) -> bool63 fn can_mask_ack(&self) -> bool {
64 false
65 }
66
irq_eoi(&self, _irq: &Arc<IrqData>)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
can_set_affinity(&self) -> bool82 fn can_set_affinity(&self) -> bool {
83 false
84 }
85
can_set_flow_type(&self) -> bool86 fn can_set_flow_type(&self) -> bool {
87 false
88 }
89
flags(&self) -> IrqChipFlags90 fn flags(&self) -> IrqChipFlags {
91 self.inner().flags
92 }
93 }
94
95 impl RiscvIntcChip {
96 const IRQ_SIZE: u32 = 64;
new() -> Self97 fn new() -> Self {
98 Self {
99 inner: SpinLock::new(InnerIrqChip {
100 flags: IrqChipFlags::empty(),
101 }),
102 }
103 }
inner(&self) -> SpinLockGuard<InnerIrqChip>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 {
map( &self, irq_domain: &Arc<IrqDomain>, hwirq: HardwareIrqNumber, virq: IrqNumber, ) -> Result<(), SystemError>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
unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber)139 fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
140 todo!("riscv_intc_domain_ops::unmap");
141 }
142 }
143
144 #[inline(never)]
riscv_intc_init() -> Result<(), SystemError>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芯片的中断域的虚拟中断号
riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber>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)]
riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber>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芯片的虚拟中断号关联
riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber>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
riscv_intc_irq(trap_frame: &mut TrapFrame)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