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