xref: /DragonOS/kernel/src/exception/irqdomain.rs (revision 352ee04918f4585ad4f8a896ca6e18b1ef7d7934)
1 use core::fmt::Debug;
2 
3 use alloc::{
4     string::{String, ToString},
5     sync::{Arc, Weak},
6     vec::Vec,
7 };
8 use hashbrown::HashMap;
9 use system_error::SystemError;
10 
11 use crate::{
12     driver::{base::device::Device, open_firmware::device_node::DeviceNode},
13     exception::{irqdata::IrqLineStatus, irqdesc::irq_desc_manager, manage::irq_manager},
14     libs::{
15         rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
16         spinlock::SpinLock,
17     },
18 };
19 
20 use super::{
21     dummychip::no_irq_chip,
22     irqchip::{IrqChip, IrqChipData, IrqChipGeneric, IrqGcFlags},
23     irqdata::{IrqData, IrqHandlerData},
24     irqdesc::{IrqDesc, IrqFlowHandler},
25     HardwareIrqNumber, IrqNumber,
26 };
27 
28 static mut IRQ_DOMAIN_MANAGER: Option<Arc<IrqDomainManager>> = None;
29 
30 /// 获取中断域管理器的引用
31 #[inline(always)]
32 pub fn irq_domain_manager() -> &'static Arc<IrqDomainManager> {
33     unsafe { IRQ_DOMAIN_MANAGER.as_ref().unwrap() }
34 }
35 
36 pub(super) fn irq_domain_manager_init() {
37     unsafe {
38         IRQ_DOMAIN_MANAGER = Some(Arc::new(IrqDomainManager::new()));
39     }
40 }
41 /// 中断域管理器
42 pub struct IrqDomainManager {
43     domains: SpinLock<Vec<Arc<IrqDomain>>>,
44     inner: RwLock<InnerIrqDomainManager>,
45 }
46 
47 impl IrqDomainManager {
48     pub fn new() -> IrqDomainManager {
49         IrqDomainManager {
50             domains: SpinLock::new(Vec::new()),
51             inner: RwLock::new(InnerIrqDomainManager {
52                 default_domain: None,
53             }),
54         }
55     }
56 
57     /// 创建一个新的线性映射的irqdomain, 并将其添加到irqdomain管理器中
58     ///
59     /// 创建的irqdomain,中断号是线性的,即从0开始,依次递增
60     ///
61     /// ## 参数
62     ///
63     /// - `name` - 中断域的名字
64     /// - `ops` - 中断域的操作
65     /// - `irq_size` - 中断号的数量
66     #[allow(dead_code)]
67     pub fn create_and_add_linear(
68         &self,
69         name: String,
70         ops: &'static dyn IrqDomainOps,
71         irq_size: u32,
72     ) -> Option<Arc<IrqDomain>> {
73         self.create_and_add(
74             name,
75             ops,
76             IrqNumber::new(0),
77             HardwareIrqNumber::new(0),
78             irq_size,
79         )
80     }
81 
82     /// 创建一个新的irqdomain, 并将其添加到irqdomain管理器中
83     ///
84     /// ## 参数
85     ///
86     /// - `name` - 中断域的名字
87     /// - `ops` - 中断域的操作
88     /// - `first_irq` - 起始软件中断号
89     /// - `first_hwirq` - 起始硬件中断号
90     /// - `irq_size` - 中断号的数量
91     ///
92     /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdomain.c?fi=__irq_domain_add#139
93     pub fn create_and_add(
94         &self,
95         name: String,
96         ops: &'static dyn IrqDomainOps,
97         first_irq: IrqNumber,
98         first_hwirq: HardwareIrqNumber,
99         irq_size: u32,
100     ) -> Option<Arc<IrqDomain>> {
101         let domain = IrqDomain::new(
102             None,
103             Some(name),
104             ops,
105             IrqDomainFlags::NAME_ALLOCATED,
106             IrqDomainBusToken::Any,
107             first_irq + irq_size,
108             first_hwirq + irq_size,
109         )?;
110 
111         self.add_domain(domain.clone());
112 
113         return Some(domain);
114     }
115 
116     fn add_domain(&self, domain: Arc<IrqDomain>) {
117         self.domains.lock_irqsave().push(domain);
118     }
119 
120     #[allow(dead_code)]
121     pub fn remove_domain(&self, domain: &Arc<IrqDomain>) {
122         let mut domains = self.domains.lock_irqsave();
123         let index = domains
124             .iter()
125             .position(|x| Arc::ptr_eq(x, domain))
126             .expect("domain not found");
127         domains.remove(index);
128     }
129 
130     /// 获取默认的中断域
131     #[allow(dead_code)]
132     pub fn default_domain(&self) -> Option<Arc<IrqDomain>> {
133         self.inner.read().default_domain.clone()
134     }
135 
136     /// 设置默认的中断域
137     ///
138     /// 在创建IRQ映射的时候,如果没有指定中断域,就会使用默认的中断域
139     pub fn set_default_domain(&self, domain: Arc<IrqDomain>) {
140         self.inner.write_irqsave().default_domain = Some(domain);
141     }
142 
143     /// 将指定范围的硬件中断号与软件中断号一一对应的关联起来
144     ///
145     /// ## 参数
146     ///
147     /// - `domain` - 中断域
148     /// - `first_irq` - 起始软件中断号
149     /// - `first_hwirq` - 起始硬件中断号
150     /// - `count` - 数量
151     pub fn domain_associate_many(
152         &self,
153         domain: &Arc<IrqDomain>,
154         first_irq: IrqNumber,
155         first_hwirq: HardwareIrqNumber,
156         count: u32,
157     ) {
158         for i in 0..count {
159             if let Err(e) = self.domain_associate(domain, first_irq + i, first_hwirq + i) {
160                 kwarn!("domain associate failed: {:?}, domain '{:?}' didn't like hwirq {} to virq {} mapping.", e, domain.name(), (first_hwirq + i).data(), (first_irq + i).data());
161             }
162         }
163     }
164 
165     /// 将一个硬件中断号与一个软件中断号关联起来
166     ///
167     /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdomain.c#562
168     pub fn domain_associate(
169         &self,
170         domain: &Arc<IrqDomain>,
171         irq: IrqNumber,
172         hwirq: HardwareIrqNumber,
173     ) -> Result<(), SystemError> {
174         if hwirq >= domain.revmap.read_irqsave().hwirq_max {
175             kwarn!(
176                 "hwirq {} is out of range for domain {:?}",
177                 hwirq.data(),
178                 domain.name()
179             );
180             return Err(SystemError::EINVAL);
181         }
182         let irq_data = irq_desc_manager()
183             .lookup(irq)
184             .ok_or_else(|| {
185                 kwarn!("irq_desc not found for irq {}", irq.data());
186                 SystemError::EINVAL
187             })?
188             .irq_data();
189         if irq_data.domain().is_some() {
190             kwarn!(
191                 "irq {} is already associated with domain {:?}",
192                 irq.data(),
193                 irq_data.domain().unwrap().name()
194             );
195             return Err(SystemError::EINVAL);
196         }
197 
198         let mut irq_data_guard = irq_data.inner();
199         irq_data_guard.set_hwirq(hwirq);
200         irq_data_guard.set_domain(Some(domain.clone()));
201         drop(irq_data_guard);
202         let r = domain.ops.map(domain, hwirq, irq);
203         if let Err(e) = r {
204             if e != SystemError::ENOSYS {
205                 if e != SystemError::EPERM {
206                     kinfo!("domain associate failed: {:?}, domain '{:?}' didn't like hwirq {} to virq {} mapping.", e, domain.name(), hwirq.data(), irq.data());
207                 }
208                 let mut irq_data_guard = irq_data.inner();
209                 irq_data_guard.set_domain(None);
210                 irq_data_guard.set_hwirq(HardwareIrqNumber::new(0));
211                 return Err(e);
212             }
213         }
214 
215         if domain.name().is_none() {
216             let chip = irq_data.chip_info_read_irqsave().chip();
217             domain.set_name(chip.name().to_string());
218         }
219 
220         self.irq_domain_set_mapping(domain, hwirq, irq_data);
221 
222         irq_manager().irq_clear_status_flags(irq, IrqLineStatus::IRQ_NOREQUEST)?;
223 
224         return Ok(());
225     }
226 
227     fn irq_domain_set_mapping(
228         &self,
229         domain: &Arc<IrqDomain>,
230         hwirq: HardwareIrqNumber,
231         irq_data: Arc<IrqData>,
232     ) {
233         if domain.no_map() {
234             return;
235         }
236 
237         domain.revmap.write_irqsave().insert(hwirq, irq_data);
238     }
239     /// 递归调用 domain_ops->activate 以激活中断
240     ///
241     /// ## 参数
242     ///
243     /// - irq_data: 与中断关联的最外层 irq_data
244     /// - reserve: 如果为true,则仅预留一个中断向量,而不是分配一个
245     ///
246     /// 这是调用 domain_ops->activate 以编程中断控制器的第二步,以便中断实际上可以被传递。
247     pub fn activate_irq(&self, irq_data: &Arc<IrqData>, reserve: bool) -> Result<(), SystemError> {
248         let mut r = Ok(());
249         // kdebug!(
250         //     "activate_irq: irq_data.common_data().status().is_activated()={}",
251         //     irq_data.common_data().status().is_activated()
252         // );
253         if !irq_data.common_data().status().is_activated() {
254             r = self.do_activate_irq(Some(irq_data.clone()), reserve);
255         }
256 
257         if r.is_err() {
258             irq_data.common_data().status().set_activated();
259         }
260 
261         return r;
262     }
263 
264     #[inline(never)]
265     fn do_activate_irq(
266         &self,
267         irq_data: Option<Arc<IrqData>>,
268         reserve: bool,
269     ) -> Result<(), SystemError> {
270         let mut r = Ok(());
271 
272         if let Some(irq_data) = irq_data {
273             // kdebug!("do_activate_irq: irq_data={:?}", irq_data);
274             if let Some(domain) = irq_data.domain() {
275                 // kdebug!("do_activate_irq: domain={:?}", domain.name());
276                 let parent_data = irq_data.parent_data().and_then(|x| x.upgrade());
277                 if let Some(parent_data) = parent_data.clone() {
278                     r = self.do_activate_irq(Some(parent_data), reserve);
279                 }
280 
281                 if r.is_err() {
282                     let tmpr = domain.ops.activate(&domain, &irq_data, reserve);
283                     if let Err(e) = tmpr {
284                         if e != SystemError::ENOSYS && parent_data.is_some() {
285                             self.do_deactivate_irq(parent_data);
286                         }
287                     }
288                 }
289             }
290         }
291 
292         return r;
293     }
294     #[allow(clippy::only_used_in_recursion)]
295     fn do_deactivate_irq(&self, irq_data: Option<Arc<IrqData>>) {
296         if let Some(irq_data) = irq_data {
297             if let Some(domain) = irq_data.domain() {
298                 domain.ops.deactivate(&domain, &irq_data);
299                 let pp = irq_data.parent_data().and_then(|x| x.upgrade());
300 
301                 if pp.is_some() {
302                     self.do_deactivate_irq(pp);
303                 }
304             }
305         }
306     }
307 
308     /// `irq_domain_set_info` - 在 @domain 中为 @virq 设置完整的数据
309     ///
310     /// ## 参数
311     ///
312     /// - `domain`: 要匹配的中断域
313     /// - `virq`: IRQ号
314     /// - `hwirq`: 硬件中断号
315     /// - `chip`: 相关的中断芯片
316     /// - `chip_data`: 相关的中断芯片数据
317     /// - `handler`: 中断流处理器
318     /// - `handler_data`: 中断流处理程序数据
319     /// - `handler_name`: 中断处理程序名称
320     #[allow(clippy::too_many_arguments)]
321     pub fn domain_set_info(
322         &self,
323         domain: &Arc<IrqDomain>,
324         virq: IrqNumber,
325         hwirq: HardwareIrqNumber,
326         chip: Arc<dyn IrqChip>,
327         chip_data: Option<Arc<dyn IrqChipData>>,
328         flow_handler: &'static dyn IrqFlowHandler,
329         handler_data: Option<Arc<dyn IrqHandlerData>>,
330         handler_name: Option<String>,
331     ) {
332         let r = self.domain_set_hwirq_and_chip(domain, virq, hwirq, Some(chip), chip_data);
333         if r.is_err() {
334             return;
335         }
336         irq_manager().__irq_set_handler(virq, flow_handler, false, handler_name);
337         irq_manager().irq_set_handler_data(virq, handler_data).ok();
338     }
339 
340     /// `domain_set_hwirq_and_chip` - 在 @domain 中为 @virq 设置 hwirq 和 irqchip
341     ///
342     /// ## 参数
343     ///
344     /// - `domain`: 要匹配的中断域
345     /// - `virq`: IRQ号
346     /// - `hwirq`: hwirq号
347     /// - `chip`: 相关的中断芯片
348     /// - `chip_data`: 相关的芯片数据
349     pub fn domain_set_hwirq_and_chip(
350         &self,
351         domain: &Arc<IrqDomain>,
352         virq: IrqNumber,
353         hwirq: HardwareIrqNumber,
354         chip: Option<Arc<dyn IrqChip>>,
355         chip_data: Option<Arc<dyn IrqChipData>>,
356     ) -> Result<(), SystemError> {
357         let irq_data: Arc<IrqData> = self
358             .domain_get_irq_data(domain, virq)
359             .ok_or(SystemError::ENOENT)?;
360         let mut inner = irq_data.inner();
361         let mut chip_info = irq_data.chip_info_write_irqsave();
362 
363         inner.set_hwirq(hwirq);
364         if let Some(chip) = chip {
365             chip_info.set_chip(Some(chip));
366         } else {
367             chip_info.set_chip(Some(no_irq_chip()));
368         };
369 
370         chip_info.set_chip_data(chip_data);
371 
372         return Ok(());
373     }
374 
375     /// `irq_domain_get_irq_data` - 获取与 @virq 和 @domain 关联的 irq_data
376     ///
377     /// ## 参数
378     ///
379     /// - `domain`: 要匹配的域
380     /// - `virq`: 要获取 irq_data 的IRQ号
381     pub fn domain_get_irq_data(
382         &self,
383         domain: &Arc<IrqDomain>,
384         virq: IrqNumber,
385     ) -> Option<Arc<IrqData>> {
386         let desc = irq_desc_manager().lookup(virq)?;
387         let mut irq_data = Some(desc.irq_data());
388 
389         while irq_data.is_some() {
390             let dt = irq_data.unwrap();
391             if dt.domain().is_some() && Arc::ptr_eq(dt.domain().as_ref().unwrap(), domain) {
392                 return Some(dt);
393             }
394             irq_data = dt.parent_data().and_then(|x| x.upgrade());
395         }
396 
397         return None;
398     }
399 
400     /// `resolve_irq_mapping` - 从硬件中断号找到中断号。
401     ///
402     /// ## 参数
403     ///
404     /// - `domain`: 拥有此硬件中断的域
405     /// - `hwirq`: 该域空间中的硬件中断号
406     /// - `irq`: 如果需要,可选的指针以返回Linux中断
407     ///
408     /// ## 返回
409     ///
410     /// 返回一个元组,包含中断描述符和中断号
411     pub fn resolve_irq_mapping(
412         &self,
413         mut domain: Option<Arc<IrqDomain>>,
414         hwirq: HardwareIrqNumber,
415     ) -> Result<(Arc<IrqDesc>, IrqNumber), SystemError> {
416         if domain.is_none() {
417             domain = Some(self.default_domain().ok_or(SystemError::EINVAL)?);
418         }
419 
420         let domain = domain.unwrap();
421 
422         if domain.no_map() {
423             if hwirq < domain.revmap_read_irqsave().hwirq_max {
424                 let irq_desc = irq_desc_manager()
425                     .lookup(IrqNumber::new(hwirq.data()))
426                     .ok_or(SystemError::EINVAL)?;
427                 if irq_desc.irq_data().hardware_irq() == hwirq {
428                     let irq = irq_desc.irq_data().irq();
429                     return Ok((irq_desc, irq));
430                 }
431             }
432 
433             return Err(SystemError::EINVAL);
434         }
435 
436         let revmap = domain.revmap_read_irqsave();
437         let irq_data = revmap.lookup(hwirq).ok_or(SystemError::EINVAL)?;
438         let irq_desc = irq_data.irq_desc().unwrap();
439         return Ok((irq_desc, irq_data.irq()));
440     }
441 }
442 
443 struct InnerIrqDomainManager {
444     default_domain: Option<Arc<IrqDomain>>,
445 }
446 
447 /// 中断域
448 ///
449 /// 用于把硬件中断号翻译为软件中断号的映射的对象
450 ///
451 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#164
452 #[allow(dead_code)]
453 #[derive(Debug)]
454 pub struct IrqDomain {
455     /// 中断域的名字 (二选一)
456     name: Option<&'static str>,
457     allocated_name: SpinLock<Option<String>>,
458     /// 中断域的操作
459     ops: &'static dyn IrqDomainOps,
460     inner: SpinLock<InnerIrqDomain>,
461     /// 中断号反向映射
462     revmap: RwLock<IrqDomainRevMap>,
463 }
464 
465 #[allow(dead_code)]
466 #[derive(Debug)]
467 struct InnerIrqDomain {
468     /// this field not touched by the core code
469     host_data: Option<Arc<dyn IrqChipData>>,
470     /// host per irq_domain flags
471     flags: IrqDomainFlags,
472     /// The number of mapped interrupts
473     mapcount: u32,
474     bus_token: IrqDomainBusToken,
475     /// 指向 generic chip 列表的指针。
476     /// 有一个辅助函数用于为中断控制器驱动程序设置一个或
477     /// 多个 generic chip,该函数使用此指针并依赖于 generic chip 库。
478     generic_chip: Option<Arc<IrqDomainChipGeneric>>,
479     /// Pointer to a device that the domain represent, and that will be
480     /// used for power management purposes.
481     device: Option<Arc<dyn Device>>,
482     /// Pointer to parent irq_domain to support hierarchy irq_domains
483     parent: Option<Weak<IrqDomain>>,
484 }
485 
486 impl IrqDomain {
487     #[allow(dead_code)]
488     pub fn new(
489         name: Option<&'static str>,
490         allocated_name: Option<String>,
491         ops: &'static dyn IrqDomainOps,
492         flags: IrqDomainFlags,
493         bus_token: IrqDomainBusToken,
494         irq_max: IrqNumber,
495         hwirq_max: HardwareIrqNumber,
496     ) -> Option<Arc<Self>> {
497         if name.is_none() && allocated_name.is_none() {
498             return None;
499         }
500 
501         let x = IrqDomain {
502             name,
503             allocated_name: SpinLock::new(allocated_name),
504             ops,
505             inner: SpinLock::new(InnerIrqDomain {
506                 host_data: None,
507                 flags,
508                 mapcount: 0,
509                 bus_token,
510                 generic_chip: None,
511                 device: None,
512                 parent: None,
513             }),
514             revmap: RwLock::new(IrqDomainRevMap {
515                 map: HashMap::new(),
516                 hwirq_max,
517                 irq_max,
518             }),
519         };
520 
521         return Some(Arc::new(x));
522     }
523 
524     /// 中断域是否不对中断号进行转换
525     pub fn no_map(&self) -> bool {
526         self.inner
527             .lock_irqsave()
528             .flags
529             .contains(IrqDomainFlags::NO_MAP)
530     }
531 
532     #[allow(dead_code)]
533     fn revmap_read_irqsave(&self) -> RwLockReadGuard<IrqDomainRevMap> {
534         self.revmap.read_irqsave()
535     }
536 
537     #[allow(dead_code)]
538     fn revmap_write_irqsave(&self) -> RwLockWriteGuard<IrqDomainRevMap> {
539         self.revmap.write_irqsave()
540     }
541 
542     #[allow(dead_code)]
543     fn set_hwirq_max(&self, hwirq_max: HardwareIrqNumber) {
544         self.revmap_write_irqsave().hwirq_max = hwirq_max;
545     }
546 
547     pub fn name(&self) -> Option<String> {
548         if let Some(name) = self.name {
549             return Some(name.to_string());
550         }
551         return self.allocated_name.lock_irqsave().clone();
552     }
553 
554     pub fn set_name(&self, name: String) {
555         *self.allocated_name.lock_irqsave() = Some(name);
556     }
557 
558     /// The number of mapped interrupts
559     pub fn map_count(&self) -> u32 {
560         self.revmap_read_irqsave().map.len() as u32
561     }
562 
563     pub fn host_data(&self) -> Option<Arc<dyn IrqChipData>> {
564         self.inner.lock_irqsave().host_data.clone()
565     }
566 
567     pub fn set_host_data(&self, host_data: Option<Arc<dyn IrqChipData>>) {
568         self.inner.lock_irqsave().host_data = host_data;
569     }
570 }
571 
572 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190
573 #[allow(dead_code)]
574 #[derive(Debug)]
575 struct IrqDomainRevMap {
576     map: HashMap<HardwareIrqNumber, Arc<IrqData>>,
577     hwirq_max: HardwareIrqNumber,
578     irq_max: IrqNumber,
579 }
580 
581 impl IrqDomainRevMap {
582     fn insert(&mut self, hwirq: HardwareIrqNumber, irq_data: Arc<IrqData>) {
583         self.map.insert(hwirq, irq_data);
584     }
585 
586     #[allow(dead_code)]
587     fn remove(&mut self, hwirq: HardwareIrqNumber) {
588         self.map.remove(&hwirq);
589     }
590 
591     #[allow(dead_code)]
592     fn lookup(&self, hwirq: HardwareIrqNumber) -> Option<Arc<IrqData>> {
593         self.map.get(&hwirq).cloned()
594     }
595 }
596 
597 bitflags! {
598     pub struct IrqDomainFlags: u32 {
599         /// Irq domain is hierarchical
600         const HIERARCHY = (1 << 0);
601         /// Irq domain name was allocated dynamically
602         const NAME_ALLOCATED = (1 << 1);
603         /// Irq domain is an IPI domain with virq per cpu
604         const IPI_PER_CPU = (1 << 2);
605         /// Irq domain is an IPI domain with single virq
606         const IPI_SINGLE = (1 << 3);
607         /// Irq domain implements MSIs
608         const MSI = (1 << 4);
609         /// Irq domain implements MSI remapping
610         const MSI_REMAP = (1 << 5);
611         /// Quirk to handle MSI implementations which do not provide masking
612         const MSI_NOMASK_QUIRK = (1 << 6);
613         /// Irq domain doesn't translate anything
614         const NO_MAP = (1 << 7);
615         /// Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
616         /// for implementation specific purposes and ignored by the core code
617         const NONCORE = (1 << 16);
618     }
619 }
620 
621 /// 如果多个域有相同的设备节点,但服务于不同的目的(例如,一个域用于PCI/MSI,另一个用于有线IRQs),
622 /// 它们可以使用特定于总线的token进行区分。预计大多数域只会携带`DomainBusAny`。
623 ///
624 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#78
625 #[allow(dead_code)]
626 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
627 pub enum IrqDomainBusToken {
628     Any = 0,
629     Wired,
630     GenericMsi,
631     PciMsi,
632     PlatformMsi,
633     Nexus,
634     Ipi,
635     FslMcMsi,
636     TiSciIntaMsi,
637     Wakeup,
638     VmdMsi,
639 }
640 
641 /// IrqDomain的操作方法
642 ///
643 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
644 pub trait IrqDomainOps: Debug + Send + Sync {
645     /// 匹配一个中断控制器设备节点到一个主机。
646     fn match_node(
647         &self,
648         _irq_domain: &Arc<IrqDomain>,
649         _device_node: &Arc<DeviceNode>,
650         _bus_token: IrqDomainBusToken,
651     ) -> bool {
652         false
653     }
654 
655     /// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。
656     /// 对于给定的映射,这只会被调用一次。
657     ///
658     /// 如果没有实现这个方法,那么就会返回`ENOSYS`
659     fn map(
660         &self,
661         _irq_domain: &Arc<IrqDomain>,
662         _hwirq: HardwareIrqNumber,
663         _virq: IrqNumber,
664     ) -> Result<(), SystemError> {
665         Err(SystemError::ENOSYS)
666     }
667 
668     /// 删除一个虚拟中断号与一个硬件中断号之间的映射。
669     fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber);
670 
671     fn activate(
672         &self,
673         _domain: &Arc<IrqDomain>,
674         _irq_data: &Arc<IrqData>,
675         _reserve: bool,
676     ) -> Result<(), SystemError> {
677         Err(SystemError::ENOSYS)
678     }
679 
680     fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {}
681 }
682 
683 #[allow(dead_code)]
684 #[derive(Debug)]
685 pub struct IrqDomainChipGeneric {
686     inner: SpinLock<InnerIrqDomainChipGeneric>,
687 }
688 
689 #[allow(dead_code)]
690 #[derive(Debug)]
691 struct InnerIrqDomainChipGeneric {
692     irqs_per_chip: u32,
693     flags_to_clear: IrqGcFlags,
694     flags_to_set: IrqGcFlags,
695     gc_flags: IrqGcFlags,
696     gc: Vec<Arc<IrqChipGeneric>>,
697 }
698