riscv_intc.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. use alloc::{string::ToString, sync::Arc};
  2. use log::error;
  3. use system_error::SystemError;
  4. use crate::{
  5. arch::interrupt::TrapFrame,
  6. driver::clocksource::timer_riscv::{riscv_sbi_timer_irq_desc_init, RiscVSbiTimer},
  7. exception::{
  8. handle::PerCpuDevIdIrqHandler,
  9. irqchip::{IrqChip, IrqChipFlags},
  10. irqdata::IrqData,
  11. irqdesc::{irq_desc_manager, GenericIrqHandler},
  12. irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
  13. softirq::do_softirq,
  14. HardwareIrqNumber, IrqNumber,
  15. },
  16. libs::spinlock::{SpinLock, SpinLockGuard},
  17. sched::{SchedMode, __schedule},
  18. };
  19. use super::riscv_sifive_plic::do_plic_irq;
  20. static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
  21. static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
  22. #[inline(always)]
  23. pub fn riscv_intc_domain() -> &'static Option<Arc<IrqDomain>> {
  24. unsafe { &RISCV_INTC_DOMAIN }
  25. }
  26. #[inline(always)]
  27. fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
  28. unsafe { RISCV_INTC_CHIP.as_ref() }
  29. }
  30. /// RISC-V INTC虚拟中断号的起始值(192映射物理的0)
  31. pub const RISCV_INTC_VIRQ_START: u32 = 192;
  32. #[derive(Debug)]
  33. struct RiscvIntcChip {
  34. inner: SpinLock<InnerIrqChip>,
  35. }
  36. impl IrqChip for RiscvIntcChip {
  37. fn name(&self) -> &'static str {
  38. "RISC-V INTC"
  39. }
  40. fn irq_disable(&self, _irq: &Arc<IrqData>) {}
  41. fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
  42. unsafe { riscv::register::sie::clear_bits(1 << irq.hardware_irq().data()) };
  43. Ok(())
  44. }
  45. fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
  46. unsafe { riscv::register::sie::set_bits(1 << irq.hardware_irq().data()) };
  47. Ok(())
  48. }
  49. fn irq_ack(&self, _irq: &Arc<IrqData>) {}
  50. fn can_mask_ack(&self) -> bool {
  51. false
  52. }
  53. fn irq_eoi(&self, _irq: &Arc<IrqData>) {
  54. /*
  55. * The RISC-V INTC driver uses handle_percpu_devid_irq() flow
  56. * for the per-HART local interrupts and child irqchip drivers
  57. * (such as PLIC, SBI IPI, CLINT, APLIC, IMSIC, etc) implement
  58. * chained handlers for the per-HART local interrupts.
  59. *
  60. * In the absence of irq_eoi(), the chained_irq_enter() and
  61. * chained_irq_exit() functions (used by child irqchip drivers)
  62. * will do unnecessary mask/unmask of per-HART local interrupts
  63. * at the time of handling interrupts. To avoid this, we provide
  64. * an empty irq_eoi() callback for RISC-V INTC irqchip.
  65. */
  66. }
  67. fn can_set_affinity(&self) -> bool {
  68. false
  69. }
  70. fn can_set_flow_type(&self) -> bool {
  71. false
  72. }
  73. fn flags(&self) -> IrqChipFlags {
  74. self.inner().flags
  75. }
  76. }
  77. impl RiscvIntcChip {
  78. const IRQ_SIZE: u32 = 64;
  79. fn new() -> Self {
  80. Self {
  81. inner: SpinLock::new(InnerIrqChip {
  82. flags: IrqChipFlags::empty(),
  83. }),
  84. }
  85. }
  86. fn inner(&self) -> SpinLockGuard<InnerIrqChip> {
  87. self.inner.lock_irqsave()
  88. }
  89. }
  90. #[derive(Debug)]
  91. struct InnerIrqChip {
  92. flags: IrqChipFlags,
  93. }
  94. #[derive(Debug)]
  95. struct RiscvIntcDomainOps;
  96. impl IrqDomainOps for RiscvIntcDomainOps {
  97. fn map(
  98. &self,
  99. irq_domain: &Arc<IrqDomain>,
  100. hwirq: HardwareIrqNumber,
  101. virq: IrqNumber,
  102. ) -> Result<(), SystemError> {
  103. irq_desc_manager().set_percpu_devid_all(virq)?;
  104. irq_domain_manager().domain_set_info(
  105. irq_domain,
  106. virq,
  107. hwirq,
  108. riscv_intc_chip().unwrap().clone() as Arc<dyn IrqChip>,
  109. irq_domain.host_data(),
  110. &PerCpuDevIdIrqHandler,
  111. None,
  112. None,
  113. );
  114. return Ok(());
  115. }
  116. fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
  117. todo!("riscv_intc_domain_ops::unmap");
  118. }
  119. }
  120. #[inline(never)]
  121. pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
  122. let intc_chip = Arc::new(RiscvIntcChip::new());
  123. unsafe {
  124. RISCV_INTC_CHIP = Some(intc_chip);
  125. }
  126. let intc_domain = irq_domain_manager()
  127. .create_and_add_linear(
  128. "riscv-intc".to_string(),
  129. &RiscvIntcDomainOps,
  130. RiscvIntcChip::IRQ_SIZE,
  131. )
  132. .ok_or_else(|| {
  133. error!("Failed to create riscv-intc domain");
  134. SystemError::ENXIO
  135. })?;
  136. irq_domain_manager().set_default_domain(intc_domain.clone());
  137. unsafe {
  138. RISCV_INTC_DOMAIN = Some(intc_domain.clone());
  139. }
  140. riscv_sbi_timer_irq_desc_init();
  141. return Ok(());
  142. }
  143. /// 把硬件中断号转换为riscv intc芯片的中断域的虚拟中断号
  144. pub const fn riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
  145. if hwirq.data() < RiscvIntcChip::IRQ_SIZE {
  146. Some(IrqNumber::new(hwirq.data() + RISCV_INTC_VIRQ_START))
  147. } else {
  148. None
  149. }
  150. }
  151. /// 把riscv intc芯片的的中断域的虚拟中断号转换为硬件中断号
  152. #[allow(dead_code)]
  153. pub const fn riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber> {
  154. if virq.data() >= RISCV_INTC_VIRQ_START
  155. && virq.data() < RISCV_INTC_VIRQ_START + RiscvIntcChip::IRQ_SIZE
  156. {
  157. Some(HardwareIrqNumber::new(virq.data() - RISCV_INTC_VIRQ_START))
  158. } else {
  159. None
  160. }
  161. }
  162. /// 将硬件中断号与riscv intc芯片的虚拟中断号关联
  163. pub fn riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
  164. let virq = riscv_intc_hwirq_to_virq(hwirq)?;
  165. irq_domain_manager()
  166. .domain_associate(
  167. riscv_intc_domain().as_ref().or_else(|| {
  168. error!("riscv_intc_domain is None");
  169. None
  170. })?,
  171. virq,
  172. hwirq,
  173. )
  174. .ok();
  175. Some(virq)
  176. }
  177. /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
  178. pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
  179. let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
  180. if hwirq.data() == 9 {
  181. // external interrupt
  182. do_plic_irq(trap_frame);
  183. } else {
  184. GenericIrqHandler::handle_domain_irq(
  185. riscv_intc_domain().clone().unwrap(),
  186. hwirq,
  187. trap_frame,
  188. )
  189. .ok();
  190. }
  191. do_softirq();
  192. if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
  193. __schedule(SchedMode::SM_PREEMPT);
  194. }
  195. }