123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- use alloc::{string::ToString, sync::Arc};
- use log::error;
- use system_error::SystemError;
- use crate::{
- arch::interrupt::TrapFrame,
- driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer},
- exception::{
- handle::PerCpuDevIdIrqHandler,
- irqchip::{IrqChip, IrqChipFlags},
- irqdata::IrqData,
- irqdesc::{irq_desc_manager, GenericIrqHandler},
- irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
- softirq::do_softirq,
- HardwareIrqNumber, IrqNumber,
- },
- libs::spinlock::{SpinLock, SpinLockGuard},
- sched::{SchedMode, __schedule},
- };
- use super::riscv_sifive_plic::do_plic_irq;
- static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
- static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
- #[inline(always)]
- pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
- unsafe { &RISCV_INTC_DOMAIN }
- }
- #[inline(always)]
- fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
- unsafe { RISCV_INTC_CHIP.as_ref() }
- }
- /// RISC-V INTC虚拟中断号的起始值(192映射物理的0)
- pub const RISCV_INTC_VIRQ_START: u32 = 192;
- #[derive(Debug)]
- struct RiscvIntcChip {
- inner: SpinLock<InnerIrqChip>,
- }
- impl IrqChip for RiscvIntcChip {
- fn name(&self) -> &'static str {
- "RISC-V INTC"
- }
- fn irq_disable(&self, _irq: &Arc<IrqData>) {}
- fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
- unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) };
- Ok(())
- }
- fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
- unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) };
- Ok(())
- }
- fn irq_ack(&self, _irq: &Arc<IrqData>) {}
- fn can_mask_ack(&self) -> bool {
- false
- }
- fn irq_eoi(&self, _irq: &Arc<IrqData>) {
- /*
- * The RISC-V INTC driver uses handle_percpu_devid_irq() flow
- * for the per-HART local interrupts and child irqchip drivers
- * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement
- * chained handlers for the per-HART local interrupts.
- *
- * In the absence of irq_eoi(), the chained_irq_enter() and
- * chained_irq_exit() functions (used by child irqchip drivers)
- * will do unnecessary mask/unmask of per-HART local interrupts
- * at the time of handling interrupts. To avoid this, we provide
- * an empty irq_eoi() callback for RISC-V INTC irqchip.
- */
- }
- fn can_set_affinity(&self) -> bool {
- false
- }
- fn can_set_flow_type(&self) -> bool {
- false
- }
- fn flags(&self) -> IrqChipFlags {
- self.inner().flags
- }
- }
- impl RiscvIntcChip {
- const IRQ_SIZE: u32 = 64;
- fn new() -> Self {
- Self {
- inner: SpinLock::new(InnerIrqChip {
- flags: IrqChipFlags::empty(),
- }),
- }
- }
- fn inner(&self) -> SpinLockGuard<InnerIrqChip> {
- self.inner.lock_irqsave()
- }
- }
- #[derive(Debug)]
- struct InnerIrqChip {
- flags: IrqChipFlags,
- }
- #[derive(Debug)]
- struct RiscvIntcDomainOps;
- impl IrqDomainOps for RiscvIntcDomainOps {
- fn map(
- &self,
- irq_domain: &Arc<IrqDomain>,
- hwirq: HardwareIrqNumber,
- virq: IrqNumber,
- ) -> Result<(), SystemError> {
- irq_desc_manager().set_percpu_devid_all(virq)?;
- irq_domain_manager().domain_set_info(
- irq_domain,
- virq,
- hwirq,
- riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>,
- irq_domain.host_data(),
- &PerCpuDevIdIrqHandler,
- None,
- None,
- );
- return Ok(());
- }
- fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
- todo!("riscv_intc_domain_ops::unmap");
- }
- }
- #[inline(never)]
- pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
- let intc_chip = Arc::new(RiscvIntcChip::new());
- unsafe {
- RISCV_INTC_CHIP = Some(intc_chip);
- }
- let intc_domain = irq_domain_manager()
- .create_and_add_linear(
- "riscv-intc".to_string(),
- &RiscvIntcDomainOps,
- RiscvIntcChip::IRQ_SIZE,
- )
- .ok_or_else(|| {
- error!("Failed to create riscv-intc domain");
- SystemError::ENXIO
- })?;
- irq_domain_manager().set_default_domain(intc_domain.clone());
- unsafe {
- RISCV_INTC_DOMAIN = Some(intc_domain.clone());
- }
- riscv_sbi_timer_irq_desc_init();
- return Ok(());
- }
- /// 把硬件中断号转换为riscv intc芯片的中断域的虚拟中断号
- pub const fn riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
- if hwirq.data() < RiscvIntcChip::IRQ_SIZE {
- Some(IrqNumber::new(hwirq.data() + RISCV_INTC_VIRQ_START))
- } else {
- None
- }
- }
- /// 把riscv intc芯片的的中断域的虚拟中断号转换为硬件中断号
- #[allow(dead_code)]
- pub const fn riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber> {
- if virq.data() >= RISCV_INTC_VIRQ_START
- && virq.data() < RISCV_INTC_VIRQ_START + RiscvIntcChip::IRQ_SIZE
- {
- Some(HardwareIrqNumber::new(virq.data() - RISCV_INTC_VIRQ_START))
- } else {
- None
- }
- }
- /// 将硬件中断号与riscv intc芯片的虚拟中断号关联
- pub fn riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
- let virq = riscv_intc_hwirq_to_virq(hwirq)?;
- irq_domain_manager()
- .domain_associate(
- riscv_intc_domain().as_ref().or_else(|| {
- error!("riscv_intc_domain is None");
- None
- })?,
- virq,
- hwirq,
- )
- .ok();
- Some(virq)
- }
- /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
- pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
- let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
- if hwirq.data() == 9 {
- // external interrupt
- do_plic_irq(trap_frame);
- } else {
- GenericIrqHandler::handle_domain_irq(
- riscv_intc_domain().clone().unwrap(),
- hwirq,
- trap_frame,
- )
- .ok();
- }
- do_softirq();
- if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
- __schedule(SchedMode::SM_PREEMPT);
- }
- }
|