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