xref: /DragonOS/kernel/src/exception/msi.rs (revision d2b28acb4d1f160779b25d76afca49ed60ad5d48)
1 use core::{any::Any, fmt::Debug};
2 
3 use alloc::sync::Arc;
4 
5 use crate::{
6     driver::{base::device::Device, pci::pci_irq::PciIrqMsg},
7     filesystem::sysfs::Attribute,
8     libs::spinlock::SpinLock,
9 };
10 
11 use super::IrqNumber;
12 
13 #[derive(Clone, Copy)]
14 pub struct MsiMsg {
15     pub address_lo: u32,
16     pub address_hi: u32,
17     pub data: u32,
18 }
19 
20 impl Debug for MsiMsg {
21     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
22         write!(
23             f,
24             "MsiMsg {{ address_lo: 0x{:x}, address_hi: 0x{:x}, data: 0x{:x} }}",
25             self.address_lo, self.address_hi, self.data
26         )
27     }
28 }
29 
30 #[allow(dead_code)]
31 impl MsiMsg {
32     /// Create a new MSI message
33     pub const fn new(address: u64, data: u32) -> Self {
34         MsiMsg {
35             address_lo: address as u32,
36             address_hi: (address >> 32) as u32,
37             data,
38         }
39     }
40 
41     /// Create a new MSI message
42     pub const fn new_lo_hi(address_lo: u32, address_hi: u32, data: u32) -> Self {
43         MsiMsg {
44             address_lo,
45             address_hi,
46             data,
47         }
48     }
49 
50     /// Get the address of the MSI message
51     pub const fn address(&self) -> u64 {
52         (self.address_hi as u64) << 32 | self.address_lo as u64
53     }
54 }
55 
56 #[allow(dead_code)]
57 #[derive(Debug)]
58 pub struct MsiDesc {
59     inner: SpinLock<InnerMsiDesc>,
60 }
61 
62 #[allow(dead_code)]
63 #[derive(Debug)]
64 struct InnerMsiDesc {
65     /// The base interrupt number
66     irq: IrqNumber,
67     /// The number of vectors used
68     nvec_used: u32,
69     /// Pointer to the device which uses this descriptor
70     dev: Option<Arc<dyn Device>>,
71     /// The last set MSI message cached for reuse
72     msg: MsiMsg,
73     /// Pointer to sysfs device attribute
74     sysfs_attribute: Option<&'static dyn Attribute>,
75     /// Pointer to MSI callback function
76     func: Option<&'static dyn MsiDescFunc>,
77     /// The index of the MSI descriptor
78     index: u32,
79     /// PCI specific msi descriptor data
80     pci_msg: PciIrqMsg,
81 }
82 
83 #[allow(dead_code)]
84 impl MsiDesc {
85     pub const fn new(
86         irq: IrqNumber,
87         nvec_used: u32,
88         dev: Option<Arc<dyn Device>>,
89         index: u32,
90         pci_msg: PciIrqMsg,
91     ) -> Self {
92         MsiDesc {
93             inner: SpinLock::new(InnerMsiDesc {
94                 irq,
95                 nvec_used,
96                 dev,
97                 msg: MsiMsg {
98                     address_lo: 0,
99                     address_hi: 0,
100                     data: 0,
101                 },
102                 sysfs_attribute: None,
103                 func: None,
104                 index,
105                 pci_msg,
106             }),
107         }
108     }
109 
110     pub fn set_msg(&self, msg: MsiMsg) {
111         self.inner.lock().msg = msg;
112     }
113 
114     pub fn msg(&self) -> MsiMsg {
115         self.inner.lock().msg
116     }
117 }
118 
119 pub trait MsiDescFunc: Debug + Send + Sync {
120     /// Callback that may be called when the MSI message
121     /// address or data changes.
122     fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>);
123 }
124 
125 /// Data parameter for the `MsiDescFunc` callback.
126 pub trait MsiDescFuncData: Send + Sync + Any {}
127