1 use core::{any::Any, fmt::Debug}; 2 3 use alloc::sync::{Arc, Weak}; 4 5 use crate::libs::spinlock::SpinLock; 6 7 use super::{ 8 irqchip::{IrqChip, IrqChipData}, 9 irqdomain::IrqDomain, 10 msi::MsiDesc, 11 HardwareIrqNumber, IrqNumber, 12 }; 13 14 /// per irq chip data passed down to chip functions 15 /// 16 /// 该结构体用于表示每个Irq的私有数据,且与具体的中断芯片绑定 17 /// 18 /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#179 19 #[allow(dead_code)] 20 #[derive(Debug)] 21 pub struct IrqData { 22 /// 中断号, 用于表示软件逻辑视角的中断号,全局唯一 23 irq: IrqNumber, 24 /// 硬件中断号, 用于表示在某个IrqDomain中的中断号 25 hwirq: HardwareIrqNumber, 26 /// 涉及的所有irqchip之间共享的数据 27 common_data: Arc<IrqCommonData>, 28 /// 绑定到的中断芯片 29 chip: Arc<dyn IrqChip>, 30 /// 中断芯片的私有数据(与当前irq相关) 31 chip_data: Arc<dyn IrqChipData>, 32 /// 中断域 33 domain: Arc<IrqDomain>, 34 /// 中断的父中断(如果具有中断域继承的话) 35 parent_data: Option<Weak<IrqData>>, 36 } 37 38 /// per irq data shared by all irqchips 39 /// 40 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147 41 #[allow(dead_code)] 42 #[derive(Debug)] 43 pub struct IrqCommonData { 44 inner: SpinLock<InnerIrqCommonData>, 45 } 46 47 #[allow(dead_code)] 48 #[derive(Debug)] 49 struct InnerIrqCommonData { 50 /// status information for irq chip functions. 51 state: IrqStatus, 52 /// per-IRQ data for the irq_chip methods 53 handler_data: Option<Arc<dyn IrqHandlerData>>, 54 msi_desc: Option<Arc<MsiDesc>>, 55 // todo: affinity 56 } 57 58 pub trait IrqHandlerData: Send + Sync + Any + Debug {} 59 60 bitflags! { 61 /// 中断线状态 62 /// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h?fi=IRQ_TYPE_PROBE#77 63 pub struct IrqLineStatus: u32 { 64 /// 默认,未指明类型 65 const IRQ_TYPE_NONE = 0x00000000; 66 /// 上升沿触发 67 const IRQ_TYPE_EDGE_RISING = 0x00000001; 68 /// 下降沿触发 69 const IRQ_TYPE_EDGE_FALLING = 0x00000002; 70 /// 上升沿和下降沿触发 71 const IRQ_TYPE_EDGE_BOTH = Self::IRQ_TYPE_EDGE_RISING.bits | Self::IRQ_TYPE_EDGE_FALLING.bits; 72 /// 高电平触发 73 const IRQ_TYPE_LEVEL_HIGH = 0x00000004; 74 /// 低电平触发 75 const IRQ_TYPE_LEVEL_LOW = 0x00000008; 76 /// 过滤掉电平位的掩码 77 const IRQ_TYPE_LEVEL_MASK = Self::IRQ_TYPE_LEVEL_LOW.bits | Self::IRQ_TYPE_LEVEL_HIGH.bits; 78 /// 上述位掩码的掩码 79 const IRQ_TYPE_SENSE_MASK = 0x0000000f; 80 /// 某些PICs使用此类型要求 `IrqChip::irq_set_type()` 设置硬件到一个合理的默认值 81 /// (由irqdomain的map()回调使用,以便为新分配的描述符同步硬件状态和软件标志位)。 82 const IRQ_TYPE_DEFAULT = Self::IRQ_TYPE_SENSE_MASK.bits; 83 84 /// 特定于探测的过程中的特殊标志 85 const IRQ_TYPE_PROBE = 0x00000010; 86 87 /// 中断是电平类型。当上述触发位通过`IrqChip::irq_set_type()` 修改时,也会在代码中更新 88 const IRQ_LEVEL = 1 << 8; 89 /// 标记一个PER_CPU的中断。将保护其免受亲和性设置的影响 90 const IRQ_PER_CPU = 1 << 9; 91 /// 中断不能被自动探测 92 const IRQ_NOPROBE = 1 << 10; 93 /// 中断不能通过request_irq()请求 94 const IRQ_NOREQUEST = 1 << 11; 95 /// 中断在request/setup_irq()中不会自动启用 96 const IRQ_NOAUTOEN = 1 << 12; 97 /// 中断不能被平衡(亲和性设置) 98 const IRQ_NO_BALANCING = 1 << 13; 99 /// 中断可以从进程上下文中迁移 100 const IRQ_MOVE_PCNTXT = 1 << 14; 101 /// 中断嵌套在另一个线程中 102 const IRQ_NESTED_THREAD = 1 << 15; 103 /// 中断不能被线程化 104 const IRQ_NOTHREAD = 1 << 16; 105 /// Dev_id是一个per-CPU变量 106 const IRQ_PER_CPU_DEVID = 1 << 17; 107 /// 总是由另一个中断轮询。将其从错误的中断检测机制和核心侧轮询中排除 108 const IRQ_IS_POLLED = 1 << 18; 109 /// 禁用延迟的中断禁用 (Disable lazy irq disable) 110 const IRQ_DISABLE_UNLAZY = 1 << 19; 111 /// 在/proc/interrupts中不显示 112 const IRQ_HIDDEN = 1 << 20; 113 /// 从note_interrupt()调试中排除 114 const IRQ_NO_DEBUG = 1 << 21; 115 } 116 117 118 119 } 120 bitflags! { 121 /// 中断状态(存储在IrqCommonData) 122 /// 123 /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#227 124 pub struct IrqStatus: u32 { 125 /// 触发类型位的掩码 126 const IRQD_TRIGGER_MASK = 0xf; 127 /// 亲和性设置待处理 128 const IRQD_SETAFFINITY_PENDING = 1 << 8; 129 /// 中断已激活 130 const IRQD_ACTIVATED = 1 << 9; 131 /// 对此IRQ禁用平衡 132 const IRQD_NO_BALANCING = 1 << 10; 133 /// 中断是每个CPU特定的 134 const IRQD_PER_CPU = 1 << 11; 135 /// 中断亲和性已设置 136 const IRQD_AFFINITY_SET = 1 << 12; 137 /// 中断是电平触发 138 const IRQD_LEVEL = 1 << 13; 139 /// 中断配置为从挂起状态唤醒 140 const IRQD_WAKEUP_STATE = 1 << 14; 141 /// 中断可以在进程上下文中移动 142 const IRQD_MOVE_PCNTXT = 1 << 15; 143 /// 中断被禁用 144 const IRQD_IRQ_DISABLED = 1 << 16; 145 /// 中断被屏蔽 146 const IRQD_IRQ_MASKED = 1 << 17; 147 /// 中断正在处理中 148 const IRQD_IRQ_INPROGRESS = 1 << 18; 149 /// 唤醒模式已准备就绪 150 const IRQD_WAKEUP_ARMED = 1 << 19; 151 /// 中断被转发到一个虚拟CPU 152 const IRQD_FORWARDED_TO_VCPU = 1 << 20; 153 /// 亲和性由内核自动管理 154 const IRQD_AFFINITY_MANAGED = 1 << 21; 155 /// 中断已启动 156 const IRQD_IRQ_STARTED = 1 << 22; 157 /// 由于空亲和性掩码而关闭的中断。仅适用于亲和性管理的中断。 158 const IRQD_MANAGED_SHUTDOWN = 1 << 23; 159 /// IRQ只允许单个亲和性目标 160 const IRQD_SINGLE_TARGET = 1 << 24; 161 /// 预期的触发器已设置 162 const IRQD_DEFAULT_TRIGGER_SET = 1 << 25; 163 /// 可以使用保留模式 164 const IRQD_CAN_RESERVE = 1 << 26; 165 /// Non-maskable MSI quirk for affinity change required 166 const IRQD_MSI_NOMASK_QUIRK = 1 << 27; 167 /// 强制要求`handle_irq_()`只能在真实的中断上下文中调用 168 const IRQD_HANDLE_ENFORCE_IRQCTX = 1 << 28; 169 /// 激活时设置亲和性。在禁用时不要调用irq_chip::irq_set_affinity()。 170 const IRQD_AFFINITY_ON_ACTIVATE = 1 << 29; 171 /// 如果irqpm具有标志 IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,则在挂起时中断被启用。 172 const IRQD_IRQ_ENABLED_ON_SUSPEND = 1 << 30; 173 } 174 } 175 176 #[allow(dead_code)] 177 impl IrqStatus { 178 pub const fn is_set_affinity_pending(&self) -> bool { 179 self.contains(Self::IRQD_SETAFFINITY_PENDING) 180 } 181 182 pub const fn is_per_cpu(&self) -> bool { 183 self.contains(Self::IRQD_PER_CPU) 184 } 185 186 pub const fn can_balance(&self) -> bool { 187 !((self.bits & (Self::IRQD_PER_CPU.bits | Self::IRQD_NO_BALANCING.bits)) != 0) 188 } 189 190 pub const fn affinity_was_set(&self) -> bool { 191 self.contains(Self::IRQD_AFFINITY_SET) 192 } 193 194 pub fn mark_affinity_set(&mut self) { 195 self.insert(Self::IRQD_AFFINITY_SET); 196 } 197 198 pub const fn trigger_type_was_set(&self) -> bool { 199 self.contains(Self::IRQD_DEFAULT_TRIGGER_SET) 200 } 201 202 pub fn mark_trigger_type_set(&mut self) { 203 self.insert(Self::IRQD_DEFAULT_TRIGGER_SET); 204 } 205 206 pub const fn trigger_type(&self) -> IrqLineStatus { 207 IrqLineStatus::from_bits_truncate(self.bits & Self::IRQD_TRIGGER_MASK.bits) 208 } 209 210 /// Must only be called inside irq_chip.irq_set_type() functions or 211 /// from the DT/ACPI setup code. 212 pub const fn set_trigger_type(&mut self, trigger: IrqLineStatus) { 213 self.bits &= !Self::IRQD_TRIGGER_MASK.bits; 214 self.bits |= trigger.bits & Self::IRQD_TRIGGER_MASK.bits; 215 216 self.bits |= Self::IRQD_DEFAULT_TRIGGER_SET.bits; 217 } 218 219 pub const fn is_level_type(&self) -> bool { 220 self.contains(Self::IRQD_LEVEL) 221 } 222 223 /// Must only be called of irqchip.irq_set_affinity() or low level 224 /// hierarchy domain allocation functions. 225 pub fn set_single_target(&mut self) { 226 self.insert(Self::IRQD_SINGLE_TARGET); 227 } 228 229 pub const fn is_single_target(&self) -> bool { 230 self.contains(Self::IRQD_SINGLE_TARGET) 231 } 232 233 pub fn set_handle_enforce_irqctx(&mut self) { 234 self.insert(Self::IRQD_HANDLE_ENFORCE_IRQCTX); 235 } 236 237 pub const fn is_handle_enforce_irqctx(&self) -> bool { 238 self.contains(Self::IRQD_HANDLE_ENFORCE_IRQCTX) 239 } 240 241 pub const fn is_enabled_on_suspend(&self) -> bool { 242 self.contains(Self::IRQD_IRQ_ENABLED_ON_SUSPEND) 243 } 244 245 pub const fn is_wakeup_set(&self) -> bool { 246 self.contains(Self::IRQD_WAKEUP_STATE) 247 } 248 249 pub const fn can_move_in_process_context(&self) -> bool { 250 self.contains(Self::IRQD_MOVE_PCNTXT) 251 } 252 253 pub const fn is_irq_disabled(&self) -> bool { 254 self.contains(Self::IRQD_IRQ_DISABLED) 255 } 256 257 pub const fn is_irq_masked(&self) -> bool { 258 self.contains(Self::IRQD_IRQ_MASKED) 259 } 260 261 pub const fn is_irq_in_progress(&self) -> bool { 262 self.contains(Self::IRQD_IRQ_INPROGRESS) 263 } 264 265 pub const fn is_wakeup_armed(&self) -> bool { 266 self.contains(Self::IRQD_WAKEUP_ARMED) 267 } 268 269 pub const fn is_forwarded_to_vcpu(&self) -> bool { 270 self.contains(Self::IRQD_FORWARDED_TO_VCPU) 271 } 272 273 pub fn set_forwarded_to_vcpu(&mut self) { 274 self.insert(Self::IRQD_FORWARDED_TO_VCPU); 275 } 276 277 pub const fn is_affinity_managed(&self) -> bool { 278 self.contains(Self::IRQD_AFFINITY_MANAGED) 279 } 280 281 pub const fn is_activated(&self) -> bool { 282 self.contains(Self::IRQD_ACTIVATED) 283 } 284 285 pub fn set_activated(&mut self) { 286 self.insert(Self::IRQD_ACTIVATED); 287 } 288 289 pub fn clear_activated(&mut self) { 290 self.remove(Self::IRQD_ACTIVATED); 291 } 292 293 pub const fn is_started(&self) -> bool { 294 self.contains(Self::IRQD_IRQ_STARTED) 295 } 296 297 pub const fn is_managed_and_shutdown(&self) -> bool { 298 self.contains(Self::IRQD_MANAGED_SHUTDOWN) 299 } 300 301 pub fn set_can_reserve(&mut self) { 302 self.insert(Self::IRQD_CAN_RESERVE); 303 } 304 305 pub const fn can_reserve(&self) -> bool { 306 self.contains(Self::IRQD_CAN_RESERVE) 307 } 308 309 pub fn clear_can_reserve(&mut self) { 310 self.remove(Self::IRQD_CAN_RESERVE); 311 } 312 313 pub fn set_msi_nomask_quirk(&mut self) { 314 self.insert(Self::IRQD_MSI_NOMASK_QUIRK); 315 } 316 317 pub fn clear_msi_nomask_quirk(&mut self) { 318 self.remove(Self::IRQD_MSI_NOMASK_QUIRK); 319 } 320 321 pub const fn is_msi_nomask_quirk(&self) -> bool { 322 self.contains(Self::IRQD_MSI_NOMASK_QUIRK) 323 } 324 325 pub fn set_affinity_on_activate(&mut self) { 326 self.insert(Self::IRQD_AFFINITY_ON_ACTIVATE); 327 } 328 329 pub const fn is_affinity_on_activate(&self) -> bool { 330 self.contains(Self::IRQD_AFFINITY_ON_ACTIVATE) 331 } 332 } 333