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