pci_types/capability/
msi.rs1use crate::{capability::PciCapabilityAddress, ConfigRegionAccess};
2use bit_field::BitField;
3use core::convert::TryFrom;
4
5#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
9pub enum MultipleMessageSupport {
10 Int1 = 0b000,
12 Int2 = 0b001,
14 Int4 = 0b010,
16 Int8 = 0b011,
18 Int16 = 0b100,
20 Int32 = 0b101,
22}
23
24impl TryFrom<u8> for MultipleMessageSupport {
25 type Error = ();
26
27 fn try_from(value: u8) -> Result<Self, Self::Error> {
28 match value {
29 0b000 => Ok(MultipleMessageSupport::Int1),
30 0b001 => Ok(MultipleMessageSupport::Int2),
31 0b010 => Ok(MultipleMessageSupport::Int4),
32 0b011 => Ok(MultipleMessageSupport::Int8),
33 0b100 => Ok(MultipleMessageSupport::Int16),
34 0b101 => Ok(MultipleMessageSupport::Int32),
35 _ => Err(()),
36 }
37 }
38}
39
40#[derive(Debug)]
42pub enum TriggerMode {
43 Edge = 0b00,
44 LevelAssert = 0b11,
45 LevelDeassert = 0b10,
46}
47
48#[derive(Debug, Clone, Copy)]
49pub struct MsiCapability {
50 pub(super) address: PciCapabilityAddress,
51 per_vector_masking: bool,
52 is_64bit: bool,
53 multiple_message_capable: MultipleMessageSupport,
54}
55
56impl MsiCapability {
57 pub(crate) fn new(address: PciCapabilityAddress, control: u16) -> MsiCapability {
58 MsiCapability {
59 address,
60 per_vector_masking: control.get_bit(8),
61 is_64bit: control.get_bit(7),
62 multiple_message_capable: MultipleMessageSupport::try_from(control.get_bits(1..4) as u8)
63 .unwrap_or(MultipleMessageSupport::Int1),
64 }
65 }
66
67 #[inline]
69 pub fn has_per_vector_masking(&self) -> bool {
70 self.per_vector_masking
71 }
72
73 #[inline]
75 pub fn is_64bit(&self) -> bool {
76 self.is_64bit
77 }
78
79 #[inline]
81 pub fn multiple_message_capable(&self) -> MultipleMessageSupport {
82 self.multiple_message_capable
83 }
84
85 pub fn ctrl(&self, access: impl ConfigRegionAccess) -> u32 {
86 unsafe { access.read(self.address.address, self.address.offset) }
87 }
88
89 pub fn is_enabled(&self, access: impl ConfigRegionAccess) -> bool {
91 let reg = unsafe { access.read(self.address.address, self.address.offset) };
92 reg.get_bit(16)
93 }
94
95 pub fn set_enabled(&self, enabled: bool, access: impl ConfigRegionAccess) {
97 let mut reg = unsafe { access.read(self.address.address, self.address.offset) };
98 reg.set_bit(16, enabled);
99 unsafe { access.write(self.address.address, self.address.offset, reg) };
100 }
101
102 pub fn set_multiple_message_enable(&self, data: MultipleMessageSupport, access: impl ConfigRegionAccess) {
105 let mut reg = unsafe { access.read(self.address.address, self.address.offset) };
106 reg.set_bits(4..7, (data.min(self.multiple_message_capable)) as u32);
107 unsafe { access.write(self.address.address, self.address.offset, reg) };
108 }
109
110 pub fn multiple_message_enable(&self, access: impl ConfigRegionAccess) -> MultipleMessageSupport {
112 let reg = unsafe { access.read(self.address.address, self.address.offset) };
113 MultipleMessageSupport::try_from(reg.get_bits(4..7) as u8).unwrap_or(MultipleMessageSupport::Int1)
114 }
115
116 pub fn set_message_info(&self, address: u64, data: u32, access: impl ConfigRegionAccess) {
119 unsafe {
120 access.write(self.address.address, self.address.offset + 0x04, address.get_bits(0..32) as u32);
121 if self.is_64bit {
122 access.write(self.address.address, self.address.offset + 0x08, address.get_bits(32..64) as u32);
123 }
124 }
125 let data_offset = if self.is_64bit { 0x0c } else { 0x08 };
126 unsafe {
127 access.write(self.address.address, self.address.offset + data_offset, data);
128 }
129 }
130
131 pub fn set_message_info_lapic(
140 &self,
141 address: u64,
142 vector: u8,
143 trigger_mode: TriggerMode,
144 access: impl ConfigRegionAccess,
145 ) {
146 let mut data = 0;
147 data.set_bits(0..8, vector as u32);
148 data.set_bits(14..16, trigger_mode as u32);
149 self.set_message_info(address, data, access);
150 }
151
152 pub fn message_mask(&self, access: impl ConfigRegionAccess) -> u32 {
158 if self.is_64bit && self.per_vector_masking {
159 unsafe { access.read(self.address.address, self.address.offset + 0x10) }
160 } else {
161 0
162 }
163 }
164
165 pub fn set_message_mask(&self, mask: u32, access: impl ConfigRegionAccess) {
171 if self.is_64bit && self.per_vector_masking {
172 unsafe { access.write(self.address.address, self.address.offset + 0x10, mask) }
173 }
174 }
175
176 pub fn is_pending(&self, access: impl ConfigRegionAccess) -> u32 {
181 if self.is_64bit {
182 unsafe { access.read(self.address.address, self.address.offset + 0x14) }
183 } else {
184 0
185 }
186 }
187}