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