xref: /cloud-hypervisor/pci/src/msi.rs (revision 5e52729453cb62edbe4fb3a4aa24f8cca31e667e)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4 //
5 
6 use byteorder::{ByteOrder, LittleEndian};
7 use std::io;
8 use std::sync::Arc;
9 use thiserror::Error;
10 use versionize::{VersionMap, Versionize, VersionizeResult};
11 use versionize_derive::Versionize;
12 use vm_device::interrupt::{
13     InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
14 };
15 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
16 
17 // MSI control masks
18 const MSI_CTL_ENABLE: u16 = 0x1;
19 const MSI_CTL_MULTI_MSG_ENABLE: u16 = 0x70;
20 const MSI_CTL_64_BITS: u16 = 0x80;
21 const MSI_CTL_PER_VECTOR: u16 = 0x100;
22 
23 // MSI message offsets
24 const MSI_MSG_CTL_OFFSET: u64 = 0x2;
25 const MSI_MSG_ADDR_LO_OFFSET: u64 = 0x4;
26 
27 // MSI message masks
28 const MSI_MSG_ADDR_LO_MASK: u32 = 0xffff_fffc;
29 
30 pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
31     let field = (msg_ctl >> 4) & 0x7;
32 
33     if field > 5 {
34         return 0;
35     }
36 
37     1 << field
38 }
39 
40 #[derive(Error, Debug)]
41 pub enum Error {
42     #[error("Failed enabling the interrupt route: {0}")]
43     EnableInterruptRoute(io::Error),
44     #[error("Failed updating the interrupt route: {0}")]
45     UpdateInterruptRoute(io::Error),
46 }
47 
48 pub const MSI_CONFIG_ID: &str = "msi_config";
49 
50 #[derive(Clone, Copy, Default, Versionize)]
51 pub struct MsiCap {
52     // Message Control Register
53     //   0:     MSI enable.
54     //   3-1;   Multiple message capable.
55     //   6-4:   Multiple message enable.
56     //   7:     64 bits address capable.
57     //   8:     Per-vector masking capable.
58     //   15-9:  Reserved.
59     pub msg_ctl: u16,
60     // Message Address (LSB)
61     //   1-0:  Reserved.
62     //   31-2: Message address.
63     pub msg_addr_lo: u32,
64     // Message Upper Address (MSB)
65     //   31-0: Message address.
66     pub msg_addr_hi: u32,
67     // Message Data
68     //   15-0: Message data.
69     pub msg_data: u16,
70     // Mask Bits
71     //   31-0: Mask bits.
72     pub mask_bits: u32,
73     // Pending Bits
74     //   31-0: Pending bits.
75     pub pending_bits: u32,
76 }
77 
78 impl MsiCap {
79     fn addr_64_bits(&self) -> bool {
80         self.msg_ctl & MSI_CTL_64_BITS == MSI_CTL_64_BITS
81     }
82 
83     fn per_vector_mask(&self) -> bool {
84         self.msg_ctl & MSI_CTL_PER_VECTOR == MSI_CTL_PER_VECTOR
85     }
86 
87     fn enabled(&self) -> bool {
88         self.msg_ctl & MSI_CTL_ENABLE == MSI_CTL_ENABLE
89     }
90 
91     fn num_enabled_vectors(&self) -> usize {
92         msi_num_enabled_vectors(self.msg_ctl)
93     }
94 
95     fn vector_masked(&self, vector: usize) -> bool {
96         if !self.per_vector_mask() {
97             return false;
98         }
99 
100         (self.mask_bits >> vector) & 0x1 == 0x1
101     }
102 
103     fn size(&self) -> u64 {
104         let mut size: u64 = 0xa;
105 
106         if self.addr_64_bits() {
107             size += 0x4;
108         }
109         if self.per_vector_mask() {
110             size += 0xa;
111         }
112 
113         size
114     }
115 
116     fn update(&mut self, offset: u64, data: &[u8]) {
117         // Calculate message data offset depending on the address being 32 or
118         // 64 bits.
119         // Calculate upper address offset if the address is 64 bits.
120         // Calculate mask bits offset based on the address being 32 or 64 bits
121         // and based on the per vector masking being enabled or not.
122         let (msg_data_offset, addr_hi_offset, mask_bits_offset): (u64, Option<u64>, Option<u64>) =
123             if self.addr_64_bits() {
124                 let mask_bits = if self.per_vector_mask() {
125                     Some(0x10)
126                 } else {
127                     None
128                 };
129                 (0xc, Some(0x8), mask_bits)
130             } else {
131                 let mask_bits = if self.per_vector_mask() {
132                     Some(0xc)
133                 } else {
134                     None
135                 };
136                 (0x8, None, mask_bits)
137             };
138 
139         // Update cache without overriding the read-only bits.
140         match data.len() {
141             2 => {
142                 let value = LittleEndian::read_u16(data);
143                 match offset {
144                     MSI_MSG_CTL_OFFSET => {
145                         self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
146                             | (value & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
147                     }
148                     x if x == msg_data_offset => self.msg_data = value,
149                     _ => error!("invalid offset"),
150                 }
151             }
152             4 => {
153                 let value = LittleEndian::read_u32(data);
154                 match offset {
155                     0x0 => {
156                         self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
157                             | ((value >> 16) as u16 & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
158                     }
159                     MSI_MSG_ADDR_LO_OFFSET => self.msg_addr_lo = value & MSI_MSG_ADDR_LO_MASK,
160                     x if x == msg_data_offset => self.msg_data = value as u16,
161                     x if addr_hi_offset.is_some() && x == addr_hi_offset.unwrap() => {
162                         self.msg_addr_hi = value
163                     }
164                     x if mask_bits_offset.is_some() && x == mask_bits_offset.unwrap() => {
165                         self.mask_bits = value
166                     }
167                     _ => error!("invalid offset"),
168                 }
169             }
170             _ => error!("invalid data length"),
171         }
172     }
173 }
174 
175 #[derive(Versionize)]
176 pub struct MsiConfigState {
177     cap: MsiCap,
178 }
179 
180 impl VersionMapped for MsiConfigState {}
181 
182 pub struct MsiConfig {
183     pub cap: MsiCap,
184     interrupt_source_group: Arc<dyn InterruptSourceGroup>,
185 }
186 
187 impl MsiConfig {
188     pub fn new(
189         msg_ctl: u16,
190         interrupt_source_group: Arc<dyn InterruptSourceGroup>,
191         state: Option<MsiConfigState>,
192     ) -> Result<Self, Error> {
193         let cap = if let Some(state) = state {
194             if state.cap.enabled() {
195                 for idx in 0..state.cap.num_enabled_vectors() {
196                     let config = MsiIrqSourceConfig {
197                         high_addr: state.cap.msg_addr_hi,
198                         low_addr: state.cap.msg_addr_lo,
199                         data: state.cap.msg_data as u32,
200                         devid: 0,
201                     };
202 
203                     interrupt_source_group
204                         .update(
205                             idx as InterruptIndex,
206                             InterruptSourceConfig::MsiIrq(config),
207                             state.cap.vector_masked(idx),
208                         )
209                         .map_err(Error::UpdateInterruptRoute)?;
210                 }
211 
212                 interrupt_source_group
213                     .enable()
214                     .map_err(Error::EnableInterruptRoute)?;
215             }
216 
217             state.cap
218         } else {
219             MsiCap {
220                 msg_ctl,
221                 ..Default::default()
222             }
223         };
224 
225         Ok(MsiConfig {
226             cap,
227             interrupt_source_group,
228         })
229     }
230 
231     fn state(&self) -> MsiConfigState {
232         MsiConfigState { cap: self.cap }
233     }
234 
235     pub fn enabled(&self) -> bool {
236         self.cap.enabled()
237     }
238 
239     pub fn size(&self) -> u64 {
240         self.cap.size()
241     }
242 
243     pub fn num_enabled_vectors(&self) -> usize {
244         self.cap.num_enabled_vectors()
245     }
246 
247     pub fn update(&mut self, offset: u64, data: &[u8]) {
248         let old_enabled = self.cap.enabled();
249 
250         self.cap.update(offset, data);
251 
252         if self.cap.enabled() {
253             for idx in 0..self.num_enabled_vectors() {
254                 let config = MsiIrqSourceConfig {
255                     high_addr: self.cap.msg_addr_hi,
256                     low_addr: self.cap.msg_addr_lo,
257                     data: self.cap.msg_data as u32,
258                     devid: 0,
259                 };
260 
261                 if let Err(e) = self.interrupt_source_group.update(
262                     idx as InterruptIndex,
263                     InterruptSourceConfig::MsiIrq(config),
264                     self.cap.vector_masked(idx),
265                 ) {
266                     error!("Failed updating vector: {:?}", e);
267                 }
268             }
269 
270             if !old_enabled {
271                 if let Err(e) = self.interrupt_source_group.enable() {
272                     error!("Failed enabling irq_fd: {:?}", e);
273                 }
274             }
275         } else if old_enabled {
276             if let Err(e) = self.interrupt_source_group.disable() {
277                 error!("Failed disabling irq_fd: {:?}", e);
278             }
279         }
280     }
281 }
282 
283 impl Pausable for MsiConfig {}
284 
285 impl Snapshottable for MsiConfig {
286     fn id(&self) -> String {
287         String::from(MSI_CONFIG_ID)
288     }
289 
290     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
291         Snapshot::new_from_versioned_state(&self.state())
292     }
293 }
294