use core::{ any::Any, fmt::Debug, sync::atomic::{AtomicI64, Ordering}, }; use alloc::{ collections::{btree_map, BTreeMap}, string::{String, ToString}, sync::{Arc, Weak}, vec::Vec, }; use system_error::SystemError; use crate::{ arch::{interrupt::TrapFrame, CurrentIrqArch}, driver::base::{ device::DeviceId, kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, kset::KSet, }, filesystem::kernfs::KernFSInode, libs::{ cpumask::CpuMask, mutex::{Mutex, MutexGuard}, rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, spinlock::{SpinLock, SpinLockGuard}, }, mm::percpu::PerCpuVar, process::ProcessControlBlock, sched::completion::Completion, smp::cpu::smp_cpu_manager, }; use super::{ dummychip::no_irq_chip, handle::bad_irq_handler, irqchip::IrqChip, irqdata::{IrqCommonData, IrqData, IrqHandlerData, IrqLineStatus, IrqStatus}, irqdomain::{irq_domain_manager, IrqDomain}, sysfs::{irq_sysfs_del, IrqKObjType}, HardwareIrqNumber, InterruptArch, IrqNumber, }; /// 中断流处理程序 pub trait IrqFlowHandler: Debug + Send + Sync + Any { fn handle(&self, irq_desc: &Arc, trap_frame: &mut TrapFrame); } /// 中断处理程序 pub trait IrqHandler: Debug + Send + Sync + Any { fn handle( &self, irq: IrqNumber, static_data: Option<&dyn IrqHandlerData>, dynamic_data: Option>, ) -> Result; } /// 中断处理函数返回值 /// /// 用于指示中断处理函数是否处理了中断 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum IrqReturn { /// 中断未被处理 NotHandled, /// 中断已被处理 Handled, /// 中断已被处理,并且需要唤醒中断线程 WakeThread, } /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdesc.h#55 #[derive(Debug)] pub struct IrqDesc { inner: SpinLock, handler: RwLock>, /// 一个用于串行化 request_irq()和free_irq() 的互斥锁 request_mutex: Mutex<()>, kobj_state: LockedKObjectState, /// 当前描述符内正在运行的中断线程数 threads_active: AtomicI64, } impl IrqDesc { #[inline(never)] pub fn new(irq: IrqNumber, name: Option, irqd_flags: IrqStatus) -> Arc { // 初始化的过程参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdesc.c#392 let common_data = Arc::new(IrqCommonData::new()); let irq_data = Arc::new(IrqData::new( irq, HardwareIrqNumber::new(irq.data()), common_data.clone(), no_irq_chip(), )); irq_data.irqd_set(IrqStatus::IRQD_IRQ_DISABLED); common_data.insert_status(IrqStatus::IRQD_IRQ_MASKED); let irq_desc = IrqDesc { inner: SpinLock::new(InnerIrqDesc { percpu_affinity: None, percpu_enabled: None, common_data, irq_data, desc_internal_state: IrqDescState::empty(), line_status: IrqLineStatus::empty(), actions: Vec::new(), name, parent_irq: None, depth: 1, wake_depth: 0, kern_inode: None, kset: None, parent_kobj: None, threads_oneshot: 0, }), request_mutex: Mutex::new(()), handler: RwLock::new(None), kobj_state: LockedKObjectState::new(Some(KObjectState::INITIALIZED)), threads_active: AtomicI64::new(0), }; let irq_desc = Arc::new(irq_desc); irq_desc.irq_data().set_irq_desc(Arc::downgrade(&irq_desc)); irq_desc.set_handler(bad_irq_handler()); irq_desc.inner().irq_data.irqd_set(irqd_flags); return irq_desc; } /// 返回当前活跃的中断线程数量 #[allow(dead_code)] pub fn threads_active(&self) -> i64 { self.threads_active.load(Ordering::SeqCst) } /// 增加当前活跃的中断线程数量, 返回增加前的值 pub fn inc_threads_active(&self) -> i64 { self.threads_active.fetch_add(1, Ordering::SeqCst) } /// 减少当前活跃的中断线程数量, 返回减少前的值 #[allow(dead_code)] pub fn dec_threads_active(&self) -> i64 { self.threads_active.fetch_sub(1, Ordering::SeqCst) } pub fn set_handler(&self, handler: &'static dyn IrqFlowHandler) { self.chip_bus_lock(); let mut guard = self.handler.write_irqsave(); *guard = Some(handler); self.chip_bus_sync_unlock(); } /// 设置中断处理程序(不对desc->inner) /// /// /// ## Safety /// /// 需要保证irq_data和chip是当前irqdesc的 pub fn set_handler_no_lock_inner( &self, handler: &'static dyn IrqFlowHandler, irq_data: &Arc, chip: &Arc, ) { chip.irq_bus_lock(irq_data).ok(); let mut guard = self.handler.write_irqsave(); *guard = Some(handler); chip.irq_bus_sync_unlock(irq_data).ok(); } pub fn handler(&self) -> Option<&'static dyn IrqFlowHandler> { let guard = self.handler.read_irqsave(); *guard } pub fn inner(&self) -> SpinLockGuard { self.inner.lock_irqsave() } pub fn actions(&self) -> Vec> { self.inner().actions.clone() } /// 对中断请求过程加锁 pub fn request_mutex_lock(&self) -> MutexGuard<()> { self.request_mutex.lock() } pub fn irq(&self) -> IrqNumber { self.inner().irq_data.irq() } pub fn hardware_irq(&self) -> HardwareIrqNumber { self.inner().irq_data.hardware_irq() } pub fn irq_data(&self) -> Arc { self.inner().irq_data.clone() } /// 标记当前irq描述符已经被添加到sysfs pub fn mark_in_sysfs(&self) { self.inner() .desc_internal_state .insert(IrqDescState::IRQS_SYSFS); } pub fn mark_not_in_sysfs(&self) { self.inner() .desc_internal_state .remove(IrqDescState::IRQS_SYSFS); } /// 判断当前描述符是否已经添加到了sysfs pub fn in_sysfs(&self) -> bool { self.inner() .desc_internal_state .contains(IrqDescState::IRQS_SYSFS) } pub fn name(&self) -> Option { self.inner().name.clone() } pub fn can_request(&self) -> bool { self.inner().can_request() } #[allow(dead_code)] pub fn set_norequest(&self) { self.inner().set_norequest(); } #[allow(dead_code)] pub fn clear_norequest(&self) { self.inner().clear_norequest(); } pub fn nested_thread(&self) -> bool { self.inner().nested_thread() } /// 中断是否可以线程化 pub fn can_thread(&self) -> bool { !self .inner() .line_status .contains(IrqLineStatus::IRQ_NOTHREAD) } pub fn chip_bus_lock(&self) { let irq_data = self.inner().irq_data.clone(); irq_data .chip_info_read_irqsave() .chip() .irq_bus_lock(&irq_data) .ok(); } /// 同步释放低速总线锁 /// /// ## 锁 /// /// 进入此函数时,必须持有低速总线锁,并且desc的inner锁和irqdata的inner锁 /// 必须已经释放。否则将死锁。 pub fn chip_bus_sync_unlock(&self) { let irq_data = self.inner().irq_data.clone(); irq_data .chip_info_write_irqsave() .chip() .irq_bus_sync_unlock(&irq_data) .ok(); } pub fn set_percpu_devid_flags(&self) { self.modify_status( IrqLineStatus::empty(), IrqLineStatus::IRQ_NOAUTOEN | IrqLineStatus::IRQ_PER_CPU | IrqLineStatus::IRQ_NOTHREAD | IrqLineStatus::IRQ_NOPROBE | IrqLineStatus::IRQ_PER_CPU_DEVID, ); } #[allow(dead_code)] pub fn set_probe(&self) { self.modify_status(IrqLineStatus::IRQ_NOPROBE, IrqLineStatus::empty()); } #[allow(dead_code)] pub fn set_noprobe(&self) { self.modify_status(IrqLineStatus::empty(), IrqLineStatus::IRQ_NOPROBE); } pub fn modify_status(&self, clear: IrqLineStatus, set: IrqLineStatus) { let mut desc_guard = self.inner(); desc_guard.line_status.remove(clear); desc_guard.line_status.insert(set); let mut trigger = desc_guard.common_data().trigger_type(); desc_guard.common_data().clear_status( IrqStatus::IRQD_NO_BALANCING | IrqStatus::IRQD_PER_CPU | IrqStatus::IRQD_TRIGGER_MASK | IrqStatus::IRQD_LEVEL | IrqStatus::IRQD_MOVE_PCNTXT, ); if desc_guard .line_status .contains(IrqLineStatus::IRQ_NO_BALANCING) { desc_guard .common_data() .insert_status(IrqStatus::IRQD_NO_BALANCING); } if desc_guard.line_status.contains(IrqLineStatus::IRQ_PER_CPU) { desc_guard .common_data() .insert_status(IrqStatus::IRQD_PER_CPU); } if desc_guard .line_status .contains(IrqLineStatus::IRQ_MOVE_PCNTXT) { desc_guard .common_data() .insert_status(IrqStatus::IRQD_MOVE_PCNTXT); } if desc_guard.line_status.is_level_type() { desc_guard .common_data() .insert_status(IrqStatus::IRQD_LEVEL); } let tmp = desc_guard.line_status.trigger_type(); if tmp != IrqLineStatus::IRQ_TYPE_NONE { trigger = tmp; } desc_guard.common_data().set_trigger_type(trigger); } } #[allow(dead_code)] #[derive(Debug)] pub struct InnerIrqDesc { /// per irq and chip data passed down to chip functions common_data: Arc, irq_data: Arc, actions: Vec>, name: Option, parent_irq: Option, /// nested irq disables depth: u32, /// nested wake enables wake_depth: u32, desc_internal_state: IrqDescState, /// 中断线的状态 line_status: IrqLineStatus, kern_inode: Option>, kset: Option>, parent_kobj: Option>, /// per-cpu enabled mask percpu_enabled: Option, /// per-cpu affinity percpu_affinity: Option, // wait_for_threads: EventWaitQueue /// bitfield to handle shared oneshot threads threads_oneshot: u64, } impl InnerIrqDesc { pub fn name(&self) -> Option<&String> { self.name.as_ref() } #[allow(dead_code)] pub fn set_name(&mut self, name: Option) { self.name = name; } pub fn can_request(&self) -> bool { !self.line_status.contains(IrqLineStatus::IRQ_NOREQUEST) } #[allow(dead_code)] pub fn set_norequest(&mut self) { self.line_status.insert(IrqLineStatus::IRQ_NOREQUEST); } #[allow(dead_code)] pub fn clear_norequest(&mut self) { self.line_status.remove(IrqLineStatus::IRQ_NOREQUEST); } #[allow(dead_code)] pub fn set_noprobe(&mut self) { self.line_status.insert(IrqLineStatus::IRQ_NOPROBE); } #[allow(dead_code)] pub fn clear_noprobe(&mut self) { self.line_status.remove(IrqLineStatus::IRQ_NOPROBE); } pub fn set_nothread(&mut self) { self.line_status.insert(IrqLineStatus::IRQ_NOTHREAD); } #[allow(dead_code)] pub fn clear_nothread(&mut self) { self.line_status.remove(IrqLineStatus::IRQ_NOTHREAD); } pub fn nested_thread(&self) -> bool { self.line_status.contains(IrqLineStatus::IRQ_NESTED_THREAD) } pub fn line_status_set_per_cpu(&mut self) { self.line_status.insert(IrqLineStatus::IRQ_PER_CPU); } #[allow(dead_code)] pub fn line_status_clear_per_cpu(&mut self) { self.line_status.remove(IrqLineStatus::IRQ_PER_CPU); } #[allow(dead_code)] pub fn line_status(&self) -> &IrqLineStatus { &self.line_status } pub fn line_status_set_no_debug(&mut self) { self.line_status.insert(IrqLineStatus::IRQ_NO_BALANCING); } #[allow(dead_code)] pub fn line_status_clear_no_debug(&mut self) { self.line_status.remove(IrqLineStatus::IRQ_NO_BALANCING); } pub fn can_autoenable(&self) -> bool { !self.line_status.contains(IrqLineStatus::IRQ_NOAUTOEN) } #[allow(dead_code)] pub fn can_thread(&self) -> bool { !self.line_status.contains(IrqLineStatus::IRQ_NOTHREAD) } pub fn threads_oneshot(&self) -> u64 { self.threads_oneshot } /// 中断是否可以设置CPU亲和性 pub fn can_set_affinity(&self) -> bool { if !self.common_data.status().can_balance() || !self .irq_data() .chip_info_read_irqsave() .chip() .can_set_affinity() { return false; } return true; } pub fn actions(&self) -> &Vec> { &self.actions } pub fn add_action(&mut self, action: Arc) { self.actions.push(action); } pub fn clear_actions(&mut self) { self.actions.clear(); } #[allow(dead_code)] pub fn remove_action(&mut self, action: &Arc) { self.actions.retain(|a| !Arc::ptr_eq(a, action)); } pub fn internal_state(&self) -> &IrqDescState { &self.desc_internal_state } pub(super) fn internal_state_mut(&mut self) -> &mut IrqDescState { &mut self.desc_internal_state } pub fn irq_data(&self) -> &Arc { &self.irq_data } pub fn common_data(&self) -> &Arc { &self.common_data } #[allow(dead_code)] pub fn depth(&self) -> u32 { self.depth } #[allow(dead_code)] pub fn wake_depth(&self) -> u32 { self.wake_depth } #[allow(dead_code)] pub fn set_depth(&mut self, depth: u32) { self.depth = depth; } pub fn set_trigger_type(&mut self, trigger: IrqLineStatus) { self.line_status.remove(IrqLineStatus::IRQ_TYPE_SENSE_MASK); self.line_status .insert(trigger & IrqLineStatus::IRQ_TYPE_SENSE_MASK); } pub fn clear_level(&mut self) { self.line_status.remove(IrqLineStatus::IRQ_LEVEL); } pub fn set_level(&mut self) { self.line_status.insert(IrqLineStatus::IRQ_LEVEL); } pub fn percpu_enabled(&self) -> &Option { &self.percpu_enabled } pub fn percpu_enabled_mut(&mut self) -> &mut Option { &mut self.percpu_enabled } #[allow(dead_code)] pub fn percpu_affinity(&self) -> &Option { &self.percpu_affinity } pub fn percpu_affinity_mut(&mut self) -> &mut Option { &mut self.percpu_affinity } } impl KObject for IrqDesc { fn as_any_ref(&self) -> &dyn Any { self } fn set_inode(&self, inode: Option>) { self.inner().kern_inode = inode; } fn inode(&self) -> Option> { self.inner().kern_inode.clone() } fn parent(&self) -> Option> { self.inner().parent_kobj.clone() } fn set_parent(&self, parent: Option>) { self.inner().parent_kobj = parent; } fn kset(&self) -> Option> { self.inner().kset.clone() } fn set_kset(&self, kset: Option>) { self.inner().kset = kset; } fn kobj_type(&self) -> Option<&'static dyn KObjType> { Some(&IrqKObjType) } fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {} fn name(&self) -> String { self.inner().irq_data.irq().data().to_string() } fn set_name(&self, _name: String) {} fn kobj_state(&self) -> RwLockReadGuard { self.kobj_state.read() } fn kobj_state_mut(&self) -> RwLockWriteGuard { self.kobj_state.write() } fn set_kobj_state(&self, state: KObjectState) { *self.kobj_state_mut() = state; } } bitflags! { /// Bit masks for desc->desc_internal_state pub struct IrqDescState: u32 { /// autodetection in progress const IRQS_AUTODETECT = 0x00000001; /// was disabled due to spurious interrupt detection const IRQS_SPURIOUS_DISABLED = 0x00000002; /// polling in progress const IRQS_POLL_INPROGRESS = 0x00000008; /// irq is not unmasked in primary handler const IRQS_ONESHOT = 0x00000020; /// irq is replayed const IRQS_REPLAY = 0x00000040; /// irq is waiting const IRQS_WAITING = 0x00000080; /// irq is pending and replayed later const IRQS_PENDING = 0x00000200; /// irq is suspended const IRQS_SUSPENDED = 0x00000800; /// irq line is used to deliver NMIs const IRQS_NMI = 0x00002000; /// descriptor has been added to sysfs const IRQS_SYSFS = 0x00004000; } } /// 每个中断的响应动作的描述符 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/interrupt.h#118 #[allow(dead_code)] #[derive(Debug)] pub struct IrqAction { inner: SpinLock, /// 用于等待线程被创建的完成量 thread_completion: Completion, } impl IrqAction { #[allow(dead_code)] pub fn new( irq: IrqNumber, name: String, handler: Option<&'static dyn IrqHandler>, thread_fn: Option<&'static dyn IrqHandler>, ) -> Arc { let action: IrqAction = IrqAction { inner: SpinLock::new(InnerIrqAction { dev_id: None, per_cpu_dev_id: None, handler, thread_fn, thread: None, secondary: None, irq, flags: IrqHandleFlags::empty(), name, thread_flags: ThreadedHandlerFlags::empty(), }), thread_completion: Completion::new(), }; return Arc::new(action); } pub fn inner(&self) -> SpinLockGuard { self.inner.lock_irqsave() } pub fn thread_completion(&self) -> &Completion { &self.thread_completion } } #[allow(dead_code)] #[derive(Debug)] pub struct InnerIrqAction { /// cookie to identify the device dev_id: Option>, /// cookie to identify the device (per cpu) per_cpu_dev_id: Option>>, /// 中断处理程序 handler: Option<&'static dyn IrqHandler>, /// interrupt handler function for threaded interrupts thread_fn: Option<&'static dyn IrqHandler>, /// thread pointer for threaded interrupts thread: Option>, /// pointer to secondary irqaction (force threading) secondary: Option>, /// 中断号 irq: IrqNumber, flags: IrqHandleFlags, /// 中断线程的标志 thread_flags: ThreadedHandlerFlags, /// name of the device name: String, } impl InnerIrqAction { pub fn dev_id(&self) -> &Option> { &self.dev_id } pub fn dev_id_mut(&mut self) -> &mut Option> { &mut self.dev_id } pub fn per_cpu_dev_id(&self) -> Option<&Arc> { self.per_cpu_dev_id.as_ref().map(|v| v.get()) } #[allow(dead_code)] pub fn per_cpu_dev_id_mut(&mut self) -> Option<&mut Arc> { self.per_cpu_dev_id.as_mut().map(|v| v.get_mut()) } pub fn handler(&self) -> Option<&'static dyn IrqHandler> { self.handler } pub fn set_handler(&mut self, handler: Option<&'static dyn IrqHandler>) { self.handler = handler; } pub fn thread_fn(&self) -> Option<&'static dyn IrqHandler> { self.thread_fn } pub fn thread(&self) -> Option> { self.thread.clone() } pub fn set_thread(&mut self, thread: Option>) { self.thread = thread; } #[allow(dead_code)] pub fn thread_flags(&self) -> &ThreadedHandlerFlags { &self.thread_flags } pub fn thread_flags_mut(&mut self) -> &mut ThreadedHandlerFlags { &mut self.thread_flags } pub fn secondary(&self) -> Option> { self.secondary.clone() } #[allow(dead_code)] pub fn irq(&self) -> IrqNumber { self.irq } #[allow(dead_code)] pub fn set_irq(&mut self, irq: IrqNumber) { self.irq = irq; } pub fn flags(&self) -> &IrqHandleFlags { &self.flags } pub fn flags_mut(&mut self) -> &mut IrqHandleFlags { &mut self.flags } pub fn name(&self) -> &String { &self.name } } bitflags! { /// 这些标志由线程处理程序使用 pub struct ThreadedHandlerFlags: u32 { /// IRQTF_RUNTHREAD - 表示应运行中断处理程序线程 const IRQTF_RUNTHREAD = 1 << 0; /// IRQTF_WARNED - 已打印警告 "IRQ_WAKE_THREAD w/o thread_fn" const IRQTF_WARNED = 1 << 1; /// IRQTF_AFFINITY - 请求irq线程调整亲和性 const IRQTF_AFFINITY = 1 << 2; /// IRQTF_FORCED_THREAD - irq操作被强制线程化 const IRQTF_FORCED_THREAD = 1 << 3; /// IRQTF_READY - 表示irq线程已准备就绪 const IRQTF_READY = 1 << 4; } } /// Implements the `ThreadedHandlerFlags` structure. impl ThreadedHandlerFlags { /// 在 `ThreadedHandlerFlags` 结构中测试并设置特定的位。 /// /// # 参数 /// /// * `bit` - 要测试并设置的位。 /// /// # 返回 /// /// 如果操作前该位已被设置,则返回 `true`,否则返回 `false`。 pub fn test_and_set_bit(&mut self, bit: ThreadedHandlerFlags) -> bool { let res = (self.bits & bit.bits) != 0; self.bits |= bit.bits; return res; } } // 定义IrqFlags位标志 bitflags! { /// 这些标志仅由内核在中断处理例程中使用。 #[allow(clippy::bad_bit_mask)] pub struct IrqHandleFlags: u32 { const IRQF_TRIGGER_NONE = IrqLineStatus::IRQ_TYPE_NONE.bits(); const IRQF_TRIGGER_RISING = IrqLineStatus::IRQ_TYPE_EDGE_RISING.bits(); const IRQF_TRIGGER_FALLING = IrqLineStatus::IRQ_TYPE_EDGE_FALLING.bits(); const IRQF_TRIGGER_HIGH = IrqLineStatus::IRQ_TYPE_LEVEL_HIGH.bits(); const IRQF_TRIGGER_LOW = IrqLineStatus::IRQ_TYPE_LEVEL_LOW.bits(); const IRQF_TRIGGER_MASK = Self::IRQF_TRIGGER_HIGH.bits | Self::IRQF_TRIGGER_LOW.bits | Self::IRQF_TRIGGER_RISING.bits | Self::IRQF_TRIGGER_FALLING.bits; /// IRQF_SHARED - 允许多个设备共享中断 const IRQF_SHARED = 0x00000080; /// IRQF_PROBE_SHARED - 当预期出现共享不匹配时,由调用者设置 const IRQF_PROBE_SHARED = 0x00000100; /// IRQF_TIMER - 标记此中断为定时器中断 const __IRQF_TIMER = 0x00000200; /// IRQF_PERCPU - 中断是每个CPU的 const IRQF_PERCPU = 0x00000400; /// IRQF_NOBALANCING - 将此中断从中断平衡中排除 const IRQF_NOBALANCING = 0x00000800; /// IRQF_IRQPOLL - 中断用于轮询(出于性能原因,只有在共享中断中首次注册的中断会被考虑) const IRQF_IRQPOLL = 0x00001000; /// IRQF_ONESHOT - 在硬中断处理程序完成后,不会重新启用中断。由需要在运行线程处理程序之前保持中断线路禁用的线程中断使用。 const IRQF_ONESHOT = 0x00002000; /// IRQF_NO_SUSPEND - 在挂起期间不禁用此IRQ。不能保证此中断会从挂起状态唤醒系统。 const IRQF_NO_SUSPEND = 0x00004000; /// IRQF_FORCE_RESUME - 即使设置了IRQF_NO_SUSPEND,也强制在恢复时启用它 const IRQF_FORCE_RESUME = 0x00008000; /// IRQF_NO_THREAD - 中断不能被线程化 const IRQF_NO_THREAD = 0x00010000; /// IRQF_EARLY_RESUME - 在syscore而不是在设备恢复时间早期恢复IRQ。 const IRQF_EARLY_RESUME = 0x00020000; /// IRQF_COND_SUSPEND - 如果IRQ与NO_SUSPEND用户共享,则在挂起中断后执行此中断处理程序。对于系统唤醒设备用户,需要在他们的中断处理程序中实现唤醒检测。 const IRQF_COND_SUSPEND = 0x00040000; /// IRQF_NO_AUTOEN - 当用户请求时,不会自动启用IRQ或NMI。用户稍后会通过enable_irq()或enable_nmi()显式启用它。 const IRQF_NO_AUTOEN = 0x00080000; /// IRQF_NO_DEBUG - 从IPI和类似处理程序的逃逸检测中排除,取决于IRQF_PERCPU。 const IRQF_NO_DEBUG = 0x00100000; const IRQF_TIMER = Self::__IRQF_TIMER.bits | Self::IRQF_NO_SUSPEND.bits | Self::IRQF_NO_THREAD.bits; } } impl IrqHandleFlags { /// 检查是否指定了触发类型 #[inline(always)] pub fn trigger_type_specified(&self) -> bool { (self.bits & Self::IRQF_TRIGGER_MASK.bits) != 0 } /// 插入触发类型 pub fn insert_trigger_type(&mut self, trigger: IrqLineStatus) { self.bits |= trigger.trigger_bits() & IrqHandleFlags::IRQF_TRIGGER_MASK.bits; } #[allow(dead_code)] pub fn remove_trigger_type(&mut self, trigger: IrqLineStatus) { self.bits &= !(trigger.trigger_bits() & IrqHandleFlags::IRQF_TRIGGER_MASK.bits); } pub fn trigger_type(&self) -> IrqLineStatus { IrqLineStatus::from_bits_truncate(self.bits & IrqHandleFlags::IRQF_TRIGGER_MASK.bits) } } #[inline(never)] pub(super) fn early_irq_init() -> Result<(), SystemError> { let irqcnt = CurrentIrqArch::probe_total_irq_num(); let mut manager = IrqDescManager::new(); for i in 0..irqcnt { let irq_desc = IrqDesc::new(IrqNumber::new(i), None, IrqStatus::empty()); manager.insert(IrqNumber::new(i), irq_desc); } unsafe { IRQ_DESC_MANAGER = Some(manager); } return CurrentIrqArch::arch_early_irq_init(); } static mut IRQ_DESC_MANAGER: Option = None; /// 获取中断描述符管理器的引用 #[inline(always)] pub fn irq_desc_manager() -> &'static IrqDescManager { return unsafe { IRQ_DESC_MANAGER.as_ref().unwrap() }; } pub struct IrqDescManager { irq_descs: BTreeMap>, } impl IrqDescManager { fn new() -> Self { IrqDescManager { irq_descs: BTreeMap::new(), } } /// 查找中断描述符 pub fn lookup(&self, irq: IrqNumber) -> Option> { self.irq_descs.get(&irq).cloned() } /// 查找中断描述符并锁定总线(没有对irqdesc进行加锁) #[allow(dead_code)] pub fn lookup_and_lock_bus( &self, irq: IrqNumber, check_global: bool, check_percpu: bool, ) -> Option> { self.do_lookup_and_lock(irq, true, check_global, check_percpu) } fn do_lookup_and_lock( &self, irq: IrqNumber, lock_bus: bool, check_global: bool, check_percpu: bool, ) -> Option> { let desc = self.lookup(irq)?; if check_global || check_percpu { if check_percpu && !desc.inner().line_status().is_per_cpu_devid() { return None; } if check_global && desc.inner().line_status().is_per_cpu_devid() { return None; } } if lock_bus { desc.chip_bus_lock(); } return Some(desc); } fn insert(&mut self, irq: IrqNumber, desc: Arc) { self.irq_descs.insert(irq, desc); } /// 释放中断描述符 #[allow(dead_code)] fn free_desc(&mut self, irq: IrqNumber) { if let Some(desc) = self.irq_descs.get(&irq) { irq_sysfs_del(desc); self.irq_descs.remove(&irq); } } /// 迭代中断描述符 pub fn iter_descs(&self) -> btree_map::Iter<'_, IrqNumber, Arc> { self.irq_descs.iter() } /// 设置指定irq的可用cpu为所有cpu #[allow(dead_code)] pub fn set_percpu_devid_all(&self, irq: IrqNumber) -> Result<(), SystemError> { self.set_percpu_devid(irq, None) } /// 设置指定irq的可用cpu /// /// 如果affinity为None,则表示设置为所有cpu pub fn set_percpu_devid( &self, irq: IrqNumber, affinity: Option<&CpuMask>, ) -> Result<(), SystemError> { let desc = self.lookup(irq).ok_or(SystemError::EINVAL)?; let mut desc_inner = desc.inner(); if desc_inner.percpu_enabled().is_some() { return Err(SystemError::EINVAL); } *desc_inner.percpu_enabled_mut() = Some(CpuMask::new()); if let Some(affinity) = affinity { desc_inner.percpu_affinity_mut().replace(affinity.clone()); } else { desc_inner .percpu_affinity_mut() .replace(smp_cpu_manager().possible_cpus().clone()); } drop(desc_inner); desc.set_percpu_devid_flags(); return Ok(()); } } pub struct GenericIrqHandler; #[allow(dead_code)] impl GenericIrqHandler { /// `handle_domain_irq` - 调用属于某个中断域的硬件中断的处理程序 /// /// # 参数 /// /// * `domain`: 执行查找的域 /// * `hwirq`: 要转换为逻辑中断的硬件中断号 /// /// # 返回 /// /// 成功时返回 `Ok(())`,如果转换失败则返回 `Err(SystemError)` /// /// 此函数必须在初始化了中断寄存器的中断上下文中调用 /// /// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/irq/irqdesc.c?fi=generic_handle_domain_irq#726 pub fn handle_domain_irq( domain: Arc, hwirq: HardwareIrqNumber, trap_frame: &mut TrapFrame, ) -> Result<(), SystemError> { let (irq_desc, _) = irq_domain_manager().resolve_irq_mapping(Some(domain.clone()), hwirq)?; irq_desc.handler().unwrap().handle(&irq_desc, trap_frame); return Ok(()); } }