xref: /DragonOS/kernel/src/driver/irqchip/riscv_sifive_plic.rs (revision c635d8a9cfe25bc11779f323ef0c7d7a0f597d4a)
1 //! 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c
2 //!
3 //!
4 //!
5 //!  This driver implements a version of the RISC-V PLIC with the actual layout
6 //!  specified in chapter 8 of the SiFive U5 Coreplex Series Manual:
7 //!
8 //!      https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf
9 //!
10 //!  The largest number supported by devices marked as 'sifive,plic-1.0.0', is
11 //!  1024, of which device 0 is defined as non-existent by the RISC-V Privileged
12 //!  Spec.
13 //!
14 
15 use core::{
16     fmt::Debug,
17     ops::Deref,
18     ptr::{read_volatile, write_volatile},
19     sync::atomic::AtomicBool,
20 };
21 
22 use alloc::{
23     string::ToString,
24     sync::{Arc, Weak},
25 };
26 use bitmap::AllocBitmap;
27 use fdt::node::FdtNode;
28 use log::{debug, warn};
29 use system_error::SystemError;
30 
31 use crate::{
32     arch::interrupt::TrapFrame,
33     driver::open_firmware::fdt::open_firmware_fdt_driver,
34     exception::{
35         handle::fast_eoi_irq_handler,
36         irqchip::{IrqChip, IrqChipData, IrqChipFlags, IrqChipSetMaskResult},
37         irqdata::IrqData,
38         irqdesc::{irq_desc_manager, GenericIrqHandler},
39         irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
40         manage::irq_manager,
41         HardwareIrqNumber, IrqNumber,
42     },
43     libs::{
44         cpumask::CpuMask,
45         once::Once,
46         spinlock::{SpinLock, SpinLockGuard},
47     },
48     mm::{
49         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
50         percpu::{PerCpu, PerCpuVar},
51         PhysAddr, VirtAddr,
52     },
53     smp::cpu::{smp_cpu_manager, ProcessorId},
54 };
55 
56 static mut PLIC_HANDLERS: Option<PerCpuVar<PlicHandler>> = None;
57 
58 static mut PLIC_IRQ_CHIP: Option<Arc<PlicIrqChip>> = None;
59 
60 #[inline(always)]
61 fn plic_irq_chip() -> Arc<PlicIrqChip> {
62     unsafe { PLIC_IRQ_CHIP.as_ref().unwrap().clone() }
63 }
64 
65 #[inline(always)]
66 fn plic_handlers() -> &'static PerCpuVar<PlicHandler> {
67     unsafe { PLIC_HANDLERS.as_ref().unwrap() }
68 }
69 
70 #[allow(dead_code)]
71 struct PlicChipData {
72     irq_domain: Weak<IrqDomain>,
73     phandle: u32,
74     lmask: SpinLock<CpuMask>,
75     mmio_guard: Option<MMIOSpaceGuard>,
76     regs: VirtAddr,
77 }
78 
79 impl PlicChipData {
80     fn new(
81         irq_domain: Weak<IrqDomain>,
82         mmio_guard: MMIOSpaceGuard,
83         regs: VirtAddr,
84         phandle: u32,
85     ) -> Arc<Self> {
86         let r = Self {
87             irq_domain,
88             lmask: SpinLock::new(CpuMask::new()),
89             mmio_guard: Some(mmio_guard),
90             regs,
91             phandle,
92         };
93 
94         Arc::new(r)
95     }
96 
97     fn lmask(&self) -> SpinLockGuard<CpuMask> {
98         self.lmask.lock()
99     }
100 }
101 
102 impl Debug for PlicChipData {
103     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104         f.debug_struct("PlicChipData").finish()
105     }
106 }
107 
108 impl IrqChipData for PlicChipData {
109     fn as_any_ref(&self) -> &dyn core::any::Any {
110         self
111     }
112 }
113 
114 struct PlicHandler {
115     priv_data: Option<Arc<PlicChipData>>,
116     present: AtomicBool,
117     inner: SpinLock<InnerPlicHandler>,
118 }
119 
120 struct InnerPlicHandler {
121     hart_base: VirtAddr,
122     enable_base: VirtAddr,
123     enable_save: Option<AllocBitmap>,
124 }
125 
126 impl PlicHandler {
127     fn new() -> Self {
128         let inner = InnerPlicHandler {
129             hart_base: VirtAddr::new(0),
130             enable_base: VirtAddr::new(0),
131             enable_save: None,
132         };
133         Self {
134             priv_data: None,
135             present: AtomicBool::new(false),
136             inner: SpinLock::new(inner),
137         }
138     }
139 
140     fn set_threshold(&self, threshold: u32) {
141         let inner = self.inner();
142         unsafe {
143             /* priority must be > threshold to trigger an interrupt */
144             core::ptr::write_volatile(
145                 (inner.hart_base + PlicIrqChip::CONTEXT_THRESHOLD).data() as *mut u32,
146                 threshold,
147             );
148         }
149     }
150 
151     unsafe fn force_set_priv_data(&mut self, priv_data: Arc<PlicChipData>) {
152         self.priv_data = Some(priv_data);
153     }
154 
155     fn priv_data(&self) -> Option<Arc<PlicChipData>> {
156         self.priv_data.clone()
157     }
158 
159     fn present(&self) -> bool {
160         self.present.load(core::sync::atomic::Ordering::SeqCst)
161     }
162 
163     fn set_present(&self, present: bool) {
164         self.present
165             .store(present, core::sync::atomic::Ordering::SeqCst);
166     }
167 
168     fn inner(&self) -> SpinLockGuard<InnerPlicHandler> {
169         self.inner.lock()
170     }
171 
172     fn toggle(&self, hwirq: HardwareIrqNumber, enable: bool) {
173         let inner = self.inner();
174         let reg = (inner.enable_base + ((hwirq.data() / 32) * 4) as usize).data() as *mut u32;
175         let hwirq_mask = 1 << (hwirq.data() % 32);
176 
177         if enable {
178             unsafe {
179                 core::ptr::write_volatile(reg, core::ptr::read_volatile(reg) | hwirq_mask);
180             }
181         } else {
182             unsafe {
183                 core::ptr::write_volatile(reg, core::ptr::read_volatile(reg) & !hwirq_mask);
184             }
185         }
186     }
187 }
188 
189 fn plic_irq_toggle(cpumask: &CpuMask, irq_data: &Arc<IrqData>, enable: bool) {
190     cpumask.iter_cpu().for_each(|cpu| {
191         debug!("plic: irq_toggle: cpu: {cpu:?}");
192         let handler = unsafe { plic_handlers().force_get(cpu) };
193         handler.toggle(irq_data.hardware_irq(), enable);
194     });
195 }
196 
197 /// SiFive PLIC中断控制器
198 ///
199 /// https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#204
200 #[derive(Debug)]
201 struct PlicIrqChip;
202 #[allow(dead_code)]
203 impl PlicIrqChip {
204     const COMPATIBLE: &'static str = "sifive,plic-1.0.0";
205 
206     const MAX_DEVICES: u32 = 1024;
207     const MAX_CONTEXTS: u32 = 15872;
208 
209     /*
210      * Each interrupt source has a priority register associated with it.
211      * We always hardwire it to one in Linux.
212      */
213     const PRIORITY_BASE: usize = 0;
214     const PRIORITY_PER_ID: usize = 4;
215 
216     /*
217      * Each hart context has a vector of interrupt enable bits associated with it.
218      * There's one bit for each interrupt source.
219      */
220     const CONTEXT_ENABLE_BASE: usize = 0x2080;
221     const CONTEXT_ENABLE_SIZE: usize = 0x100;
222 
223     /*
224      * Each hart context has a set of control registers associated with it.  Right
225      * now there's only two: a source priority threshold over which the hart will
226      * take an interrupt, and a register to claim interrupts.
227      */
228     const CONTEXT_BASE: usize = 0x201000;
229     const CONTEXT_SIZE: usize = 0x2000;
230     const CONTEXT_THRESHOLD: usize = 0x00;
231     const CONTEXT_CLAIM: usize = 0x04;
232 
233     const PLIC_DISABLE_THRESHOLD: u32 = 0x7;
234     const PLIC_ENABLE_THRESHOLD: u32 = 0;
235 
236     const PLIC_QUIRK_EDGE_INTERRUPT: u32 = 0;
237 }
238 
239 impl IrqChip for PlicIrqChip {
240     fn name(&self) -> &'static str {
241         "SiFive PLIC"
242     }
243     fn irq_enable(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
244         // warn!("plic: irq_enable");
245         let common_data = irq_data.common_data();
246         let inner_guard = common_data.inner();
247         let mask = inner_guard.effective_affinity();
248 
249         plic_irq_toggle(mask, irq_data, true);
250         self.irq_unmask(irq_data).expect("irq_unmask failed");
251 
252         Ok(())
253     }
254 
255     fn irq_unmask(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
256         // warn!("plic: irq_unmask");
257 
258         let chip_data = irq_data
259             .chip_info_read_irqsave()
260             .chip_data()
261             .ok_or(SystemError::EINVAL)?;
262         let plic_chip_data = chip_data
263             .as_any_ref()
264             .downcast_ref::<PlicChipData>()
265             .ok_or(SystemError::EINVAL)?;
266 
267         unsafe {
268             core::ptr::write_volatile(
269                 (plic_chip_data.regs
270                     + PlicIrqChip::PRIORITY_BASE
271                     + irq_data.hardware_irq().data() as usize * PlicIrqChip::PRIORITY_PER_ID)
272                     .data() as *mut u32,
273                 1,
274             );
275         }
276 
277         Ok(())
278     }
279 
280     fn irq_mask(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
281         let chip_data = irq_data
282             .chip_info_read_irqsave()
283             .chip_data()
284             .ok_or(SystemError::EINVAL)?;
285         let plic_chip_data = chip_data
286             .as_any_ref()
287             .downcast_ref::<PlicChipData>()
288             .ok_or(SystemError::EINVAL)?;
289 
290         unsafe {
291             core::ptr::write_volatile(
292                 (plic_chip_data.regs
293                     + PlicIrqChip::PRIORITY_BASE
294                     + irq_data.hardware_irq().data() as usize * PlicIrqChip::PRIORITY_PER_ID)
295                     .data() as *mut u32,
296                 0,
297             );
298         }
299 
300         Ok(())
301     }
302 
303     fn irq_disable(&self, irq_data: &Arc<IrqData>) {
304         debug!("plic: irq_disable");
305         let common_data = irq_data.common_data();
306         let inner_guard = common_data.inner();
307         let mask = inner_guard.effective_affinity();
308         plic_irq_toggle(mask, irq_data, false);
309     }
310 
311     fn irq_eoi(&self, irq_data: &Arc<IrqData>) {
312         let handler = plic_handlers().get();
313 
314         if core::intrinsics::unlikely(irq_data.common_data().disabled()) {
315             handler.toggle(irq_data.hardware_irq(), true);
316             unsafe {
317                 write_volatile(
318                     (handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *mut u32,
319                     irq_data.hardware_irq().data(),
320                 );
321             }
322 
323             handler.toggle(irq_data.hardware_irq(), false);
324         } else {
325             // debug!("plic: irq_eoi: hwirq: {:?}", irq_data.hardware_irq());
326             unsafe {
327                 write_volatile(
328                     (handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *mut u32,
329                     irq_data.hardware_irq().data(),
330                 );
331             }
332         }
333     }
334 
335     fn irq_ack(&self, _irq: &Arc<IrqData>) {
336         todo!()
337     }
338 
339     fn can_mask_ack(&self) -> bool {
340         false
341     }
342 
343     fn can_set_affinity(&self) -> bool {
344         true
345     }
346 
347     /// 设置中断的亲和性
348     ///
349     /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#161
350     fn irq_set_affinity(
351         &self,
352         irq_data: &Arc<IrqData>,
353         mask_val: &CpuMask,
354         force: bool,
355     ) -> Result<IrqChipSetMaskResult, SystemError> {
356         let chip_data = irq_data
357             .chip_info_read_irqsave()
358             .chip_data()
359             .ok_or(SystemError::EINVAL)?;
360         let plic_chip_data = chip_data
361             .as_any_ref()
362             .downcast_ref::<PlicChipData>()
363             .ok_or(SystemError::EINVAL)?;
364 
365         let mut amask = plic_chip_data.lmask().deref() & mask_val;
366         let cpu = if force {
367             mask_val.first()
368         } else {
369             amask.bitand_assign(smp_cpu_manager().possible_cpus());
370             // todo: 随机选择一个CPU
371             amask.first()
372         }
373         .ok_or(SystemError::EINVAL)?;
374 
375         if cpu.data() > smp_cpu_manager().present_cpus_count() {
376             return Err(SystemError::EINVAL);
377         }
378 
379         self.irq_disable(irq_data);
380         irq_data
381             .common_data()
382             .set_effective_affinity(CpuMask::from_cpu(cpu));
383         if !irq_data.common_data().disabled() {
384             self.irq_enable(irq_data).ok();
385         }
386 
387         Ok(IrqChipSetMaskResult::Done)
388     }
389 
390     fn can_set_flow_type(&self) -> bool {
391         false
392     }
393 
394     fn flags(&self) -> IrqChipFlags {
395         IrqChipFlags::empty()
396     }
397 }
398 
399 #[inline(never)]
400 pub fn riscv_sifive_plic_init() -> Result<(), SystemError> {
401     static INIT_PLIC_IRQ_CHIP_ONCE: Once = Once::new();
402     INIT_PLIC_IRQ_CHIP_ONCE.call_once(|| unsafe {
403         PLIC_IRQ_CHIP = Some(Arc::new(PlicIrqChip));
404 
405         PLIC_HANDLERS = Some(
406             PerCpuVar::new(
407                 (0..PerCpu::MAX_CPU_NUM)
408                     .map(|_| PlicHandler::new())
409                     .collect(),
410             )
411             .unwrap(),
412         );
413     });
414 
415     let fdt = open_firmware_fdt_driver().fdt_ref()?;
416     let all_plics = fdt.all_nodes().filter(|x| {
417         if let Some(compatible) = x.compatible() {
418             compatible
419                 .all()
420                 .any(|x| x == PlicIrqChip::COMPATIBLE || x == "riscv,plic0")
421         } else {
422             false
423         }
424     });
425     for node in all_plics {
426         if let Err(e) = do_riscv_sifive_plic_init(&node) {
427             warn!("Failed to init SiFive PLIC: node: {node:?} {e:?}");
428         }
429     }
430 
431     unsafe { riscv::register::sie::set_sext() };
432     Ok(())
433 }
434 
435 /// 初始化SiFive PLIC
436 ///
437 /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#415
438 fn do_riscv_sifive_plic_init(fdt_node: &FdtNode) -> Result<(), SystemError> {
439     let reg = fdt_node
440         .reg()
441         .ok_or(SystemError::EINVAL)?
442         .next()
443         .ok_or(SystemError::EIO)?;
444     let paddr = PhysAddr::new(reg.starting_address as usize);
445     let size = reg.size.ok_or(SystemError::EINVAL)?;
446     let mmio_guard = mmio_pool().create_mmio(size)?;
447     let vaddr = unsafe { mmio_guard.map_any_phys(paddr, size) }?;
448 
449     let phandle = fdt_node
450         .property("phandle")
451         .ok_or(SystemError::EINVAL)?
452         .as_usize()
453         .ok_or(SystemError::EINVAL)?;
454 
455     // 中断数量
456     let irq_num = fdt_node
457         .property("riscv,ndev")
458         .ok_or(SystemError::EINVAL)?
459         .as_usize()
460         .ok_or(SystemError::EINVAL)?;
461     debug!(
462         "plic: node: {}, irq_num: {irq_num}, paddr: {paddr:?}, size: {size}",
463         fdt_node.name
464     );
465     let nr_contexts = fdt_node
466         .interrupts_extended()
467         .ok_or(SystemError::EINVAL)?
468         .count();
469     debug!("plic: nr_contexts: {nr_contexts}");
470 
471     let irq_domain = irq_domain_manager()
472         .create_and_add_linear(
473             fdt_node.name.to_string(),
474             &PlicIrqDomainOps,
475             (irq_num + 1) as u32,
476         )
477         .ok_or(SystemError::EINVAL)?;
478     // debug!("plic: irq_domain: {irq_domain:?}");
479 
480     let priv_data = PlicChipData::new(
481         Arc::downgrade(&irq_domain),
482         mmio_guard,
483         vaddr,
484         phandle as u32,
485     );
486     irq_domain.set_host_data(Some(priv_data.clone() as Arc<dyn IrqChipData>));
487 
488     let loop_done_setup = |irq_handler: &PlicHandler| {
489         for x in 1..=irq_num {
490             irq_handler.toggle(HardwareIrqNumber::new(x as u32), false);
491 
492             unsafe {
493                 core::ptr::write_volatile(
494                     (priv_data.regs + PlicIrqChip::PRIORITY_BASE + x * PlicIrqChip::PRIORITY_PER_ID)
495                         .data() as *mut u32,
496                     1,
497                 )
498             };
499         }
500     };
501 
502     // todo: 学习linux那样处理,获取到hartid,这里暂时糊代码
503     // linux: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#458
504     for i in smp_cpu_manager().present_cpus().iter_cpu() {
505         let i = i.data() as usize;
506 
507         let cpu = ProcessorId::new(i as u32);
508         let handler = unsafe { plic_handlers().force_get(cpu) };
509         if handler.present() {
510             warn!("plic: handler {i} already present.");
511             handler.set_threshold(PlicIrqChip::PLIC_ENABLE_THRESHOLD);
512             loop_done_setup(handler);
513             continue;
514         }
515 
516         debug!("plic: setup lmask {cpu:?}.");
517         priv_data.lmask().set(cpu, true);
518         let mut handler_inner = handler.inner();
519         handler_inner.hart_base =
520             priv_data.regs + PlicIrqChip::CONTEXT_BASE + i * PlicIrqChip::CONTEXT_SIZE;
521         handler_inner.enable_base = priv_data.regs
522             + PlicIrqChip::CONTEXT_ENABLE_BASE
523             + i * PlicIrqChip::CONTEXT_ENABLE_SIZE;
524         handler.set_present(true);
525         unsafe {
526             plic_handlers()
527                 .force_get_mut(cpu)
528                 .force_set_priv_data(priv_data.clone())
529         };
530 
531         handler_inner.enable_save = Some(AllocBitmap::new(irq_num as usize));
532 
533         drop(handler_inner);
534         handler.set_threshold(PlicIrqChip::PLIC_ENABLE_THRESHOLD);
535 
536         loop_done_setup(handler);
537     }
538 
539     // 把外部设备的中断与PLIC关联起来
540     associate_irq_with_plic_domain(&irq_domain, phandle as u32).ok();
541 
542     Ok(())
543 }
544 
545 /// 把设备的中断与PLIC的关联起来
546 fn associate_irq_with_plic_domain(
547     irq_domain: &Arc<IrqDomain>,
548     plic_phandle: u32,
549 ) -> Result<(), SystemError> {
550     let fdt_ref = open_firmware_fdt_driver().fdt_ref()?;
551     let nodes = fdt_ref.all_nodes().filter(|x| {
552         if let Some(pa) = x.property("interrupt-parent").and_then(|x| x.as_usize()) {
553             pa as u32 == plic_phandle
554         } else {
555             false
556         }
557     });
558 
559     for node in nodes {
560         if let Some(irq) = node.interrupts().and_then(|mut x| x.next()) {
561             let irq = irq as u32;
562             let virq = IrqNumber::new(irq);
563             let hwirq = HardwareIrqNumber::new(irq);
564             debug!("plic: associate irq: {irq}, virq: {virq:?}, hwirq: {hwirq:?}");
565             irq_domain_manager()
566                 .domain_associate(irq_domain, virq, hwirq)
567                 .ok();
568         }
569     }
570 
571     Ok(())
572 }
573 #[derive(Debug)]
574 struct PlicIrqDomainOps;
575 
576 impl IrqDomainOps for PlicIrqDomainOps {
577     fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
578         todo!()
579     }
580 
581     fn map(
582         &self,
583         irq_domain: &Arc<IrqDomain>,
584         hwirq: HardwareIrqNumber,
585         virq: IrqNumber,
586     ) -> Result<(), SystemError> {
587         // debug!("plic: map: virq: {virq:?}, hwirq: {hwirq:?}");
588 
589         let chip_data = irq_domain.host_data().ok_or(SystemError::EINVAL)?;
590         let plic_chip_data = chip_data
591             .as_any_ref()
592             .downcast_ref::<PlicChipData>()
593             .ok_or(SystemError::EINVAL)?;
594         irq_domain_manager().domain_set_info(
595             irq_domain,
596             virq,
597             hwirq,
598             plic_irq_chip(),
599             irq_domain.host_data(),
600             fast_eoi_irq_handler(),
601             None,
602             None,
603         );
604         let irq_desc = irq_desc_manager().lookup(virq).unwrap();
605         irq_desc.set_noprobe();
606         let mask = plic_chip_data.lmask().clone();
607         irq_manager().irq_set_affinity(&irq_desc.irq_data(), &irq_desc.inner(), &mask)?;
608         Ok(())
609     }
610 
611     fn activate(
612         &self,
613         _domain: &Arc<IrqDomain>,
614         _irq_data: &Arc<IrqData>,
615         _reserve: bool,
616     ) -> Result<(), SystemError> {
617         warn!("plic: activate");
618         loop {}
619     }
620 
621     fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {}
622 }
623 
624 /// 处理PLIC中断
625 pub(super) fn do_plic_irq(trap_frame: &mut TrapFrame) {
626     // debug!("plic: do_plic_irq");
627 
628     let handler = plic_handlers().get();
629     let priv_data = handler.priv_data();
630     if priv_data.is_none() {
631         return;
632     }
633 
634     let domain = priv_data.unwrap().irq_domain.upgrade();
635     if domain.is_none() {
636         return;
637     }
638 
639     let domain = domain.unwrap();
640 
641     // 循环处理中断
642     loop {
643         let claim = unsafe {
644             read_volatile(
645                 (handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *const u32,
646             )
647         };
648 
649         if claim == 0 {
650             break;
651         }
652         debug!("plic: claim: {claim:?}");
653 
654         let hwirq = HardwareIrqNumber::new(claim);
655         if let Err(e) = GenericIrqHandler::handle_domain_irq(domain.clone(), hwirq, trap_frame) {
656             warn!("plic: can't find mapping for hwirq {hwirq:?}, {e:?}");
657         }
658     }
659 }
660