xref: /cloud-hypervisor/pci/src/msi.rs (revision 88a9f799449c04180c6b9a21d3b9c0c4b57e2bd6)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4 //
5 
6 use std::io;
7 use std::sync::Arc;
8 
9 use byteorder::{ByteOrder, LittleEndian};
10 use serde::{Deserialize, Serialize};
11 use thiserror::Error;
12 use vm_device::interrupt::{
13     InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
14 };
15 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
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, Serialize, Deserialize)]
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(Serialize, Deserialize)]
176 pub struct MsiConfigState {
177     cap: MsiCap,
178 }
179 
180 pub struct MsiConfig {
181     pub cap: MsiCap,
182     interrupt_source_group: Arc<dyn InterruptSourceGroup>,
183 }
184 
185 impl MsiConfig {
186     pub fn new(
187         msg_ctl: u16,
188         interrupt_source_group: Arc<dyn InterruptSourceGroup>,
189         state: Option<MsiConfigState>,
190     ) -> Result<Self, Error> {
191         let cap = if let Some(state) = state {
192             if state.cap.enabled() {
193                 for idx in 0..state.cap.num_enabled_vectors() {
194                     let config = MsiIrqSourceConfig {
195                         high_addr: state.cap.msg_addr_hi,
196                         low_addr: state.cap.msg_addr_lo,
197                         data: state.cap.msg_data as u32,
198                         devid: 0,
199                     };
200 
201                     interrupt_source_group
202                         .update(
203                             idx as InterruptIndex,
204                             InterruptSourceConfig::MsiIrq(config),
205                             state.cap.vector_masked(idx),
206                             false,
207                         )
208                         .map_err(Error::UpdateInterruptRoute)?;
209                 }
210 
211                 interrupt_source_group
212                     .set_gsi()
213                     .map_err(Error::EnableInterruptRoute)?;
214 
215                 interrupt_source_group
216                     .enable()
217                     .map_err(Error::EnableInterruptRoute)?;
218             }
219 
220             state.cap
221         } else {
222             MsiCap {
223                 msg_ctl,
224                 ..Default::default()
225             }
226         };
227 
228         Ok(MsiConfig {
229             cap,
230             interrupt_source_group,
231         })
232     }
233 
234     fn state(&self) -> MsiConfigState {
235         MsiConfigState { cap: self.cap }
236     }
237 
238     pub fn enabled(&self) -> bool {
239         self.cap.enabled()
240     }
241 
242     pub fn size(&self) -> u64 {
243         self.cap.size()
244     }
245 
246     pub fn num_enabled_vectors(&self) -> usize {
247         self.cap.num_enabled_vectors()
248     }
249 
250     pub fn update(&mut self, offset: u64, data: &[u8]) {
251         let old_enabled = self.cap.enabled();
252 
253         self.cap.update(offset, data);
254 
255         if self.cap.enabled() {
256             for idx in 0..self.num_enabled_vectors() {
257                 let config = MsiIrqSourceConfig {
258                     high_addr: self.cap.msg_addr_hi,
259                     low_addr: self.cap.msg_addr_lo,
260                     data: self.cap.msg_data as u32,
261                     devid: 0,
262                 };
263 
264                 if let Err(e) = self.interrupt_source_group.update(
265                     idx as InterruptIndex,
266                     InterruptSourceConfig::MsiIrq(config),
267                     self.cap.vector_masked(idx),
268                     true,
269                 ) {
270                     error!("Failed updating vector: {:?}", e);
271                 }
272             }
273 
274             if !old_enabled {
275                 if let Err(e) = self.interrupt_source_group.enable() {
276                     error!("Failed enabling irq_fd: {:?}", e);
277                 }
278             }
279         } else if old_enabled {
280             if let Err(e) = self.interrupt_source_group.disable() {
281                 error!("Failed disabling irq_fd: {:?}", e);
282             }
283         }
284     }
285 }
286 
287 impl Pausable for MsiConfig {}
288 
289 impl Snapshottable for MsiConfig {
290     fn id(&self) -> String {
291         String::from(MSI_CONFIG_ID)
292     }
293 
294     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
295         Snapshot::new_from_state(&self.state())
296     }
297 }
298