pci_core/capabilities/extended/
acs.rs1use super::PciExtendedCapability;
7use crate::spec::caps::ExtendedCapabilityId;
8use crate::spec::caps::acs::AcsCapabilities;
9use crate::spec::caps::acs::AcsControl;
10use crate::spec::caps::acs::AcsExtendedCapabilityHeader;
11use crate::spec::caps::acs::DEFAULT_ACS_CAP_MASK;
12use chipset_device::pci::ByteEnabledDwordRead;
13use chipset_device::pci::ByteEnabledDwordWrite;
14use inspect::Inspect;
15
16#[derive(Debug, Inspect)]
18pub struct AcsExtendedCapability {
19 capabilities: AcsCapabilities,
20 control: AcsControl,
21}
22
23impl AcsExtendedCapability {
24 pub fn new() -> Self {
26 Self::with_capabilities(DEFAULT_ACS_CAP_MASK)
27 }
28
29 pub fn with_capabilities(capability_bits: u16) -> Self {
31 let capabilities = AcsCapabilities::from_bits(capability_bits);
32
33 Self {
34 capabilities,
35 control: AcsControl::new(),
36 }
37 }
38}
39
40impl PciExtendedCapability for AcsExtendedCapability {
41 fn label(&self) -> &str {
42 "acs"
43 }
44
45 fn extended_capability_id(&self) -> u16 {
46 ExtendedCapabilityId::ACS.0
47 }
48
49 fn capability_version(&self) -> u8 {
50 1
51 }
52
53 fn len(&self) -> usize {
54 12
55 }
56
57 fn read(&self, offset: u16, mut value: ByteEnabledDwordRead<'_>) {
58 match AcsExtendedCapabilityHeader(offset) {
59 AcsExtendedCapabilityHeader::HEADER => {
60 value.set_low_high(
61 self.extended_capability_id(),
62 self.capability_version().into(),
63 );
64 }
65 AcsExtendedCapabilityHeader::CAPS_CONTROL => {
66 value.set_low_high(self.capabilities.into_bits(), self.control.into_bits());
67 }
68 AcsExtendedCapabilityHeader::EGRESS_CONTROL_VECTOR => value.set(0),
69 _ => value.set(!0),
70 }
71 }
72
73 fn write(&mut self, offset: u16, val: ByteEnabledDwordWrite) {
74 match AcsExtendedCapabilityHeader(offset) {
77 AcsExtendedCapabilityHeader::HEADER => {
78 tracelimit::warn_ratelimited!(
79 offset,
80 ?val,
81 "write to read-only ACS extended capability register"
82 );
83 }
84 AcsExtendedCapabilityHeader::CAPS_CONTROL => {
85 self.control = AcsControl::from_bits(
87 val.merge_high(self.control.into_bits()) & self.capabilities.into_bits(),
88 );
89 }
90 AcsExtendedCapabilityHeader::EGRESS_CONTROL_VECTOR => {
91 tracelimit::warn_ratelimited!(
92 offset,
93 ?val,
94 "ACS egress control vector writes are currently not supported; dropping write"
95 );
96 }
97 _ => {
98 tracelimit::warn_ratelimited!(
99 offset,
100 ?val,
101 "unexpected ACS extended capability write"
102 );
103 }
104 }
105 }
106
107 fn reset(&mut self) {
108 self.control = AcsControl::new();
109 }
110}
111
112mod save_restore {
113 use super::*;
114 use vmcore::save_restore::RestoreError;
115 use vmcore::save_restore::SaveError;
116 use vmcore::save_restore::SaveRestore;
117
118 mod state {
119 use mesh::payload::Protobuf;
120 use vmcore::save_restore::SavedStateRoot;
121
122 #[derive(Debug, Protobuf, SavedStateRoot)]
123 #[mesh(package = "pci.capabilities.extended.acs")]
124 pub struct SavedState {
125 #[mesh(1)]
126 pub control: u16,
127 }
128 }
129
130 impl SaveRestore for AcsExtendedCapability {
131 type SavedState = state::SavedState;
132
133 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
134 Ok(state::SavedState {
135 control: self.control.into_bits(),
136 })
137 }
138
139 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
140 self.control = AcsControl::from_bits(state.control & self.capabilities.into_bits());
141 Ok(())
142 }
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::capabilities::extended::assert_extended_header_contract;
150 use crate::test_helpers::read_extended_cap_u32;
151 use crate::test_helpers::write_extended_cap_u32;
152 use vmcore::save_restore::SaveRestore;
153
154 #[test]
155 fn test_acs_defaults() {
156 let cap = AcsExtendedCapability::new();
157
158 assert_eq!(cap.label(), "acs");
159 assert_eq!(cap.extended_capability_id(), ExtendedCapabilityId::ACS.0);
160 assert_eq!(cap.capability_version(), 1);
161 assert_eq!(cap.len(), 12);
162 assert_extended_header_contract(&cap);
163
164 let caps_ctl = read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0);
165 assert_eq!(caps_ctl as u16, DEFAULT_ACS_CAP_MASK);
166 assert_eq!((caps_ctl >> 16) as u16, 0);
167 }
168
169 #[test]
170 fn test_acs_control_write_masks_unsupported_bits() {
171 let mut cap = AcsExtendedCapability::new();
172
173 write_extended_cap_u32(
174 &mut cap,
175 AcsExtendedCapabilityHeader::CAPS_CONTROL.0,
176 0xffff_0000,
177 );
178 let caps_ctl = read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0);
179
180 assert_eq!((caps_ctl >> 16) as u16, DEFAULT_ACS_CAP_MASK);
181 }
182
183 #[test]
184 fn test_acs_reset_clears_control() {
185 let mut cap = AcsExtendedCapability::new();
186
187 write_extended_cap_u32(
188 &mut cap,
189 AcsExtendedCapabilityHeader::CAPS_CONTROL.0,
190 0xffff_0000,
191 );
192 cap.reset();
193
194 let caps_ctl = read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0);
195 assert_eq!((caps_ctl >> 16) as u16, 0);
196 }
197
198 #[test]
199 fn test_acs_save_restore() {
200 let mut cap = AcsExtendedCapability::new();
201 write_extended_cap_u32(
202 &mut cap,
203 AcsExtendedCapabilityHeader::CAPS_CONTROL.0,
204 0xffff_0000,
205 );
206
207 let saved = cap.save().expect("save should succeed");
208
209 cap.reset();
210 assert_eq!(
211 (read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0) >> 16) as u16,
212 0
213 );
214
215 cap.restore(saved).expect("restore should succeed");
216 assert_eq!(
217 (read_extended_cap_u32(&cap, AcsExtendedCapabilityHeader::CAPS_CONTROL.0) >> 16) as u16,
218 DEFAULT_ACS_CAP_MASK
219 );
220 }
221}