blob: f52fe9bfe31c995625c5293b94c3605616dc608f [file] [log] [blame]
Zide Chen1d158512019-09-13 14:21:05 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::pci::{PciCapability, PciCapabilityID};
Zach Reiznerd49bcdb2021-01-07 08:30:28 -08006use base::{error, AsRawDescriptor, Error as SysError, Event, RawDescriptor, Tube, TubeError};
7
Daniel Verkamp52253772021-08-18 14:20:23 -07008use remain::sorted;
Zide Chen1f204972019-09-17 11:31:53 -07009use std::convert::TryInto;
Daniel Verkamp52253772021-08-18 14:20:23 -070010use thiserror::Error;
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080011use vm_control::{VmIrqRequest, VmIrqResponse};
Zide Chen1d158512019-09-13 14:21:05 -070012
13use data_model::DataInit;
14
15const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048;
Xiong Zhang521646a2019-11-08 18:36:55 +080016pub const MSIX_TABLE_ENTRIES_MODULO: u64 = 16;
17pub const MSIX_PBA_ENTRIES_MODULO: u64 = 8;
18pub const BITS_PER_PBA_ENTRY: usize = 64;
Zide Chen1f204972019-09-17 11:31:53 -070019const FUNCTION_MASK_BIT: u16 = 0x4000;
20const MSIX_ENABLE_BIT: u16 = 0x8000;
21
22#[derive(Clone)]
23struct MsixTableEntry {
24 msg_addr_lo: u32,
25 msg_addr_hi: u32,
26 msg_data: u32,
27 vector_ctl: u32,
28}
29
30impl MsixTableEntry {
Zide Chen1f204972019-09-17 11:31:53 -070031 fn masked(&self) -> bool {
32 self.vector_ctl & 0x1 == 0x1
33 }
34}
35
36impl Default for MsixTableEntry {
37 fn default() -> Self {
38 MsixTableEntry {
39 msg_addr_lo: 0,
40 msg_addr_hi: 0,
41 msg_data: 0,
42 vector_ctl: 0,
43 }
44 }
45}
46
Zide Chend6be9612019-09-26 11:40:49 -070047struct IrqfdGsi {
Michael Hoyle685316f2020-09-16 15:29:20 -070048 irqfd: Event,
Zide Chend6be9612019-09-26 11:40:49 -070049 gsi: u32,
50}
51
Zide Chen1f204972019-09-17 11:31:53 -070052/// Wrapper over MSI-X Capability Structure and MSI-X Tables
53pub struct MsixConfig {
54 table_entries: Vec<MsixTableEntry>,
55 pba_entries: Vec<u64>,
Zide Chend6be9612019-09-26 11:40:49 -070056 irq_vec: Vec<IrqfdGsi>,
Zide Chen1f204972019-09-17 11:31:53 -070057 masked: bool,
58 enabled: bool,
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080059 msi_device_socket: Tube,
Zide Chend6be9612019-09-26 11:40:49 -070060 msix_num: u16,
Zide Chen1f204972019-09-17 11:31:53 -070061}
62
Daniel Verkamp52253772021-08-18 14:20:23 -070063#[sorted]
64#[derive(Error, Debug)]
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080065enum MsixError {
Daniel Verkamp52253772021-08-18 14:20:23 -070066 #[error("AddMsiRoute failed: {0}")]
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080067 AddMsiRoute(SysError),
Daniel Verkamp52253772021-08-18 14:20:23 -070068 #[error("failed to receive AddMsiRoute response: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080069 AddMsiRouteRecv(TubeError),
Daniel Verkamp52253772021-08-18 14:20:23 -070070 #[error("failed to send AddMsiRoute request: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080071 AddMsiRouteSend(TubeError),
Daniel Verkamp52253772021-08-18 14:20:23 -070072 #[error("AllocateOneMsi failed: {0}")]
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080073 AllocateOneMsi(SysError),
Daniel Verkamp52253772021-08-18 14:20:23 -070074 #[error("failed to receive AllocateOneMsi response: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080075 AllocateOneMsiRecv(TubeError),
Daniel Verkamp52253772021-08-18 14:20:23 -070076 #[error("failed to send AllocateOneMsi request: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080077 AllocateOneMsiSend(TubeError),
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080078}
79
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080080type MsixResult<T> = std::result::Result<T, MsixError>;
81
Chuanxiao Dong45a94be2020-03-21 09:15:16 +080082pub enum MsixStatus {
83 Changed,
84 EntryChanged(usize),
85 NothingToDo,
86}
87
Zide Chen1f204972019-09-17 11:31:53 -070088impl MsixConfig {
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080089 pub fn new(msix_vectors: u16, vm_socket: Tube) -> Self {
Zide Chen1f204972019-09-17 11:31:53 -070090 assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE);
91
92 let mut table_entries: Vec<MsixTableEntry> = Vec::new();
93 table_entries.resize_with(msix_vectors as usize, Default::default);
94 let mut pba_entries: Vec<u64> = Vec::new();
Peter Fang9d614072021-06-17 03:16:14 -070095 let num_pba_entries: usize =
96 ((msix_vectors as usize) + BITS_PER_PBA_ENTRY - 1) / BITS_PER_PBA_ENTRY;
Zide Chen1f204972019-09-17 11:31:53 -070097 pba_entries.resize_with(num_pba_entries, Default::default);
98
99 MsixConfig {
100 table_entries,
101 pba_entries,
Zide Chend6be9612019-09-26 11:40:49 -0700102 irq_vec: Vec::new(),
Zide Chen1f204972019-09-17 11:31:53 -0700103 masked: false,
104 enabled: false,
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700105 msi_device_socket: vm_socket,
Zide Chend6be9612019-09-26 11:40:49 -0700106 msix_num: msix_vectors,
Zide Chen1f204972019-09-17 11:31:53 -0700107 }
108 }
109
Daniel Verkampbb712d62019-11-19 09:47:33 -0800110 /// Get the number of MSI-X vectors in this configuration.
111 pub fn num_vectors(&self) -> u16 {
112 self.msix_num
113 }
114
Zide Chen1f204972019-09-17 11:31:53 -0700115 /// Check whether the Function Mask bit in Message Control word in set or not.
116 /// if 1, all of the vectors associated with the function are masked,
117 /// regardless of their per-vector Mask bit states.
Xiong Zhang3185ae92019-09-05 19:29:30 +0800118 /// If 0, each vector's Mask bit determines whether the vector is masked or not.
Zide Chen1f204972019-09-17 11:31:53 -0700119 pub fn masked(&self) -> bool {
120 self.masked
121 }
122
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800123 /// Check whether the Function Mask bit in MSIX table Message Control
124 /// word in set or not.
125 /// If true, the vector is masked.
126 /// If false, the vector is unmasked.
127 pub fn table_masked(&self, index: usize) -> bool {
128 if index >= self.table_entries.len() {
129 true
130 } else {
131 self.table_entries[index].masked()
132 }
133 }
134
Zide Chen1f204972019-09-17 11:31:53 -0700135 /// Check whether the MSI-X Enable bit in Message Control word in set or not.
136 /// if 1, the function is permitted to use MSI-X to request service.
137 pub fn enabled(&self) -> bool {
138 self.enabled
139 }
140
141 /// Read the MSI-X Capability Structure.
142 /// The top 2 bits in Message Control word are emulated and all other
143 /// bits are read only.
144 pub fn read_msix_capability(&self, data: u32) -> u32 {
145 let mut msg_ctl = (data >> 16) as u16;
146 msg_ctl &= !(MSIX_ENABLE_BIT | FUNCTION_MASK_BIT);
147
148 if self.enabled {
149 msg_ctl |= MSIX_ENABLE_BIT;
150 }
151 if self.masked {
152 msg_ctl |= FUNCTION_MASK_BIT;
153 }
154 (msg_ctl as u32) << 16 | (data & u16::max_value() as u32)
155 }
156
157 /// Write to the MSI-X Capability Structure.
158 /// Only the top 2 bits in Message Control Word are writable.
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800159 pub fn write_msix_capability(&mut self, offset: u64, data: &[u8]) -> MsixStatus {
Zide Chen1f204972019-09-17 11:31:53 -0700160 if offset == 2 && data.len() == 2 {
161 let reg = u16::from_le_bytes([data[0], data[1]]);
Zide Chend6be9612019-09-26 11:40:49 -0700162 let old_masked = self.masked;
163 let old_enabled = self.enabled;
Zide Chen1f204972019-09-17 11:31:53 -0700164
165 self.masked = (reg & FUNCTION_MASK_BIT) == FUNCTION_MASK_BIT;
166 self.enabled = (reg & MSIX_ENABLE_BIT) == MSIX_ENABLE_BIT;
Zide Chend6be9612019-09-26 11:40:49 -0700167
168 if !old_enabled && self.enabled {
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800169 if let Err(e) = self.msix_enable() {
170 error!("failed to enable MSI-X: {}", e);
171 self.enabled = false;
172 }
Zide Chend6be9612019-09-26 11:40:49 -0700173 }
174
175 // If the Function Mask bit was set, and has just been cleared, it's
176 // important to go through the entire PBA to check if there was any
177 // pending MSI-X message to inject, given that the vector is not
178 // masked.
179 if old_masked && !self.masked {
180 for (index, entry) in self.table_entries.clone().iter().enumerate() {
181 if !entry.masked() && self.get_pba_bit(index as u16) == 1 {
182 self.inject_msix_and_clear_pba(index);
183 }
184 }
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800185 return MsixStatus::Changed;
186 } else if !old_masked && self.masked {
187 return MsixStatus::Changed;
Zide Chend6be9612019-09-26 11:40:49 -0700188 }
Zide Chen1f204972019-09-17 11:31:53 -0700189 } else {
190 error!(
191 "invalid write to MSI-X Capability Structure offset {:x}",
192 offset
193 );
194 }
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800195 MsixStatus::NothingToDo
Zide Chen1f204972019-09-17 11:31:53 -0700196 }
197
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800198 fn add_msi_route(&self, index: u16, gsi: u32) -> MsixResult<()> {
Zide Chend6be9612019-09-26 11:40:49 -0700199 let mut data: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
200 self.read_msix_table((index * 16).into(), data.as_mut());
201 let msi_address: u64 = u64::from_le_bytes(data);
202 let mut data: [u8; 4] = [0, 0, 0, 0];
203 self.read_msix_table((index * 16 + 8).into(), data.as_mut());
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700204 let msi_data: u32 = u32::from_le_bytes(data);
Zide Chend6be9612019-09-26 11:40:49 -0700205
206 if msi_address == 0 {
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800207 return Ok(());
Zide Chend6be9612019-09-26 11:40:49 -0700208 }
209
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800210 self.msi_device_socket
211 .send(&VmIrqRequest::AddMsiRoute {
212 gsi,
213 msi_address,
214 msi_data,
215 })
216 .map_err(MsixError::AddMsiRouteSend)?;
217 if let VmIrqResponse::Err(e) = self
218 .msi_device_socket
219 .recv()
220 .map_err(MsixError::AddMsiRouteRecv)?
221 {
222 return Err(MsixError::AddMsiRoute(e));
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700223 }
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800224 Ok(())
Zide Chend6be9612019-09-26 11:40:49 -0700225 }
226
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800227 fn msix_enable(&mut self) -> MsixResult<()> {
Zide Chend6be9612019-09-26 11:40:49 -0700228 self.irq_vec.clear();
229 for i in 0..self.msix_num {
Michael Hoyle685316f2020-09-16 15:29:20 -0700230 let irqfd = Event::new().unwrap();
Zach Reiznerd49bcdb2021-01-07 08:30:28 -0800231 let request = VmIrqRequest::AllocateOneMsi { irqfd };
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800232 self.msi_device_socket
Zach Reiznerd49bcdb2021-01-07 08:30:28 -0800233 .send(&request)
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800234 .map_err(MsixError::AllocateOneMsiSend)?;
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700235 let irq_num: u32;
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800236 match self
237 .msi_device_socket
238 .recv()
239 .map_err(MsixError::AllocateOneMsiRecv)?
240 {
241 VmIrqResponse::AllocateOneMsi { gsi } => irq_num = gsi,
242 VmIrqResponse::Err(e) => return Err(MsixError::AllocateOneMsi(e)),
243 _ => unreachable!(),
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700244 }
Zide Chend6be9612019-09-26 11:40:49 -0700245 self.irq_vec.push(IrqfdGsi {
Zach Reiznerd49bcdb2021-01-07 08:30:28 -0800246 irqfd: match request {
247 VmIrqRequest::AllocateOneMsi { irqfd } => irqfd,
248 _ => unreachable!(),
249 },
Zide Chend6be9612019-09-26 11:40:49 -0700250 gsi: irq_num,
251 });
252
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800253 self.add_msi_route(i, irq_num)?;
Zide Chend6be9612019-09-26 11:40:49 -0700254 }
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800255 Ok(())
Zide Chend6be9612019-09-26 11:40:49 -0700256 }
257
Zide Chen1f204972019-09-17 11:31:53 -0700258 /// Read MSI-X table
259 /// # Arguments
260 /// * 'offset' - the offset within the MSI-X Table
261 /// * 'data' - used to store the read results
262 ///
263 /// For all accesses to MSI-X Table and MSI-X PBA fields, software must use aligned full
264 /// DWORD or aligned full QWORD transactions; otherwise, the result is undefined.
265 ///
Xiong Zhang3185ae92019-09-05 19:29:30 +0800266 /// location: DWORD3 DWORD2 DWORD1 DWORD0
Zide Chen1f204972019-09-17 11:31:53 -0700267 /// entry 0: Vector Control Msg Data Msg Upper Addr Msg Addr
268 /// entry 1: Vector Control Msg Data Msg Upper Addr Msg Addr
269 /// entry 2: Vector Control Msg Data Msg Upper Addr Msg Addr
270 /// ...
271 pub fn read_msix_table(&self, offset: u64, data: &mut [u8]) {
272 let index: usize = (offset / MSIX_TABLE_ENTRIES_MODULO) as usize;
273 let modulo_offset = offset % MSIX_TABLE_ENTRIES_MODULO;
274
275 match data.len() {
276 4 => {
277 let value = match modulo_offset {
278 0x0 => self.table_entries[index].msg_addr_lo,
279 0x4 => self.table_entries[index].msg_addr_hi,
280 0x8 => self.table_entries[index].msg_data,
281 0xc => self.table_entries[index].vector_ctl,
282 _ => {
283 error!("invalid offset");
284 0
285 }
286 };
287
288 data.copy_from_slice(&value.to_le_bytes());
289 }
290 8 => {
291 let value = match modulo_offset {
292 0x0 => {
293 (u64::from(self.table_entries[index].msg_addr_hi) << 32)
294 | u64::from(self.table_entries[index].msg_addr_lo)
295 }
296 0x8 => {
297 (u64::from(self.table_entries[index].vector_ctl) << 32)
298 | u64::from(self.table_entries[index].msg_data)
299 }
300 _ => {
301 error!("invalid offset");
302 0
303 }
304 };
305
306 data.copy_from_slice(&value.to_le_bytes());
307 }
308 _ => error!("invalid data length"),
309 };
310 }
311
312 /// Write to MSI-X table
313 ///
314 /// Message Address: the contents of this field specifies the address
315 /// for the memory write transaction; different MSI-X vectors have
316 /// different Message Address values
317 /// Message Data: the contents of this field specifies the data driven
Xiong Zhang3185ae92019-09-05 19:29:30 +0800318 /// on AD[31::00] during the memory write transaction's data phase.
Zide Chen1f204972019-09-17 11:31:53 -0700319 /// Vector Control: only bit 0 (Mask Bit) is not reserved: when this bit
320 /// is set, the function is prohibited from sending a message using
321 /// this MSI-X Table entry.
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800322 pub fn write_msix_table(&mut self, offset: u64, data: &[u8]) -> MsixStatus {
Zide Chen1f204972019-09-17 11:31:53 -0700323 let index: usize = (offset / MSIX_TABLE_ENTRIES_MODULO) as usize;
324 let modulo_offset = offset % MSIX_TABLE_ENTRIES_MODULO;
325
Zide Chend6be9612019-09-26 11:40:49 -0700326 // Store the value of the entry before modification
327 let old_entry = self.table_entries[index].clone();
328
Zide Chen1f204972019-09-17 11:31:53 -0700329 match data.len() {
330 4 => {
331 let value = u32::from_le_bytes(data.try_into().unwrap());
332 match modulo_offset {
333 0x0 => self.table_entries[index].msg_addr_lo = value,
334 0x4 => self.table_entries[index].msg_addr_hi = value,
335 0x8 => self.table_entries[index].msg_data = value,
336 0xc => self.table_entries[index].vector_ctl = value,
337 _ => error!("invalid offset"),
338 };
339 }
340 8 => {
341 let value = u64::from_le_bytes(data.try_into().unwrap());
342 match modulo_offset {
343 0x0 => {
344 self.table_entries[index].msg_addr_lo = (value & 0xffff_ffffu64) as u32;
345 self.table_entries[index].msg_addr_hi = (value >> 32) as u32;
346 }
347 0x8 => {
348 self.table_entries[index].msg_data = (value & 0xffff_ffffu64) as u32;
349 self.table_entries[index].vector_ctl = (value >> 32) as u32;
350 }
351 _ => error!("invalid offset"),
352 };
353 }
354 _ => error!("invalid data length"),
355 };
Zide Chend6be9612019-09-26 11:40:49 -0700356
357 let new_entry = self.table_entries[index].clone();
358 if self.enabled()
Zide Chend6be9612019-09-26 11:40:49 -0700359 && (old_entry.msg_addr_lo != new_entry.msg_addr_lo
360 || old_entry.msg_addr_hi != new_entry.msg_addr_hi
361 || old_entry.msg_data != new_entry.msg_data)
362 {
363 let irq_num = self.irq_vec[index].gsi;
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800364 if let Err(e) = self.add_msi_route(index as u16, irq_num) {
365 error!("add_msi_route failed: {}", e);
366 }
Zide Chend6be9612019-09-26 11:40:49 -0700367 }
368
369 // After the MSI-X table entry has been updated, it is necessary to
370 // check if the vector control masking bit has changed. In case the
371 // bit has been flipped from 1 to 0, we need to inject a MSI message
372 // if the corresponding pending bit from the PBA is set. Once the MSI
373 // has been injected, the pending bit in the PBA needs to be cleared.
374 // All of this is valid only if MSI-X has not been masked for the whole
375 // device.
376
377 // Check if bit has been flipped
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800378 if !self.masked() {
379 if old_entry.masked() && !self.table_entries[index].masked() {
380 if self.get_pba_bit(index as u16) == 1 {
381 self.inject_msix_and_clear_pba(index);
382 }
383 return MsixStatus::EntryChanged(index);
384 } else if !old_entry.masked() && self.table_entries[index].masked() {
385 return MsixStatus::EntryChanged(index);
386 }
Zide Chend6be9612019-09-26 11:40:49 -0700387 }
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800388 MsixStatus::NothingToDo
Zide Chen1f204972019-09-17 11:31:53 -0700389 }
390
391 /// Read PBA Entries
392 /// # Arguments
393 /// * 'offset' - the offset within the PBA entries
394 /// * 'data' - used to store the read results
395 ///
396 /// Pending Bits[63::00]: For each Pending Bit that is set, the function
397 /// has a pending message for the associated MSI-X Table entry.
398 pub fn read_pba_entries(&self, offset: u64, data: &mut [u8]) {
399 let index: usize = (offset / MSIX_PBA_ENTRIES_MODULO) as usize;
400 let modulo_offset = offset % MSIX_PBA_ENTRIES_MODULO;
401
402 match data.len() {
403 4 => {
404 let value: u32 = match modulo_offset {
405 0x0 => (self.pba_entries[index] & 0xffff_ffffu64) as u32,
406 0x4 => (self.pba_entries[index] >> 32) as u32,
407 _ => {
408 error!("invalid offset");
409 0
410 }
411 };
412
413 data.copy_from_slice(&value.to_le_bytes());
414 }
415 8 => {
416 let value: u64 = match modulo_offset {
417 0x0 => self.pba_entries[index],
418 _ => {
419 error!("invalid offset");
420 0
421 }
422 };
423
424 data.copy_from_slice(&value.to_le_bytes());
425 }
426 _ => error!("invalid data length"),
427 }
428 }
429
430 /// Write to PBA Entries
431 ///
432 /// Software should never write, and should only read Pending Bits.
433 /// If software writes to Pending Bits, the result is undefined.
434 pub fn write_pba_entries(&mut self, _offset: u64, _data: &[u8]) {
435 error!("Pending Bit Array is read only");
436 }
437
Zide Chen1f204972019-09-17 11:31:53 -0700438 fn set_pba_bit(&mut self, vector: u16, set: bool) {
439 assert!(vector < MAX_MSIX_VECTORS_PER_DEVICE);
440
441 let index: usize = (vector as usize) / BITS_PER_PBA_ENTRY;
442 let shift: usize = (vector as usize) % BITS_PER_PBA_ENTRY;
443 let mut mask: u64 = (1 << shift) as u64;
444
445 if set {
446 self.pba_entries[index] |= mask;
447 } else {
448 mask = !mask;
449 self.pba_entries[index] &= mask;
450 }
451 }
452
Zide Chen1f204972019-09-17 11:31:53 -0700453 fn get_pba_bit(&self, vector: u16) -> u8 {
454 assert!(vector < MAX_MSIX_VECTORS_PER_DEVICE);
455
456 let index: usize = (vector as usize) / BITS_PER_PBA_ENTRY;
457 let shift: usize = (vector as usize) % BITS_PER_PBA_ENTRY;
458
459 ((self.pba_entries[index] >> shift) & 0x0000_0001u64) as u8
460 }
Zide Chend6be9612019-09-26 11:40:49 -0700461
462 fn inject_msix_and_clear_pba(&mut self, vector: usize) {
463 if let Some(irq) = self.irq_vec.get(vector) {
464 irq.irqfd.write(1).unwrap();
465 }
466
467 // Clear the bit from PBA
468 self.set_pba_bit(vector as u16, false);
469 }
470
471 /// Inject virtual interrupt to the guest
472 ///
473 /// # Arguments
474 /// * 'vector' - the index to the MSI-X Table entry
475 ///
476 /// PCI Spec 3.0 6.8.3.5: while a vector is masked, the function is
477 /// prohibited from sending the associated message, and the function
478 /// must set the associated Pending bit whenever the function would
479 /// otherwise send the message. When software unmasks a vector whose
480 /// associated Pending bit is set, the function must schedule sending
481 /// the associated message, and clear the Pending bit as soon as the
482 /// message has been sent.
483 ///
484 /// If the vector is unmasked, writing to irqfd which wakes up KVM to
485 /// inject virtual interrupt to the guest.
486 pub fn trigger(&mut self, vector: u16) {
487 if self.table_entries[vector as usize].masked() || self.masked() {
488 self.set_pba_bit(vector, true);
489 } else if let Some(irq) = self.irq_vec.get(vector as usize) {
490 irq.irqfd.write(1).unwrap();
491 }
492 }
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700493
494 /// Return the raw fd of the MSI device socket
Michael Hoylee392c462020-10-07 03:29:24 -0700495 pub fn get_msi_socket(&self) -> RawDescriptor {
Zach Reiznerd49bcdb2021-01-07 08:30:28 -0800496 self.msi_device_socket.as_raw_descriptor()
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700497 }
Xiong Zhang521646a2019-11-08 18:36:55 +0800498
499 /// Return irqfd of MSI-X Table entry
500 ///
501 /// # Arguments
502 /// * 'vector' - the index to the MSI-X table entry
Michael Hoyle685316f2020-09-16 15:29:20 -0700503 pub fn get_irqfd(&self, vector: usize) -> Option<&Event> {
Xiong Zhang521646a2019-11-08 18:36:55 +0800504 match self.irq_vec.get(vector) {
505 Some(irq) => Some(&irq.irqfd),
506 None => None,
507 }
508 }
Zide Chen1f204972019-09-17 11:31:53 -0700509}
Zide Chen1d158512019-09-13 14:21:05 -0700510
Michael Hoylee392c462020-10-07 03:29:24 -0700511impl AsRawDescriptor for MsixConfig {
512 fn as_raw_descriptor(&self) -> RawDescriptor {
513 self.msi_device_socket.as_raw_descriptor()
Daniel Verkamp10154a92020-09-28 17:44:40 -0700514 }
515}
516
Zide Chen1d158512019-09-13 14:21:05 -0700517// It is safe to implement DataInit; all members are simple numbers and any value is valid.
518unsafe impl DataInit for MsixCap {}
519
520#[allow(dead_code)]
521#[repr(C)]
522#[derive(Clone, Copy, Default)]
523/// MSI-X Capability Structure
524pub struct MsixCap {
525 // To make add_capability() happy
526 _cap_vndr: u8,
527 _cap_next: u8,
528 // Message Control Register
529 // 10-0: MSI-X Table size
530 // 13-11: Reserved
531 // 14: Mask. Mask all MSI-X when set.
532 // 15: Enable. Enable all MSI-X when set.
533 msg_ctl: u16,
534 // Table. Contains the offset and the BAR indicator (BIR)
535 // 2-0: Table BAR indicator (BIR). Can be 0 to 5.
536 // 31-3: Table offset in the BAR pointed by the BIR.
537 table: u32,
538 // Pending Bit Array. Contains the offset and the BAR indicator (BIR)
539 // 2-0: PBA BAR indicator (BIR). Can be 0 to 5.
540 // 31-3: PBA offset in the BAR pointed by the BIR.
541 pba: u32,
542}
543
544impl PciCapability for MsixCap {
545 fn bytes(&self) -> &[u8] {
546 self.as_slice()
547 }
548
549 fn id(&self) -> PciCapabilityID {
Dennis Kempinc3dedf32021-11-12 14:42:28 -0800550 PciCapabilityID::Msix
Zide Chen1d158512019-09-13 14:21:05 -0700551 }
Xiong Zhang12274bf2021-05-18 16:53:24 +0800552
553 fn writable_bits(&self) -> Vec<u32> {
554 // Only msg_ctl[15:14] is writable
555 vec![0x3000_0000, 0, 0]
556 }
Zide Chen1d158512019-09-13 14:21:05 -0700557}
558
559impl MsixCap {
560 pub fn new(
561 table_pci_bar: u8,
562 table_size: u16,
563 table_off: u32,
564 pba_pci_bar: u8,
565 pba_off: u32,
566 ) -> Self {
567 assert!(table_size < MAX_MSIX_VECTORS_PER_DEVICE);
568
569 // Set the table size and enable MSI-X.
Zide Chen1f204972019-09-17 11:31:53 -0700570 let msg_ctl: u16 = MSIX_ENABLE_BIT + table_size - 1;
Zide Chen1d158512019-09-13 14:21:05 -0700571
572 MsixCap {
573 _cap_vndr: 0,
574 _cap_next: 0,
575 msg_ctl,
576 table: (table_off & 0xffff_fff8u32) | u32::from(table_pci_bar & 0x7u8),
577 pba: (pba_off & 0xffff_fff8u32) | u32::from(pba_pci_bar & 0x7u8),
578 }
579 }
580}