1*ce5850adSLoGin use core::{any::Any, fmt::Debug}; 2*ce5850adSLoGin 3*ce5850adSLoGin use alloc::{ 4*ce5850adSLoGin sync::{Arc, Weak}, 5*ce5850adSLoGin vec::Vec, 6*ce5850adSLoGin }; 7*ce5850adSLoGin use system_error::SystemError; 8*ce5850adSLoGin 9*ce5850adSLoGin use crate::{libs::spinlock::SpinLock, mm::VirtAddr}; 10*ce5850adSLoGin 11*ce5850adSLoGin use super::{ 12*ce5850adSLoGin irqdata::{IrqData, IrqLineStatus}, 13*ce5850adSLoGin irqdomain::IrqDomain, 14*ce5850adSLoGin msi::MsiMsg, 15*ce5850adSLoGin }; 16*ce5850adSLoGin 17*ce5850adSLoGin /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#506 18*ce5850adSLoGin pub trait IrqChip: Sync + Send + Any + Debug { 19*ce5850adSLoGin fn name(&self) -> &'static str; 20*ce5850adSLoGin /// start up the interrupt (defaults to ->enable if ENOSYS) 21*ce5850adSLoGin fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> { 22*ce5850adSLoGin Err(SystemError::ENOSYS) 23*ce5850adSLoGin } 24*ce5850adSLoGin 25*ce5850adSLoGin /// shut down the interrupt (defaults to ->disable if ENOSYS) 26*ce5850adSLoGin fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> { 27*ce5850adSLoGin Err(SystemError::ENOSYS) 28*ce5850adSLoGin } 29*ce5850adSLoGin 30*ce5850adSLoGin /// enable the interrupt 31*ce5850adSLoGin /// 32*ce5850adSLoGin /// (defaults to ->unmask if ENOSYS) 33*ce5850adSLoGin fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> { 34*ce5850adSLoGin Err(SystemError::ENOSYS) 35*ce5850adSLoGin } 36*ce5850adSLoGin 37*ce5850adSLoGin /// disable the interrupt 38*ce5850adSLoGin fn irq_disable(&self, irq: &Arc<IrqData>); 39*ce5850adSLoGin 40*ce5850adSLoGin /// start of a new interrupt 41*ce5850adSLoGin fn irq_ack(&self, irq: &Arc<IrqData>); 42*ce5850adSLoGin 43*ce5850adSLoGin /// mask an interrupt source 44*ce5850adSLoGin fn irq_mask(&self, irq: &Arc<IrqData>); 45*ce5850adSLoGin /// ack and mask an interrupt source 46*ce5850adSLoGin fn irq_mask_ack(&self, irq: &Arc<IrqData>); 47*ce5850adSLoGin /// unmask an interrupt source 48*ce5850adSLoGin fn irq_unmask(&self, irq: &Arc<IrqData>); 49*ce5850adSLoGin /// end of interrupt 50*ce5850adSLoGin fn irq_eoi(&self, irq: &Arc<IrqData>); 51*ce5850adSLoGin 52*ce5850adSLoGin // todo: set affinity 53*ce5850adSLoGin 54*ce5850adSLoGin /// retrigger an IRQ to the CPU 55*ce5850adSLoGin fn retrigger(&self, irq: &Arc<IrqData>); 56*ce5850adSLoGin 57*ce5850adSLoGin /// set the flow type of an interrupt 58*ce5850adSLoGin /// 59*ce5850adSLoGin /// flow_type: the flow type to set 60*ce5850adSLoGin /// 61*ce5850adSLoGin fn irq_set_type( 62*ce5850adSLoGin &self, 63*ce5850adSLoGin _irq: &Arc<IrqData>, 64*ce5850adSLoGin _flow_type: IrqLineStatus, 65*ce5850adSLoGin ) -> Result<(), SystemError> { 66*ce5850adSLoGin Err(SystemError::ENOSYS) 67*ce5850adSLoGin } 68*ce5850adSLoGin 69*ce5850adSLoGin /// enable/disable power management wake-on of an interrupt 70*ce5850adSLoGin fn irq_set_wake(&self, _irq: &Arc<IrqData>, _on: bool) -> Result<(), SystemError> { 71*ce5850adSLoGin Err(SystemError::ENOSYS) 72*ce5850adSLoGin } 73*ce5850adSLoGin 74*ce5850adSLoGin /// function to lock access to slow bus (i2c) chips 75*ce5850adSLoGin fn irq_bus_lock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> { 76*ce5850adSLoGin Ok(()) 77*ce5850adSLoGin } 78*ce5850adSLoGin 79*ce5850adSLoGin /// function to sync and unlock slow bus (i2c) chips 80*ce5850adSLoGin fn irq_bus_sync_unlock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> { 81*ce5850adSLoGin Ok(()) 82*ce5850adSLoGin } 83*ce5850adSLoGin 84*ce5850adSLoGin /// function called from core code on suspend once per 85*ce5850adSLoGin /// chip, when one or more interrupts are installed 86*ce5850adSLoGin fn irq_suspend(&self, irq: &Arc<IrqData>); 87*ce5850adSLoGin 88*ce5850adSLoGin /// function called from core code on resume once per chip, 89*ce5850adSLoGin /// when one ore more interrupts are installed 90*ce5850adSLoGin fn irq_resume(&self, irq: &Arc<IrqData>); 91*ce5850adSLoGin 92*ce5850adSLoGin /// function called from core code on shutdown once per chip 93*ce5850adSLoGin fn irq_pm_shutdown(&self, irq: &Arc<IrqData>); 94*ce5850adSLoGin 95*ce5850adSLoGin /// Optional function to set irq_data.mask for special cases 96*ce5850adSLoGin fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {} 97*ce5850adSLoGin 98*ce5850adSLoGin // todo: print chip 99*ce5850adSLoGin 100*ce5850adSLoGin /// optional to request resources before calling 101*ce5850adSLoGin /// any other callback related to this irq 102*ce5850adSLoGin fn irq_request_resources(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> { 103*ce5850adSLoGin Ok(()) 104*ce5850adSLoGin } 105*ce5850adSLoGin 106*ce5850adSLoGin /// optional to release resources acquired with 107*ce5850adSLoGin /// irq_request_resources 108*ce5850adSLoGin fn irq_release_resources(&self, _irq: &Arc<IrqData>) {} 109*ce5850adSLoGin 110*ce5850adSLoGin /// optional to compose message content for MSI 111*ce5850adSLoGin fn irq_compose_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &mut MsiMsg) {} 112*ce5850adSLoGin 113*ce5850adSLoGin /// optional to write message content for MSI 114*ce5850adSLoGin fn irq_write_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &MsiMsg) {} 115*ce5850adSLoGin 116*ce5850adSLoGin /// return the internal state of an interrupt 117*ce5850adSLoGin fn irqchip_state( 118*ce5850adSLoGin &self, 119*ce5850adSLoGin _irq: &Arc<IrqData>, 120*ce5850adSLoGin _which: IrqChipState, 121*ce5850adSLoGin ) -> Result<bool, SystemError> { 122*ce5850adSLoGin Err(SystemError::ENOSYS) 123*ce5850adSLoGin } 124*ce5850adSLoGin 125*ce5850adSLoGin /// set the internal state of an interrupt 126*ce5850adSLoGin fn set_irqchip_state( 127*ce5850adSLoGin &self, 128*ce5850adSLoGin _irq: &Arc<IrqData>, 129*ce5850adSLoGin _which: IrqChipState, 130*ce5850adSLoGin _state: bool, 131*ce5850adSLoGin ) -> Result<(), SystemError> { 132*ce5850adSLoGin Err(SystemError::ENOSYS) 133*ce5850adSLoGin } 134*ce5850adSLoGin 135*ce5850adSLoGin // todo: set vcpu affinity 136*ce5850adSLoGin 137*ce5850adSLoGin /// send a single IPI to destination cpus 138*ce5850adSLoGin fn send_single_ipi(&self, irq: &Arc<IrqData>, cpu: u32); 139*ce5850adSLoGin 140*ce5850adSLoGin // todo: send ipi with cpu mask 141*ce5850adSLoGin 142*ce5850adSLoGin /// function called from core code before enabling an NMI 143*ce5850adSLoGin fn irq_nmi_setup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> { 144*ce5850adSLoGin Err(SystemError::ENOSYS) 145*ce5850adSLoGin } 146*ce5850adSLoGin 147*ce5850adSLoGin /// function called from core code after disabling an NMI 148*ce5850adSLoGin fn irq_nmi_teardown(&self, irq: &Arc<IrqData>); 149*ce5850adSLoGin } 150*ce5850adSLoGin 151*ce5850adSLoGin #[allow(dead_code)] 152*ce5850adSLoGin #[derive(Debug, Clone, Copy)] 153*ce5850adSLoGin pub enum IrqChipState { 154*ce5850adSLoGin /// Is the interrupt pending? 155*ce5850adSLoGin Pending, 156*ce5850adSLoGin /// Is the interrupt in progress? 157*ce5850adSLoGin Active, 158*ce5850adSLoGin /// Is the interrupt masked? 159*ce5850adSLoGin Masked, 160*ce5850adSLoGin /// Is Irq line high? 161*ce5850adSLoGin LineLevel, 162*ce5850adSLoGin } 163*ce5850adSLoGin 164*ce5850adSLoGin pub trait IrqChipData: Sync + Send + Any + Debug {} 165*ce5850adSLoGin 166*ce5850adSLoGin bitflags! { 167*ce5850adSLoGin /// 定义 IrqGcFlags 位标志 168*ce5850adSLoGin pub struct IrqGcFlags: u32 { 169*ce5850adSLoGin /// 通过读取mask reg来初始化mask_cache 170*ce5850adSLoGin const IRQ_GC_INIT_MASK_CACHE = 1 << 0; 171*ce5850adSLoGin /// 对于需要在父irq上调用irq_set_wake()的irq芯片, 将irqs的锁类设置为嵌套。Usually GPIO implementations 172*ce5850adSLoGin const IRQ_GC_INIT_NESTED_LOCK = 1 << 1; 173*ce5850adSLoGin /// Mask cache是芯片类型私有的 174*ce5850adSLoGin const IRQ_GC_MASK_CACHE_PER_TYPE = 1 << 2; 175*ce5850adSLoGin /// 不计算irqData->mask 176*ce5850adSLoGin const IRQ_GC_NO_MASK = 1 << 3; 177*ce5850adSLoGin /// 使用大端字节序的寄存器访问(默认:小端LE) 178*ce5850adSLoGin const IRQ_GC_BE_IO = 1 << 4; 179*ce5850adSLoGin } 180*ce5850adSLoGin } 181*ce5850adSLoGin 182*ce5850adSLoGin #[allow(dead_code)] 183*ce5850adSLoGin #[derive(Debug)] 184*ce5850adSLoGin pub struct IrqChipGeneric { 185*ce5850adSLoGin inner: SpinLock<InnerIrqChipGeneric>, 186*ce5850adSLoGin } 187*ce5850adSLoGin 188*ce5850adSLoGin #[allow(dead_code)] 189*ce5850adSLoGin #[derive(Debug)] 190*ce5850adSLoGin struct InnerIrqChipGeneric { 191*ce5850adSLoGin /// Register base address 192*ce5850adSLoGin reg_base: VirtAddr, 193*ce5850adSLoGin ops: &'static dyn IrqChipGenericOps, 194*ce5850adSLoGin /// Interrupt base num for this chip 195*ce5850adSLoGin irq_base: u32, 196*ce5850adSLoGin /// Number of interrupts handled by this chip 197*ce5850adSLoGin irq_cnt: u32, 198*ce5850adSLoGin /// Cached mask register shared between all chip types 199*ce5850adSLoGin mask_cache: u32, 200*ce5850adSLoGin /// Cached type register 201*ce5850adSLoGin type_cache: u32, 202*ce5850adSLoGin /// Cached polarity register 203*ce5850adSLoGin polarity_cache: u32, 204*ce5850adSLoGin /// Interrupt can wakeup from suspend 205*ce5850adSLoGin wake_enabled: bool, 206*ce5850adSLoGin /// Interrupt is marked as an wakeup from suspend source 207*ce5850adSLoGin wake_active: bool, 208*ce5850adSLoGin /// Number of available irq_chip_type instances (usually 1) 209*ce5850adSLoGin num_chip_type: u32, 210*ce5850adSLoGin private_data: Option<Arc<dyn IrqChipGenericPrivateData>>, 211*ce5850adSLoGin installed: u64, 212*ce5850adSLoGin unused: u64, 213*ce5850adSLoGin domain: Weak<IrqDomain>, 214*ce5850adSLoGin chip_types: Vec<IrqChipType>, 215*ce5850adSLoGin } 216*ce5850adSLoGin 217*ce5850adSLoGin pub trait IrqChipGenericOps: Debug { 218*ce5850adSLoGin /// Alternate I/O accessor (defaults to readl if NULL) 219*ce5850adSLoGin unsafe fn reg_readl(&self, addr: VirtAddr) -> u32; 220*ce5850adSLoGin 221*ce5850adSLoGin /// Alternate I/O accessor (defaults to writel if NULL) 222*ce5850adSLoGin unsafe fn reg_writel(&self, addr: VirtAddr, val: u32); 223*ce5850adSLoGin 224*ce5850adSLoGin /// Function called from core code on suspend once per 225*ce5850adSLoGin /// chip; can be useful instead of irq_chip::suspend to 226*ce5850adSLoGin /// handle chip details even when no interrupts are in use 227*ce5850adSLoGin fn suspend(&self, gc: &Arc<IrqChipGeneric>); 228*ce5850adSLoGin /// Function called from core code on resume once per chip; 229*ce5850adSLoGin /// can be useful instead of irq_chip::resume to handle chip 230*ce5850adSLoGin /// details even when no interrupts are in use 231*ce5850adSLoGin fn resume(&self, gc: &Arc<IrqChipGeneric>); 232*ce5850adSLoGin } 233*ce5850adSLoGin 234*ce5850adSLoGin pub trait IrqChipGenericPrivateData: Sync + Send + Any + Debug {} 235*ce5850adSLoGin 236*ce5850adSLoGin #[derive(Debug)] 237*ce5850adSLoGin pub struct IrqChipType { 238*ce5850adSLoGin // todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024 239*ce5850adSLoGin } 240