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