blob: 57a3b4cd3fc54d3082ffcfeb2163b54a1e9909f9 [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
Zach Reiznerd49bcdb2021-01-07 08:30:28 -08005use base::{error, AsRawDescriptor, Error as SysError, Event, RawDescriptor, Tube, TubeError};
Keiichi Watanabe9ba5f662022-02-08 01:15:02 +09006use bit_field::*;
7use data_model::DataInit;
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
Keiichi Watanabe9ba5f662022-02-08 01:15:02 +090013use crate::pci::{PciCapability, PciCapabilityID};
Zide Chen1d158512019-09-13 14:21:05 -070014
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;
Tinghao Zhang95932f02022-03-22 10:19:50 +080021const MSIX_TABLE_ENTRY_MASK_BIT: u32 = 0x1;
Zide Chen1f204972019-09-17 11:31:53 -070022
Anton Romanovcb3cabe2022-02-03 03:21:33 +000023#[derive(Clone, Default)]
Zide Chen1f204972019-09-17 11:31:53 -070024struct MsixTableEntry {
25 msg_addr_lo: u32,
26 msg_addr_hi: u32,
27 msg_data: u32,
28 vector_ctl: u32,
29}
30
31impl MsixTableEntry {
Zide Chen1f204972019-09-17 11:31:53 -070032 fn masked(&self) -> bool {
Tinghao Zhang95932f02022-03-22 10:19:50 +080033 self.vector_ctl & MSIX_TABLE_ENTRY_MASK_BIT == MSIX_TABLE_ENTRY_MASK_BIT
Zide Chen1f204972019-09-17 11:31:53 -070034 }
35}
36
Zide Chend6be9612019-09-26 11:40:49 -070037struct IrqfdGsi {
Michael Hoyle685316f2020-09-16 15:29:20 -070038 irqfd: Event,
Zide Chend6be9612019-09-26 11:40:49 -070039 gsi: u32,
40}
41
Zide Chen1f204972019-09-17 11:31:53 -070042/// Wrapper over MSI-X Capability Structure and MSI-X Tables
43pub struct MsixConfig {
44 table_entries: Vec<MsixTableEntry>,
45 pba_entries: Vec<u64>,
Tinghao Zhang95932f02022-03-22 10:19:50 +080046 irq_vec: Vec<Option<IrqfdGsi>>,
Zide Chen1f204972019-09-17 11:31:53 -070047 masked: bool,
48 enabled: bool,
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080049 msi_device_socket: Tube,
Zide Chend6be9612019-09-26 11:40:49 -070050 msix_num: u16,
Vikram Auradkar0953c582022-03-21 17:33:54 -070051 pci_id: u32,
52 device_name: String,
Zide Chen1f204972019-09-17 11:31:53 -070053}
54
Daniel Verkamp52253772021-08-18 14:20:23 -070055#[sorted]
56#[derive(Error, Debug)]
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080057enum MsixError {
Daniel Verkamp52253772021-08-18 14:20:23 -070058 #[error("AddMsiRoute failed: {0}")]
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080059 AddMsiRoute(SysError),
Daniel Verkamp52253772021-08-18 14:20:23 -070060 #[error("failed to receive AddMsiRoute response: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080061 AddMsiRouteRecv(TubeError),
Daniel Verkamp52253772021-08-18 14:20:23 -070062 #[error("failed to send AddMsiRoute request: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080063 AddMsiRouteSend(TubeError),
Daniel Verkamp52253772021-08-18 14:20:23 -070064 #[error("AllocateOneMsi failed: {0}")]
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080065 AllocateOneMsi(SysError),
Daniel Verkamp52253772021-08-18 14:20:23 -070066 #[error("failed to receive AllocateOneMsi response: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080067 AllocateOneMsiRecv(TubeError),
Daniel Verkamp52253772021-08-18 14:20:23 -070068 #[error("failed to send AllocateOneMsi request: {0}")]
Zach Reiznerd49bcdb2021-01-07 08:30:28 -080069 AllocateOneMsiSend(TubeError),
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080070}
71
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -080072type MsixResult<T> = std::result::Result<T, MsixError>;
73
Chuanxiao Dong45a94be2020-03-21 09:15:16 +080074pub enum MsixStatus {
75 Changed,
76 EntryChanged(usize),
77 NothingToDo,
78}
79
Zide Chen1f204972019-09-17 11:31:53 -070080impl MsixConfig {
Vikram Auradkar0953c582022-03-21 17:33:54 -070081 pub fn new(msix_vectors: u16, vm_socket: Tube, pci_id: u32, device_name: String) -> Self {
Zide Chen1f204972019-09-17 11:31:53 -070082 assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE);
83
84 let mut table_entries: Vec<MsixTableEntry> = Vec::new();
85 table_entries.resize_with(msix_vectors as usize, Default::default);
Tinghao Zhang95932f02022-03-22 10:19:50 +080086 table_entries
87 .iter_mut()
88 .for_each(|entry| entry.vector_ctl |= MSIX_TABLE_ENTRY_MASK_BIT);
Zide Chen1f204972019-09-17 11:31:53 -070089 let mut pba_entries: Vec<u64> = Vec::new();
Peter Fang9d614072021-06-17 03:16:14 -070090 let num_pba_entries: usize =
91 ((msix_vectors as usize) + BITS_PER_PBA_ENTRY - 1) / BITS_PER_PBA_ENTRY;
Zide Chen1f204972019-09-17 11:31:53 -070092 pba_entries.resize_with(num_pba_entries, Default::default);
93
Tinghao Zhang95932f02022-03-22 10:19:50 +080094 let mut irq_vec = Vec::new();
95 irq_vec.resize_with(msix_vectors.into(), || None::<IrqfdGsi>);
96
Zide Chen1f204972019-09-17 11:31:53 -070097 MsixConfig {
98 table_entries,
99 pba_entries,
Tinghao Zhang95932f02022-03-22 10:19:50 +0800100 irq_vec,
Zide Chen1f204972019-09-17 11:31:53 -0700101 masked: false,
102 enabled: false,
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700103 msi_device_socket: vm_socket,
Zide Chend6be9612019-09-26 11:40:49 -0700104 msix_num: msix_vectors,
Vikram Auradkar0953c582022-03-21 17:33:54 -0700105 pci_id,
106 device_name,
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 {
Tinghao Zhang95932f02022-03-22 10:19:50 +0800169 if let Err(e) = self.msix_enable_all() {
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800170 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
Tinghao Zhang95932f02022-03-22 10:19:50 +0800227 // Enable MSI-X
228 fn msix_enable_all(&mut self) -> MsixResult<()> {
229 for index in 0..self.irq_vec.len() {
230 self.msix_enable_one(index)?;
Zide Chend6be9612019-09-26 11:40:49 -0700231 }
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800232 Ok(())
Zide Chend6be9612019-09-26 11:40:49 -0700233 }
234
Tinghao Zhang95932f02022-03-22 10:19:50 +0800235 // Use a new MSI-X vector
236 // Create a new eventfd and bind them to a new msi
237 fn msix_enable_one(&mut self, index: usize) -> MsixResult<()> {
238 if self.irq_vec[index].is_some()
239 || !self.enabled()
240 || self.masked()
241 || self.table_masked(index)
242 {
243 return Ok(());
244 }
245 let irqfd = Event::new().map_err(MsixError::AllocateOneMsi)?;
Vikram Auradkar0953c582022-03-21 17:33:54 -0700246 let request = VmIrqRequest::AllocateOneMsi {
247 irqfd,
248 device_id: self.pci_id,
249 queue_id: index as usize,
250 device_name: self.device_name.clone(),
251 };
Tinghao Zhang95932f02022-03-22 10:19:50 +0800252 self.msi_device_socket
253 .send(&request)
254 .map_err(MsixError::AllocateOneMsiSend)?;
Daniel Verkampf35f6362022-04-07 17:24:21 -0700255 let irq_num: u32 = match self
Tinghao Zhang95932f02022-03-22 10:19:50 +0800256 .msi_device_socket
257 .recv()
258 .map_err(MsixError::AllocateOneMsiRecv)?
259 {
Daniel Verkampf35f6362022-04-07 17:24:21 -0700260 VmIrqResponse::AllocateOneMsi { gsi } => gsi,
Tinghao Zhang95932f02022-03-22 10:19:50 +0800261 VmIrqResponse::Err(e) => return Err(MsixError::AllocateOneMsi(e)),
262 _ => unreachable!(),
Daniel Verkampf35f6362022-04-07 17:24:21 -0700263 };
Tinghao Zhang95932f02022-03-22 10:19:50 +0800264 self.irq_vec[index] = Some(IrqfdGsi {
265 irqfd: match request {
Vikram Auradkar0953c582022-03-21 17:33:54 -0700266 VmIrqRequest::AllocateOneMsi { irqfd, .. } => irqfd,
Tinghao Zhang95932f02022-03-22 10:19:50 +0800267 _ => unreachable!(),
268 },
269 gsi: irq_num,
270 });
271
272 self.add_msi_route(index as u16, irq_num)?;
273 Ok(())
274 }
275
Zide Chen1f204972019-09-17 11:31:53 -0700276 /// Read MSI-X table
277 /// # Arguments
278 /// * 'offset' - the offset within the MSI-X Table
279 /// * 'data' - used to store the read results
280 ///
281 /// For all accesses to MSI-X Table and MSI-X PBA fields, software must use aligned full
282 /// DWORD or aligned full QWORD transactions; otherwise, the result is undefined.
283 ///
Xiong Zhang3185ae92019-09-05 19:29:30 +0800284 /// location: DWORD3 DWORD2 DWORD1 DWORD0
Zide Chen1f204972019-09-17 11:31:53 -0700285 /// entry 0: Vector Control Msg Data Msg Upper Addr Msg Addr
286 /// entry 1: Vector Control Msg Data Msg Upper Addr Msg Addr
287 /// entry 2: Vector Control Msg Data Msg Upper Addr Msg Addr
288 /// ...
289 pub fn read_msix_table(&self, offset: u64, data: &mut [u8]) {
290 let index: usize = (offset / MSIX_TABLE_ENTRIES_MODULO) as usize;
291 let modulo_offset = offset % MSIX_TABLE_ENTRIES_MODULO;
292
293 match data.len() {
294 4 => {
295 let value = match modulo_offset {
296 0x0 => self.table_entries[index].msg_addr_lo,
297 0x4 => self.table_entries[index].msg_addr_hi,
298 0x8 => self.table_entries[index].msg_data,
299 0xc => self.table_entries[index].vector_ctl,
300 _ => {
301 error!("invalid offset");
302 0
303 }
304 };
305
306 data.copy_from_slice(&value.to_le_bytes());
307 }
308 8 => {
309 let value = match modulo_offset {
310 0x0 => {
311 (u64::from(self.table_entries[index].msg_addr_hi) << 32)
312 | u64::from(self.table_entries[index].msg_addr_lo)
313 }
314 0x8 => {
315 (u64::from(self.table_entries[index].vector_ctl) << 32)
316 | u64::from(self.table_entries[index].msg_data)
317 }
318 _ => {
319 error!("invalid offset");
320 0
321 }
322 };
323
324 data.copy_from_slice(&value.to_le_bytes());
325 }
326 _ => error!("invalid data length"),
327 };
328 }
329
330 /// Write to MSI-X table
331 ///
332 /// Message Address: the contents of this field specifies the address
333 /// for the memory write transaction; different MSI-X vectors have
334 /// different Message Address values
335 /// Message Data: the contents of this field specifies the data driven
Xiong Zhang3185ae92019-09-05 19:29:30 +0800336 /// on AD[31::00] during the memory write transaction's data phase.
Zide Chen1f204972019-09-17 11:31:53 -0700337 /// Vector Control: only bit 0 (Mask Bit) is not reserved: when this bit
338 /// is set, the function is prohibited from sending a message using
339 /// this MSI-X Table entry.
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800340 pub fn write_msix_table(&mut self, offset: u64, data: &[u8]) -> MsixStatus {
Zide Chen1f204972019-09-17 11:31:53 -0700341 let index: usize = (offset / MSIX_TABLE_ENTRIES_MODULO) as usize;
342 let modulo_offset = offset % MSIX_TABLE_ENTRIES_MODULO;
343
Zide Chend6be9612019-09-26 11:40:49 -0700344 // Store the value of the entry before modification
345 let old_entry = self.table_entries[index].clone();
346
Zide Chen1f204972019-09-17 11:31:53 -0700347 match data.len() {
348 4 => {
349 let value = u32::from_le_bytes(data.try_into().unwrap());
350 match modulo_offset {
351 0x0 => self.table_entries[index].msg_addr_lo = value,
352 0x4 => self.table_entries[index].msg_addr_hi = value,
353 0x8 => self.table_entries[index].msg_data = value,
354 0xc => self.table_entries[index].vector_ctl = value,
355 _ => error!("invalid offset"),
356 };
357 }
358 8 => {
359 let value = u64::from_le_bytes(data.try_into().unwrap());
360 match modulo_offset {
361 0x0 => {
362 self.table_entries[index].msg_addr_lo = (value & 0xffff_ffffu64) as u32;
363 self.table_entries[index].msg_addr_hi = (value >> 32) as u32;
364 }
365 0x8 => {
366 self.table_entries[index].msg_data = (value & 0xffff_ffffu64) as u32;
367 self.table_entries[index].vector_ctl = (value >> 32) as u32;
368 }
369 _ => error!("invalid offset"),
370 };
371 }
372 _ => error!("invalid data length"),
373 };
Zide Chend6be9612019-09-26 11:40:49 -0700374
375 let new_entry = self.table_entries[index].clone();
Tinghao Zhang95932f02022-03-22 10:19:50 +0800376
377 // This MSI-X vector is enabled for the first time.
378 if self.enabled()
379 && !self.masked()
380 && self.irq_vec[index].is_none()
381 && old_entry.masked()
382 && !new_entry.masked()
383 {
384 if let Err(e) = self.msix_enable_one(index) {
385 error!("failed to enable MSI-X vector {}: {}", index, e);
386 self.table_entries[index].vector_ctl |= MSIX_TABLE_ENTRY_MASK_BIT;
387 }
388 return MsixStatus::EntryChanged(index);
389 }
390
Zide Chend6be9612019-09-26 11:40:49 -0700391 if self.enabled()
Zide Chend6be9612019-09-26 11:40:49 -0700392 && (old_entry.msg_addr_lo != new_entry.msg_addr_lo
393 || old_entry.msg_addr_hi != new_entry.msg_addr_hi
394 || old_entry.msg_data != new_entry.msg_data)
395 {
Tinghao Zhang95932f02022-03-22 10:19:50 +0800396 if let Some(irqfd_gsi) = &self.irq_vec[index] {
397 let irq_num = irqfd_gsi.gsi;
398 if let Err(e) = self.add_msi_route(index as u16, irq_num) {
399 error!("add_msi_route failed: {}", e);
400 }
Daniel Verkamp1f9c1bb2020-02-20 14:55:24 -0800401 }
Zide Chend6be9612019-09-26 11:40:49 -0700402 }
403
404 // After the MSI-X table entry has been updated, it is necessary to
405 // check if the vector control masking bit has changed. In case the
406 // bit has been flipped from 1 to 0, we need to inject a MSI message
407 // if the corresponding pending bit from the PBA is set. Once the MSI
408 // has been injected, the pending bit in the PBA needs to be cleared.
409 // All of this is valid only if MSI-X has not been masked for the whole
410 // device.
411
412 // Check if bit has been flipped
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800413 if !self.masked() {
414 if old_entry.masked() && !self.table_entries[index].masked() {
415 if self.get_pba_bit(index as u16) == 1 {
416 self.inject_msix_and_clear_pba(index);
417 }
418 return MsixStatus::EntryChanged(index);
419 } else if !old_entry.masked() && self.table_entries[index].masked() {
420 return MsixStatus::EntryChanged(index);
421 }
Zide Chend6be9612019-09-26 11:40:49 -0700422 }
Chuanxiao Dong45a94be2020-03-21 09:15:16 +0800423 MsixStatus::NothingToDo
Zide Chen1f204972019-09-17 11:31:53 -0700424 }
425
426 /// Read PBA Entries
427 /// # Arguments
428 /// * 'offset' - the offset within the PBA entries
429 /// * 'data' - used to store the read results
430 ///
431 /// Pending Bits[63::00]: For each Pending Bit that is set, the function
432 /// has a pending message for the associated MSI-X Table entry.
433 pub fn read_pba_entries(&self, offset: u64, data: &mut [u8]) {
434 let index: usize = (offset / MSIX_PBA_ENTRIES_MODULO) as usize;
435 let modulo_offset = offset % MSIX_PBA_ENTRIES_MODULO;
436
437 match data.len() {
438 4 => {
439 let value: u32 = match modulo_offset {
440 0x0 => (self.pba_entries[index] & 0xffff_ffffu64) as u32,
441 0x4 => (self.pba_entries[index] >> 32) as u32,
442 _ => {
443 error!("invalid offset");
444 0
445 }
446 };
447
448 data.copy_from_slice(&value.to_le_bytes());
449 }
450 8 => {
451 let value: u64 = match modulo_offset {
452 0x0 => self.pba_entries[index],
453 _ => {
454 error!("invalid offset");
455 0
456 }
457 };
458
459 data.copy_from_slice(&value.to_le_bytes());
460 }
461 _ => error!("invalid data length"),
462 }
463 }
464
465 /// Write to PBA Entries
466 ///
467 /// Software should never write, and should only read Pending Bits.
468 /// If software writes to Pending Bits, the result is undefined.
469 pub fn write_pba_entries(&mut self, _offset: u64, _data: &[u8]) {
470 error!("Pending Bit Array is read only");
471 }
472
Zide Chen1f204972019-09-17 11:31:53 -0700473 fn set_pba_bit(&mut self, vector: u16, set: bool) {
474 assert!(vector < MAX_MSIX_VECTORS_PER_DEVICE);
475
476 let index: usize = (vector as usize) / BITS_PER_PBA_ENTRY;
477 let shift: usize = (vector as usize) % BITS_PER_PBA_ENTRY;
478 let mut mask: u64 = (1 << shift) as u64;
479
480 if set {
481 self.pba_entries[index] |= mask;
482 } else {
483 mask = !mask;
484 self.pba_entries[index] &= mask;
485 }
486 }
487
Zide Chen1f204972019-09-17 11:31:53 -0700488 fn get_pba_bit(&self, vector: u16) -> u8 {
489 assert!(vector < MAX_MSIX_VECTORS_PER_DEVICE);
490
491 let index: usize = (vector as usize) / BITS_PER_PBA_ENTRY;
492 let shift: usize = (vector as usize) % BITS_PER_PBA_ENTRY;
493
494 ((self.pba_entries[index] >> shift) & 0x0000_0001u64) as u8
495 }
Zide Chend6be9612019-09-26 11:40:49 -0700496
497 fn inject_msix_and_clear_pba(&mut self, vector: usize) {
Tinghao Zhang95932f02022-03-22 10:19:50 +0800498 if let Some(irq) = &self.irq_vec[vector] {
Zide Chend6be9612019-09-26 11:40:49 -0700499 irq.irqfd.write(1).unwrap();
500 }
501
502 // Clear the bit from PBA
503 self.set_pba_bit(vector as u16, false);
504 }
505
506 /// Inject virtual interrupt to the guest
507 ///
508 /// # Arguments
509 /// * 'vector' - the index to the MSI-X Table entry
510 ///
511 /// PCI Spec 3.0 6.8.3.5: while a vector is masked, the function is
512 /// prohibited from sending the associated message, and the function
513 /// must set the associated Pending bit whenever the function would
514 /// otherwise send the message. When software unmasks a vector whose
515 /// associated Pending bit is set, the function must schedule sending
516 /// the associated message, and clear the Pending bit as soon as the
517 /// message has been sent.
518 ///
519 /// If the vector is unmasked, writing to irqfd which wakes up KVM to
520 /// inject virtual interrupt to the guest.
521 pub fn trigger(&mut self, vector: u16) {
522 if self.table_entries[vector as usize].masked() || self.masked() {
523 self.set_pba_bit(vector, true);
Tinghao Zhang95932f02022-03-22 10:19:50 +0800524 } else if let Some(irq) = self.irq_vec.get(vector as usize).unwrap_or(&None) {
Zide Chend6be9612019-09-26 11:40:49 -0700525 irq.irqfd.write(1).unwrap();
526 }
527 }
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700528
Vikram Auradkar0953c582022-03-21 17:33:54 -0700529 /// Return the raw descriptor of the MSI device socket
Michael Hoylee392c462020-10-07 03:29:24 -0700530 pub fn get_msi_socket(&self) -> RawDescriptor {
Zach Reiznerd49bcdb2021-01-07 08:30:28 -0800531 self.msi_device_socket.as_raw_descriptor()
Xiong Zhanga5d248c2019-09-17 14:17:19 -0700532 }
Xiong Zhang521646a2019-11-08 18:36:55 +0800533
534 /// Return irqfd of MSI-X Table entry
535 ///
536 /// # Arguments
537 /// * 'vector' - the index to the MSI-X table entry
Michael Hoyle685316f2020-09-16 15:29:20 -0700538 pub fn get_irqfd(&self, vector: usize) -> Option<&Event> {
Tinghao Zhang95932f02022-03-22 10:19:50 +0800539 match self.irq_vec.get(vector as usize).unwrap_or(&None) {
Xiong Zhang521646a2019-11-08 18:36:55 +0800540 Some(irq) => Some(&irq.irqfd),
541 None => None,
542 }
543 }
Xiong Zhang4fbc5542021-06-01 11:29:14 +0800544
545 pub fn destroy(&mut self) {
546 while let Some(irq) = self.irq_vec.pop() {
Tinghao Zhang95932f02022-03-22 10:19:50 +0800547 if let Some(irq) = irq {
548 let request = VmIrqRequest::ReleaseOneIrq {
549 gsi: irq.gsi,
550 irqfd: irq.irqfd,
551 };
552 if self.msi_device_socket.send(&request).is_err() {
553 continue;
554 }
555 let _ = self.msi_device_socket.recv::<VmIrqResponse>();
Xiong Zhang4fbc5542021-06-01 11:29:14 +0800556 }
Xiong Zhang4fbc5542021-06-01 11:29:14 +0800557 }
558 }
Zide Chen1f204972019-09-17 11:31:53 -0700559}
Zide Chen1d158512019-09-13 14:21:05 -0700560
Michael Hoylee392c462020-10-07 03:29:24 -0700561impl AsRawDescriptor for MsixConfig {
562 fn as_raw_descriptor(&self) -> RawDescriptor {
563 self.msi_device_socket.as_raw_descriptor()
Daniel Verkamp10154a92020-09-28 17:44:40 -0700564 }
565}
566
Keiichi Watanabe9ba5f662022-02-08 01:15:02 +0900567/// Message Control Register
568// 10-0: MSI-X Table size
569// 13-11: Reserved
570// 14: Mask. Mask all MSI-X when set.
571// 15: Enable. Enable all MSI-X when set.
572// See <https://wiki.osdev.org/PCI#Enabling_MSI-X> for the details.
573#[bitfield]
574#[derive(Copy, Clone, Default)]
575pub struct MsixCtrl {
576 table_size: B10,
577 reserved: B4,
578 mask: B1,
579 enable: B1,
580}
581
Zide Chen1d158512019-09-13 14:21:05 -0700582// It is safe to implement DataInit; all members are simple numbers and any value is valid.
583unsafe impl DataInit for MsixCap {}
584
585#[allow(dead_code)]
586#[repr(C)]
587#[derive(Clone, Copy, Default)]
588/// MSI-X Capability Structure
589pub struct MsixCap {
590 // To make add_capability() happy
591 _cap_vndr: u8,
592 _cap_next: u8,
593 // Message Control Register
Keiichi Watanabe9ba5f662022-02-08 01:15:02 +0900594 msg_ctl: MsixCtrl,
Zide Chen1d158512019-09-13 14:21:05 -0700595 // Table. Contains the offset and the BAR indicator (BIR)
596 // 2-0: Table BAR indicator (BIR). Can be 0 to 5.
597 // 31-3: Table offset in the BAR pointed by the BIR.
598 table: u32,
599 // Pending Bit Array. Contains the offset and the BAR indicator (BIR)
600 // 2-0: PBA BAR indicator (BIR). Can be 0 to 5.
601 // 31-3: PBA offset in the BAR pointed by the BIR.
602 pba: u32,
603}
604
605impl PciCapability for MsixCap {
606 fn bytes(&self) -> &[u8] {
607 self.as_slice()
608 }
609
610 fn id(&self) -> PciCapabilityID {
Dennis Kempinc3dedf32021-11-12 14:42:28 -0800611 PciCapabilityID::Msix
Zide Chen1d158512019-09-13 14:21:05 -0700612 }
Xiong Zhang12274bf2021-05-18 16:53:24 +0800613
614 fn writable_bits(&self) -> Vec<u32> {
615 // Only msg_ctl[15:14] is writable
616 vec![0x3000_0000, 0, 0]
617 }
Zide Chen1d158512019-09-13 14:21:05 -0700618}
619
620impl MsixCap {
621 pub fn new(
622 table_pci_bar: u8,
623 table_size: u16,
624 table_off: u32,
625 pba_pci_bar: u8,
626 pba_off: u32,
627 ) -> Self {
628 assert!(table_size < MAX_MSIX_VECTORS_PER_DEVICE);
629
630 // Set the table size and enable MSI-X.
Keiichi Watanabe9ba5f662022-02-08 01:15:02 +0900631 let mut msg_ctl = MsixCtrl::new();
632 msg_ctl.set_enable(1);
633 // Table Size is N - 1 encoded.
634 msg_ctl.set_table_size(table_size - 1);
Zide Chen1d158512019-09-13 14:21:05 -0700635
636 MsixCap {
637 _cap_vndr: 0,
638 _cap_next: 0,
639 msg_ctl,
640 table: (table_off & 0xffff_fff8u32) | u32::from(table_pci_bar & 0x7u8),
641 pba: (pba_off & 0xffff_fff8u32) | u32::from(pba_pci_bar & 0x7u8),
642 }
643 }
Keiichi Watanabe7bae9ee2022-02-10 01:29:29 +0900644
Vikram Auradkar0953c582022-03-21 17:33:54 -0700645 #[cfg(unix)]
Keiichi Watanabe7bae9ee2022-02-10 01:29:29 +0900646 pub fn msg_ctl(&self) -> MsixCtrl {
647 self.msg_ctl
648 }
Zide Chen1d158512019-09-13 14:21:05 -0700649}