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