xref: /DragonOS/kernel/src/exception/irqdomain.rs (revision 5eeefb8c80e5580641d295724f8d2190bd54979c)
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_ok() {
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 irq_data.is_some() && irq_data.as_ref().unwrap().domain().is_some() {
268             let domain = irq_data.as_ref().unwrap().domain().unwrap();
269 
270             let irq_data = irq_data.unwrap();
271 
272             let parent_data = irq_data.parent_data().map(|x| x.upgrade()).flatten();
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         return r;
288     }
289 
290     fn do_deactivate_irq(&self, irq_data: Option<Arc<IrqData>>) {
291         if let Some(irq_data) = irq_data {
292             if let Some(domain) = irq_data.domain() {
293                 domain.ops.deactivate(&domain, &irq_data);
294                 let pp = irq_data.parent_data().map(|x| x.upgrade()).flatten();
295 
296                 if pp.is_some() {
297                     self.do_deactivate_irq(pp);
298                 }
299             }
300         }
301     }
302 
303     /// `irq_domain_set_info` - 在 @domain 中为 @virq 设置完整的数据
304     ///
305     /// ## 参数
306     ///
307     /// - `domain`: 要匹配的中断域
308     /// - `virq`: IRQ号
309     /// - `hwirq`: 硬件中断号
310     /// - `chip`: 相关的中断芯片
311     /// - `chip_data`: 相关的中断芯片数据
312     /// - `handler`: 中断流处理器
313     /// - `handler_data`: 中断流处理程序数据
314     /// - `handler_name`: 中断处理程序名称
315     pub fn domain_set_info(
316         &self,
317         domain: &Arc<IrqDomain>,
318         virq: IrqNumber,
319         hwirq: HardwareIrqNumber,
320         chip: Arc<dyn IrqChip>,
321         chip_data: Option<Arc<dyn IrqChipData>>,
322         flow_handler: &'static dyn IrqFlowHandler,
323         handler_data: Option<Arc<dyn IrqHandlerData>>,
324         handler_name: Option<String>,
325     ) {
326         let r = self.domain_set_hwirq_and_chip(domain, virq, hwirq, Some(chip), chip_data);
327         if r.is_err() {
328             return;
329         }
330         irq_manager().__irq_set_handler(virq, flow_handler, false, handler_name);
331         irq_manager().irq_set_handler_data(virq, handler_data).ok();
332     }
333 
334     /// `domain_set_hwirq_and_chip` - 在 @domain 中为 @virq 设置 hwirq 和 irqchip
335     ///
336     /// ## 参数
337     ///
338     /// - `domain`: 要匹配的中断域
339     /// - `virq`: IRQ号
340     /// - `hwirq`: hwirq号
341     /// - `chip`: 相关的中断芯片
342     /// - `chip_data`: 相关的芯片数据
343     pub fn domain_set_hwirq_and_chip(
344         &self,
345         domain: &Arc<IrqDomain>,
346         virq: IrqNumber,
347         hwirq: HardwareIrqNumber,
348         chip: Option<Arc<dyn IrqChip>>,
349         chip_data: Option<Arc<dyn IrqChipData>>,
350     ) -> Result<(), SystemError> {
351         let irq_data: Arc<IrqData> = self
352             .domain_get_irq_data(domain, virq)
353             .ok_or(SystemError::ENOENT)?;
354         let mut inner = irq_data.inner();
355         let mut chip_info = irq_data.chip_info_write_irqsave();
356 
357         inner.set_hwirq(hwirq);
358         if let Some(chip) = chip {
359             chip_info.set_chip(Some(chip));
360         } else {
361             chip_info.set_chip(Some(no_irq_chip()));
362         };
363 
364         chip_info.set_chip_data(chip_data);
365 
366         return Ok(());
367     }
368 
369     /// `irq_domain_get_irq_data` - 获取与 @virq 和 @domain 关联的 irq_data
370     ///
371     /// ## 参数
372     ///
373     /// - `domain`: 要匹配的域
374     /// - `virq`: 要获取 irq_data 的IRQ号
375     pub fn domain_get_irq_data(
376         &self,
377         domain: &Arc<IrqDomain>,
378         virq: IrqNumber,
379     ) -> Option<Arc<IrqData>> {
380         let desc = irq_desc_manager().lookup(virq)?;
381         let mut irq_data = Some(desc.irq_data());
382 
383         while irq_data.is_some() {
384             let dt = irq_data.unwrap();
385             if dt.domain().is_some() && Arc::ptr_eq(dt.domain().as_ref().unwrap(), domain) {
386                 return Some(dt);
387             }
388             irq_data = dt.parent_data().map(|x| x.upgrade()).flatten();
389         }
390 
391         return None;
392     }
393 }
394 
395 struct InnerIrqDomainManager {
396     default_domain: Option<Arc<IrqDomain>>,
397 }
398 
399 /// 中断域
400 ///
401 /// 用于把硬件中断号翻译为软件中断号的映射的对象
402 ///
403 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#164
404 #[allow(dead_code)]
405 #[derive(Debug)]
406 pub struct IrqDomain {
407     /// 中断域的名字 (二选一)
408     name: Option<&'static str>,
409     allocated_name: SpinLock<Option<String>>,
410     /// 中断域的操作
411     ops: &'static dyn IrqDomainOps,
412     inner: SpinLock<InnerIrqDomain>,
413     /// 中断号反向映射
414     revmap: RwLock<IrqDomainRevMap>,
415 }
416 
417 #[allow(dead_code)]
418 #[derive(Debug)]
419 struct InnerIrqDomain {
420     /// this field not touched by the core code
421     host_data: Option<Arc<dyn IrqChipData>>,
422     /// host per irq_domain flags
423     flags: IrqDomainFlags,
424     /// The number of mapped interrupts
425     mapcount: u32,
426     bus_token: IrqDomainBusToken,
427     /// 指向 generic chip 列表的指针。
428     /// 有一个辅助函数用于为中断控制器驱动程序设置一个或
429     /// 多个 generic chip,该函数使用此指针并依赖于 generic chip 库。
430     generic_chip: Option<Arc<IrqDomainChipGeneric>>,
431     /// Pointer to a device that the domain represent, and that will be
432     /// used for power management purposes.
433     device: Option<Arc<dyn Device>>,
434     /// Pointer to parent irq_domain to support hierarchy irq_domains
435     parent: Option<Weak<IrqDomain>>,
436 }
437 
438 impl IrqDomain {
439     #[allow(dead_code)]
440     pub fn new(
441         name: Option<&'static str>,
442         allocated_name: Option<String>,
443         ops: &'static dyn IrqDomainOps,
444         flags: IrqDomainFlags,
445         bus_token: IrqDomainBusToken,
446         irq_max: IrqNumber,
447         hwirq_max: HardwareIrqNumber,
448     ) -> Option<Arc<Self>> {
449         if name.is_none() && allocated_name.is_none() {
450             return None;
451         }
452 
453         let x = IrqDomain {
454             name,
455             allocated_name: SpinLock::new(allocated_name),
456             ops,
457             inner: SpinLock::new(InnerIrqDomain {
458                 host_data: None,
459                 flags,
460                 mapcount: 0,
461                 bus_token,
462                 generic_chip: None,
463                 device: None,
464                 parent: None,
465             }),
466             revmap: RwLock::new(IrqDomainRevMap {
467                 map: HashMap::new(),
468                 hwirq_max,
469                 irq_max,
470             }),
471         };
472 
473         return Some(Arc::new(x));
474     }
475 
476     /// 中断域是否不对中断号进行转换
477     pub fn no_map(&self) -> bool {
478         self.inner
479             .lock_irqsave()
480             .flags
481             .contains(IrqDomainFlags::NO_MAP)
482     }
483 
484     #[allow(dead_code)]
485     fn set_hwirq_max(&self, hwirq_max: HardwareIrqNumber) {
486         self.revmap.write_irqsave().hwirq_max = hwirq_max;
487     }
488 
489     pub fn name(&self) -> Option<String> {
490         if let Some(name) = self.name {
491             return Some(name.to_string());
492         }
493         return self.allocated_name.lock_irqsave().clone();
494     }
495 
496     pub fn set_name(&self, name: String) {
497         *self.allocated_name.lock_irqsave() = Some(name);
498     }
499 
500     /// The number of mapped interrupts
501     pub fn map_count(&self) -> u32 {
502         self.revmap.read().map.len() as u32
503     }
504 
505     pub fn host_data(&self) -> Option<Arc<dyn IrqChipData>> {
506         self.inner.lock_irqsave().host_data.clone()
507     }
508 
509     pub fn set_host_data(&self, host_data: Option<Arc<dyn IrqChipData>>) {
510         self.inner.lock_irqsave().host_data = host_data;
511     }
512 }
513 
514 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190
515 #[allow(dead_code)]
516 #[derive(Debug)]
517 struct IrqDomainRevMap {
518     map: HashMap<HardwareIrqNumber, Arc<IrqData>>,
519     hwirq_max: HardwareIrqNumber,
520     irq_max: IrqNumber,
521 }
522 
523 impl IrqDomainRevMap {
524     fn insert(&mut self, hwirq: HardwareIrqNumber, irq_data: Arc<IrqData>) {
525         self.map.insert(hwirq, irq_data);
526     }
527 
528     #[allow(dead_code)]
529     fn remove(&mut self, hwirq: HardwareIrqNumber) {
530         self.map.remove(&hwirq);
531     }
532 
533     #[allow(dead_code)]
534     fn lookup(&self, hwirq: HardwareIrqNumber) -> Option<Arc<IrqData>> {
535         self.map.get(&hwirq).cloned()
536     }
537 }
538 
539 bitflags! {
540     pub struct IrqDomainFlags: u32 {
541         /// Irq domain is hierarchical
542         const HIERARCHY = (1 << 0);
543         /// Irq domain name was allocated dynamically
544         const NAME_ALLOCATED = (1 << 1);
545         /// Irq domain is an IPI domain with virq per cpu
546         const IPI_PER_CPU = (1 << 2);
547         /// Irq domain is an IPI domain with single virq
548         const IPI_SINGLE = (1 << 3);
549         /// Irq domain implements MSIs
550         const MSI = (1 << 4);
551         /// Irq domain implements MSI remapping
552         const MSI_REMAP = (1 << 5);
553         /// Quirk to handle MSI implementations which do not provide masking
554         const MSI_NOMASK_QUIRK = (1 << 6);
555         /// Irq domain doesn't translate anything
556         const NO_MAP = (1 << 7);
557         /// Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
558         /// for implementation specific purposes and ignored by the core code
559         const NONCORE = (1 << 16);
560     }
561 }
562 
563 /// 如果多个域有相同的设备节点,但服务于不同的目的(例如,一个域用于PCI/MSI,另一个用于有线IRQs),
564 /// 它们可以使用特定于总线的token进行区分。预计大多数域只会携带`DomainBusAny`。
565 ///
566 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#78
567 #[allow(dead_code)]
568 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
569 pub enum IrqDomainBusToken {
570     Any = 0,
571     Wired,
572     GenericMsi,
573     PciMsi,
574     PlatformMsi,
575     Nexus,
576     Ipi,
577     FslMcMsi,
578     TiSciIntaMsi,
579     Wakeup,
580     VmdMsi,
581 }
582 
583 /// IrqDomain的操作方法
584 ///
585 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
586 pub trait IrqDomainOps: Debug + Send + Sync {
587     /// 匹配一个中断控制器设备节点到一个主机。
588     fn match_node(
589         &self,
590         _irq_domain: &Arc<IrqDomain>,
591         _device_node: &Arc<DeviceNode>,
592         _bus_token: IrqDomainBusToken,
593     ) -> bool {
594         false
595     }
596 
597     /// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。
598     /// 对于给定的映射,这只会被调用一次。
599     ///
600     /// 如果没有实现这个方法,那么就会返回`ENOSYS`
601     fn map(
602         &self,
603         _irq_domain: &Arc<IrqDomain>,
604         _hwirq: HardwareIrqNumber,
605         _virq: IrqNumber,
606     ) -> Result<(), SystemError> {
607         Err(SystemError::ENOSYS)
608     }
609 
610     /// 删除一个虚拟中断号与一个硬件中断号之间的映射。
611     fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber);
612 
613     fn activate(
614         &self,
615         _domain: &Arc<IrqDomain>,
616         _irq_data: &Arc<IrqData>,
617         _reserve: bool,
618     ) -> Result<(), SystemError> {
619         Err(SystemError::ENOSYS)
620     }
621 
622     fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {}
623 }
624 
625 #[allow(dead_code)]
626 #[derive(Debug)]
627 pub struct IrqDomainChipGeneric {
628     inner: SpinLock<InnerIrqDomainChipGeneric>,
629 }
630 
631 #[allow(dead_code)]
632 #[derive(Debug)]
633 struct InnerIrqDomainChipGeneric {
634     irqs_per_chip: u32,
635     flags_to_clear: IrqGcFlags,
636     flags_to_set: IrqGcFlags,
637     gc_flags: IrqGcFlags,
638     gc: Vec<Arc<IrqChipGeneric>>,
639 }
640