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