xref: /DragonOS/kernel/src/exception/msi.rs (revision 55e6f0b65f91b32638fd56581f711a816eccdcd1)
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     pub const fn new_zeroed() -> Self {
56         MsiMsg {
57             address_lo: 0,
58             address_hi: 0,
59             data: 0,
60         }
61     }
62 }
63 
64 #[allow(dead_code)]
65 #[derive(Debug)]
66 pub struct MsiDesc {
67     inner: SpinLock<InnerMsiDesc>,
68 }
69 
70 #[allow(dead_code)]
71 #[derive(Debug)]
72 struct InnerMsiDesc {
73     /// The base interrupt number
74     irq: IrqNumber,
75     /// The number of vectors used
76     nvec_used: u32,
77     /// Pointer to the device which uses this descriptor
78     dev: Option<Arc<dyn Device>>,
79     /// The last set MSI message cached for reuse
80     msg: MsiMsg,
81     /// Pointer to sysfs device attribute
82     sysfs_attribute: Option<&'static dyn Attribute>,
83     /// Pointer to MSI callback function
84     func: Option<&'static dyn MsiDescFunc>,
85     /// The index of the MSI descriptor
86     index: u32,
87     /// PCI specific msi descriptor data
88     pci_msg: PciIrqMsg,
89 }
90 
91 #[allow(dead_code)]
92 impl MsiDesc {
93     pub const fn new(
94         irq: IrqNumber,
95         nvec_used: u32,
96         dev: Option<Arc<dyn Device>>,
97         index: u32,
98         pci_msg: PciIrqMsg,
99     ) -> Self {
100         MsiDesc {
101             inner: SpinLock::new(InnerMsiDesc {
102                 irq,
103                 nvec_used,
104                 dev,
105                 msg: MsiMsg {
106                     address_lo: 0,
107                     address_hi: 0,
108                     data: 0,
109                 },
110                 sysfs_attribute: None,
111                 func: None,
112                 index,
113                 pci_msg,
114             }),
115         }
116     }
117 
118     pub fn set_msg(&self, msg: MsiMsg) {
119         self.inner.lock().msg = msg;
120     }
121 
122     pub fn msg(&self) -> MsiMsg {
123         self.inner.lock().msg
124     }
125 }
126 
127 #[allow(dead_code)]
128 pub trait MsiDescFunc: Debug + Send + Sync {
129     /// Callback that may be called when the MSI message
130     /// address or data changes.
131     fn write_msi_msg(&self, data: Arc<dyn MsiDescFuncData>);
132 }
133 
134 /// Data parameter for the `MsiDescFunc` callback.
135 pub trait MsiDescFuncData: Send + Sync + Any {}
136