1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto; 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context; 8*bb4ee6a4SAndroid Build Coastguard Worker use base::error; 9*bb4ee6a4SAndroid Build Coastguard Worker use base::info; 10*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor; 11*bb4ee6a4SAndroid Build Coastguard Worker use base::Error as SysError; 12*bb4ee6a4SAndroid Build Coastguard Worker use base::Event; 13*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor; 14*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube; 15*bb4ee6a4SAndroid Build Coastguard Worker use base::TubeError; 16*bb4ee6a4SAndroid Build Coastguard Worker use bit_field::*; 17*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted; 18*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize; 19*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize; 20*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error; 21*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmIrqRequest; 22*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmIrqResponse; 23*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes; 24*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes; 25*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes; 26*bb4ee6a4SAndroid Build Coastguard Worker 27*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciCapConfig; 28*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciCapConfigWriteResult; 29*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciCapability; 30*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciCapabilityID; 31*bb4ee6a4SAndroid Build Coastguard Worker 32*bb4ee6a4SAndroid Build Coastguard Worker const MAX_MSIX_VECTORS_PER_DEVICE: u16 = 2048; 33*bb4ee6a4SAndroid Build Coastguard Worker pub const MSIX_TABLE_ENTRIES_MODULO: u64 = 16; 34*bb4ee6a4SAndroid Build Coastguard Worker pub const MSIX_PBA_ENTRIES_MODULO: u64 = 8; 35*bb4ee6a4SAndroid Build Coastguard Worker pub const BITS_PER_PBA_ENTRY: usize = 64; 36*bb4ee6a4SAndroid Build Coastguard Worker const FUNCTION_MASK_BIT: u16 = 0x4000; 37*bb4ee6a4SAndroid Build Coastguard Worker const MSIX_ENABLE_BIT: u16 = 0x8000; 38*bb4ee6a4SAndroid Build Coastguard Worker const MSIX_TABLE_ENTRY_MASK_BIT: u32 = 0x1; 39*bb4ee6a4SAndroid Build Coastguard Worker 40*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize, Clone, Default)] 41*bb4ee6a4SAndroid Build Coastguard Worker struct MsixTableEntry { 42*bb4ee6a4SAndroid Build Coastguard Worker msg_addr_lo: u32, 43*bb4ee6a4SAndroid Build Coastguard Worker msg_addr_hi: u32, 44*bb4ee6a4SAndroid Build Coastguard Worker msg_data: u32, 45*bb4ee6a4SAndroid Build Coastguard Worker vector_ctl: u32, 46*bb4ee6a4SAndroid Build Coastguard Worker } 47*bb4ee6a4SAndroid Build Coastguard Worker 48*bb4ee6a4SAndroid Build Coastguard Worker impl MsixTableEntry { masked(&self) -> bool49*bb4ee6a4SAndroid Build Coastguard Worker fn masked(&self) -> bool { 50*bb4ee6a4SAndroid Build Coastguard Worker self.vector_ctl & MSIX_TABLE_ENTRY_MASK_BIT == MSIX_TABLE_ENTRY_MASK_BIT 51*bb4ee6a4SAndroid Build Coastguard Worker } 52*bb4ee6a4SAndroid Build Coastguard Worker } 53*bb4ee6a4SAndroid Build Coastguard Worker 54*bb4ee6a4SAndroid Build Coastguard Worker struct IrqfdGsi { 55*bb4ee6a4SAndroid Build Coastguard Worker irqfd: Event, 56*bb4ee6a4SAndroid Build Coastguard Worker gsi: u32, 57*bb4ee6a4SAndroid Build Coastguard Worker } 58*bb4ee6a4SAndroid Build Coastguard Worker 59*bb4ee6a4SAndroid Build Coastguard Worker /// Wrapper over MSI-X Capability Structure and MSI-X Tables 60*bb4ee6a4SAndroid Build Coastguard Worker pub struct MsixConfig { 61*bb4ee6a4SAndroid Build Coastguard Worker table_entries: Vec<MsixTableEntry>, 62*bb4ee6a4SAndroid Build Coastguard Worker pba_entries: Vec<u64>, 63*bb4ee6a4SAndroid Build Coastguard Worker irq_vec: Vec<Option<IrqfdGsi>>, 64*bb4ee6a4SAndroid Build Coastguard Worker masked: bool, 65*bb4ee6a4SAndroid Build Coastguard Worker enabled: bool, 66*bb4ee6a4SAndroid Build Coastguard Worker msi_device_socket: Tube, 67*bb4ee6a4SAndroid Build Coastguard Worker msix_num: u16, 68*bb4ee6a4SAndroid Build Coastguard Worker pci_id: u32, 69*bb4ee6a4SAndroid Build Coastguard Worker device_name: String, 70*bb4ee6a4SAndroid Build Coastguard Worker } 71*bb4ee6a4SAndroid Build Coastguard Worker 72*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)] 73*bb4ee6a4SAndroid Build Coastguard Worker struct MsixConfigSnapshot { 74*bb4ee6a4SAndroid Build Coastguard Worker table_entries: Vec<MsixTableEntry>, 75*bb4ee6a4SAndroid Build Coastguard Worker pba_entries: Vec<u64>, 76*bb4ee6a4SAndroid Build Coastguard Worker /// Just like MsixConfig::irq_vec, but only the GSI. 77*bb4ee6a4SAndroid Build Coastguard Worker irq_gsi_vec: Vec<Option<u32>>, 78*bb4ee6a4SAndroid Build Coastguard Worker masked: bool, 79*bb4ee6a4SAndroid Build Coastguard Worker enabled: bool, 80*bb4ee6a4SAndroid Build Coastguard Worker msix_num: u16, 81*bb4ee6a4SAndroid Build Coastguard Worker pci_id: u32, 82*bb4ee6a4SAndroid Build Coastguard Worker device_name: String, 83*bb4ee6a4SAndroid Build Coastguard Worker } 84*bb4ee6a4SAndroid Build Coastguard Worker 85*bb4ee6a4SAndroid Build Coastguard Worker #[sorted] 86*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)] 87*bb4ee6a4SAndroid Build Coastguard Worker pub enum MsixError { 88*bb4ee6a4SAndroid Build Coastguard Worker #[error("AddMsiRoute failed: {0}")] 89*bb4ee6a4SAndroid Build Coastguard Worker AddMsiRoute(SysError), 90*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to receive AddMsiRoute response: {0}")] 91*bb4ee6a4SAndroid Build Coastguard Worker AddMsiRouteRecv(TubeError), 92*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to send AddMsiRoute request: {0}")] 93*bb4ee6a4SAndroid Build Coastguard Worker AddMsiRouteSend(TubeError), 94*bb4ee6a4SAndroid Build Coastguard Worker #[error("AllocateOneMsi failed: {0}")] 95*bb4ee6a4SAndroid Build Coastguard Worker AllocateOneMsi(SysError), 96*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to receive AllocateOneMsi response: {0}")] 97*bb4ee6a4SAndroid Build Coastguard Worker AllocateOneMsiRecv(TubeError), 98*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to send AllocateOneMsi request: {0}")] 99*bb4ee6a4SAndroid Build Coastguard Worker AllocateOneMsiSend(TubeError), 100*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to deserialize snapshot: {0}")] 101*bb4ee6a4SAndroid Build Coastguard Worker DeserializationFailed(serde_json::Error), 102*bb4ee6a4SAndroid Build Coastguard Worker #[error("invalid vector length in snapshot: {0}")] 103*bb4ee6a4SAndroid Build Coastguard Worker InvalidVectorLength(std::num::TryFromIntError), 104*bb4ee6a4SAndroid Build Coastguard Worker #[error("ReleaseOneIrq failed: {0}")] 105*bb4ee6a4SAndroid Build Coastguard Worker ReleaseOneIrq(base::Error), 106*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to receive ReleaseOneIrq response: {0}")] 107*bb4ee6a4SAndroid Build Coastguard Worker ReleaseOneIrqRecv(TubeError), 108*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to send ReleaseOneIrq request: {0}")] 109*bb4ee6a4SAndroid Build Coastguard Worker ReleaseOneIrqSend(TubeError), 110*bb4ee6a4SAndroid Build Coastguard Worker } 111*bb4ee6a4SAndroid Build Coastguard Worker 112*bb4ee6a4SAndroid Build Coastguard Worker type MsixResult<T> = std::result::Result<T, MsixError>; 113*bb4ee6a4SAndroid Build Coastguard Worker 114*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone)] 115*bb4ee6a4SAndroid Build Coastguard Worker pub enum MsixStatus { 116*bb4ee6a4SAndroid Build Coastguard Worker Changed, 117*bb4ee6a4SAndroid Build Coastguard Worker EntryChanged(usize), 118*bb4ee6a4SAndroid Build Coastguard Worker NothingToDo, 119*bb4ee6a4SAndroid Build Coastguard Worker } 120*bb4ee6a4SAndroid Build Coastguard Worker 121*bb4ee6a4SAndroid Build Coastguard Worker impl PciCapConfigWriteResult for MsixStatus {} 122*bb4ee6a4SAndroid Build Coastguard Worker 123*bb4ee6a4SAndroid Build Coastguard Worker impl MsixConfig { new(msix_vectors: u16, vm_socket: Tube, pci_id: u32, device_name: String) -> Self124*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(msix_vectors: u16, vm_socket: Tube, pci_id: u32, device_name: String) -> Self { 125*bb4ee6a4SAndroid Build Coastguard Worker assert!(msix_vectors <= MAX_MSIX_VECTORS_PER_DEVICE); 126*bb4ee6a4SAndroid Build Coastguard Worker 127*bb4ee6a4SAndroid Build Coastguard Worker let mut table_entries: Vec<MsixTableEntry> = Vec::new(); 128*bb4ee6a4SAndroid Build Coastguard Worker table_entries.resize_with(msix_vectors as usize, Default::default); 129*bb4ee6a4SAndroid Build Coastguard Worker table_entries 130*bb4ee6a4SAndroid Build Coastguard Worker .iter_mut() 131*bb4ee6a4SAndroid Build Coastguard Worker .for_each(|entry| entry.vector_ctl |= MSIX_TABLE_ENTRY_MASK_BIT); 132*bb4ee6a4SAndroid Build Coastguard Worker let mut pba_entries: Vec<u64> = Vec::new(); 133*bb4ee6a4SAndroid Build Coastguard Worker let num_pba_entries: usize = 134*bb4ee6a4SAndroid Build Coastguard Worker ((msix_vectors as usize) + BITS_PER_PBA_ENTRY - 1) / BITS_PER_PBA_ENTRY; 135*bb4ee6a4SAndroid Build Coastguard Worker pba_entries.resize_with(num_pba_entries, Default::default); 136*bb4ee6a4SAndroid Build Coastguard Worker 137*bb4ee6a4SAndroid Build Coastguard Worker let mut irq_vec = Vec::new(); 138*bb4ee6a4SAndroid Build Coastguard Worker irq_vec.resize_with(msix_vectors.into(), || None::<IrqfdGsi>); 139*bb4ee6a4SAndroid Build Coastguard Worker 140*bb4ee6a4SAndroid Build Coastguard Worker MsixConfig { 141*bb4ee6a4SAndroid Build Coastguard Worker table_entries, 142*bb4ee6a4SAndroid Build Coastguard Worker pba_entries, 143*bb4ee6a4SAndroid Build Coastguard Worker irq_vec, 144*bb4ee6a4SAndroid Build Coastguard Worker masked: false, 145*bb4ee6a4SAndroid Build Coastguard Worker enabled: false, 146*bb4ee6a4SAndroid Build Coastguard Worker msi_device_socket: vm_socket, 147*bb4ee6a4SAndroid Build Coastguard Worker msix_num: msix_vectors, 148*bb4ee6a4SAndroid Build Coastguard Worker pci_id, 149*bb4ee6a4SAndroid Build Coastguard Worker device_name, 150*bb4ee6a4SAndroid Build Coastguard Worker } 151*bb4ee6a4SAndroid Build Coastguard Worker } 152*bb4ee6a4SAndroid Build Coastguard Worker 153*bb4ee6a4SAndroid Build Coastguard Worker /// Get the number of MSI-X vectors in this configuration. num_vectors(&self) -> u16154*bb4ee6a4SAndroid Build Coastguard Worker pub fn num_vectors(&self) -> u16 { 155*bb4ee6a4SAndroid Build Coastguard Worker self.msix_num 156*bb4ee6a4SAndroid Build Coastguard Worker } 157*bb4ee6a4SAndroid Build Coastguard Worker 158*bb4ee6a4SAndroid Build Coastguard Worker /// Check whether the Function Mask bit in Message Control word in set or not. 159*bb4ee6a4SAndroid Build Coastguard Worker /// if 1, all of the vectors associated with the function are masked, 160*bb4ee6a4SAndroid Build Coastguard Worker /// regardless of their per-vector Mask bit states. 161*bb4ee6a4SAndroid Build Coastguard Worker /// If 0, each vector's Mask bit determines whether the vector is masked or not. masked(&self) -> bool162*bb4ee6a4SAndroid Build Coastguard Worker pub fn masked(&self) -> bool { 163*bb4ee6a4SAndroid Build Coastguard Worker self.masked 164*bb4ee6a4SAndroid Build Coastguard Worker } 165*bb4ee6a4SAndroid Build Coastguard Worker 166*bb4ee6a4SAndroid Build Coastguard Worker /// Check whether the Function Mask bit in MSIX table Message Control 167*bb4ee6a4SAndroid Build Coastguard Worker /// word in set or not. 168*bb4ee6a4SAndroid Build Coastguard Worker /// If true, the vector is masked. 169*bb4ee6a4SAndroid Build Coastguard Worker /// If false, the vector is unmasked. table_masked(&self, index: usize) -> bool170*bb4ee6a4SAndroid Build Coastguard Worker pub fn table_masked(&self, index: usize) -> bool { 171*bb4ee6a4SAndroid Build Coastguard Worker if index >= self.table_entries.len() { 172*bb4ee6a4SAndroid Build Coastguard Worker true 173*bb4ee6a4SAndroid Build Coastguard Worker } else { 174*bb4ee6a4SAndroid Build Coastguard Worker self.table_entries[index].masked() 175*bb4ee6a4SAndroid Build Coastguard Worker } 176*bb4ee6a4SAndroid Build Coastguard Worker } 177*bb4ee6a4SAndroid Build Coastguard Worker 178*bb4ee6a4SAndroid Build Coastguard Worker /// Check whether the MSI-X Enable bit in Message Control word in set or not. 179*bb4ee6a4SAndroid Build Coastguard Worker /// if 1, the function is permitted to use MSI-X to request service. enabled(&self) -> bool180*bb4ee6a4SAndroid Build Coastguard Worker pub fn enabled(&self) -> bool { 181*bb4ee6a4SAndroid Build Coastguard Worker self.enabled 182*bb4ee6a4SAndroid Build Coastguard Worker } 183*bb4ee6a4SAndroid Build Coastguard Worker 184*bb4ee6a4SAndroid Build Coastguard Worker /// Read the MSI-X Capability Structure. 185*bb4ee6a4SAndroid Build Coastguard Worker /// The top 2 bits in Message Control word are emulated and all other 186*bb4ee6a4SAndroid Build Coastguard Worker /// bits are read only. read_msix_capability(&self, data: u32) -> u32187*bb4ee6a4SAndroid Build Coastguard Worker pub fn read_msix_capability(&self, data: u32) -> u32 { 188*bb4ee6a4SAndroid Build Coastguard Worker let mut msg_ctl = (data >> 16) as u16; 189*bb4ee6a4SAndroid Build Coastguard Worker msg_ctl &= !(MSIX_ENABLE_BIT | FUNCTION_MASK_BIT); 190*bb4ee6a4SAndroid Build Coastguard Worker 191*bb4ee6a4SAndroid Build Coastguard Worker if self.enabled { 192*bb4ee6a4SAndroid Build Coastguard Worker msg_ctl |= MSIX_ENABLE_BIT; 193*bb4ee6a4SAndroid Build Coastguard Worker } 194*bb4ee6a4SAndroid Build Coastguard Worker if self.masked { 195*bb4ee6a4SAndroid Build Coastguard Worker msg_ctl |= FUNCTION_MASK_BIT; 196*bb4ee6a4SAndroid Build Coastguard Worker } 197*bb4ee6a4SAndroid Build Coastguard Worker (msg_ctl as u32) << 16 | (data & u16::MAX as u32) 198*bb4ee6a4SAndroid Build Coastguard Worker } 199*bb4ee6a4SAndroid Build Coastguard Worker 200*bb4ee6a4SAndroid Build Coastguard Worker /// Write to the MSI-X Capability Structure. 201*bb4ee6a4SAndroid Build Coastguard Worker /// Only the top 2 bits in Message Control Word are writable. write_msix_capability(&mut self, offset: u64, data: &[u8]) -> MsixStatus202*bb4ee6a4SAndroid Build Coastguard Worker pub fn write_msix_capability(&mut self, offset: u64, data: &[u8]) -> MsixStatus { 203*bb4ee6a4SAndroid Build Coastguard Worker if offset == 2 && data.len() == 2 { 204*bb4ee6a4SAndroid Build Coastguard Worker let reg = u16::from_le_bytes([data[0], data[1]]); 205*bb4ee6a4SAndroid Build Coastguard Worker let old_masked = self.masked; 206*bb4ee6a4SAndroid Build Coastguard Worker let old_enabled = self.enabled; 207*bb4ee6a4SAndroid Build Coastguard Worker 208*bb4ee6a4SAndroid Build Coastguard Worker self.masked = (reg & FUNCTION_MASK_BIT) == FUNCTION_MASK_BIT; 209*bb4ee6a4SAndroid Build Coastguard Worker self.enabled = (reg & MSIX_ENABLE_BIT) == MSIX_ENABLE_BIT; 210*bb4ee6a4SAndroid Build Coastguard Worker 211*bb4ee6a4SAndroid Build Coastguard Worker if !old_enabled && self.enabled { 212*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.msix_enable_all() { 213*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to enable MSI-X: {}", e); 214*bb4ee6a4SAndroid Build Coastguard Worker self.enabled = false; 215*bb4ee6a4SAndroid Build Coastguard Worker } 216*bb4ee6a4SAndroid Build Coastguard Worker } 217*bb4ee6a4SAndroid Build Coastguard Worker 218*bb4ee6a4SAndroid Build Coastguard Worker // If the Function Mask bit was set, and has just been cleared, it's 219*bb4ee6a4SAndroid Build Coastguard Worker // important to go through the entire PBA to check if there was any 220*bb4ee6a4SAndroid Build Coastguard Worker // pending MSI-X message to inject, given that the vector is not 221*bb4ee6a4SAndroid Build Coastguard Worker // masked. 222*bb4ee6a4SAndroid Build Coastguard Worker if old_masked && !self.masked { 223*bb4ee6a4SAndroid Build Coastguard Worker for (index, entry) in self.table_entries.clone().iter().enumerate() { 224*bb4ee6a4SAndroid Build Coastguard Worker if !entry.masked() && self.get_pba_bit(index as u16) == 1 { 225*bb4ee6a4SAndroid Build Coastguard Worker self.inject_msix_and_clear_pba(index); 226*bb4ee6a4SAndroid Build Coastguard Worker } 227*bb4ee6a4SAndroid Build Coastguard Worker } 228*bb4ee6a4SAndroid Build Coastguard Worker return MsixStatus::Changed; 229*bb4ee6a4SAndroid Build Coastguard Worker } else if !old_masked && self.masked { 230*bb4ee6a4SAndroid Build Coastguard Worker return MsixStatus::Changed; 231*bb4ee6a4SAndroid Build Coastguard Worker } 232*bb4ee6a4SAndroid Build Coastguard Worker } else { 233*bb4ee6a4SAndroid Build Coastguard Worker error!( 234*bb4ee6a4SAndroid Build Coastguard Worker "invalid write to MSI-X Capability Structure offset {:x}", 235*bb4ee6a4SAndroid Build Coastguard Worker offset 236*bb4ee6a4SAndroid Build Coastguard Worker ); 237*bb4ee6a4SAndroid Build Coastguard Worker } 238*bb4ee6a4SAndroid Build Coastguard Worker MsixStatus::NothingToDo 239*bb4ee6a4SAndroid Build Coastguard Worker } 240*bb4ee6a4SAndroid Build Coastguard Worker 241*bb4ee6a4SAndroid Build Coastguard Worker /// Create a snapshot of the current MsixConfig struct for use in 242*bb4ee6a4SAndroid Build Coastguard Worker /// snapshotting. snapshot(&mut self) -> anyhow::Result<serde_json::Value>243*bb4ee6a4SAndroid Build Coastguard Worker pub fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> { 244*bb4ee6a4SAndroid Build Coastguard Worker serde_json::to_value(MsixConfigSnapshot { 245*bb4ee6a4SAndroid Build Coastguard Worker table_entries: self.table_entries.clone(), 246*bb4ee6a4SAndroid Build Coastguard Worker pba_entries: self.pba_entries.clone(), 247*bb4ee6a4SAndroid Build Coastguard Worker masked: self.masked, 248*bb4ee6a4SAndroid Build Coastguard Worker enabled: self.enabled, 249*bb4ee6a4SAndroid Build Coastguard Worker msix_num: self.msix_num, 250*bb4ee6a4SAndroid Build Coastguard Worker pci_id: self.pci_id, 251*bb4ee6a4SAndroid Build Coastguard Worker device_name: self.device_name.clone(), 252*bb4ee6a4SAndroid Build Coastguard Worker irq_gsi_vec: self 253*bb4ee6a4SAndroid Build Coastguard Worker .irq_vec 254*bb4ee6a4SAndroid Build Coastguard Worker .iter() 255*bb4ee6a4SAndroid Build Coastguard Worker .map(|irq_opt| irq_opt.as_ref().map(|irq| irq.gsi)) 256*bb4ee6a4SAndroid Build Coastguard Worker .collect(), 257*bb4ee6a4SAndroid Build Coastguard Worker }) 258*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to serialize MsixConfigSnapshot") 259*bb4ee6a4SAndroid Build Coastguard Worker } 260*bb4ee6a4SAndroid Build Coastguard Worker 261*bb4ee6a4SAndroid Build Coastguard Worker /// Restore a MsixConfig struct based on a snapshot. In short, this will 262*bb4ee6a4SAndroid Build Coastguard Worker /// restore all data exposed via MMIO, and recreate all MSI-X vectors (they 263*bb4ee6a4SAndroid Build Coastguard Worker /// will be re-wired to the irq chip). restore(&mut self, snapshot: serde_json::Value) -> MsixResult<()>264*bb4ee6a4SAndroid Build Coastguard Worker pub fn restore(&mut self, snapshot: serde_json::Value) -> MsixResult<()> { 265*bb4ee6a4SAndroid Build Coastguard Worker let snapshot: MsixConfigSnapshot = 266*bb4ee6a4SAndroid Build Coastguard Worker serde_json::from_value(snapshot).map_err(MsixError::DeserializationFailed)?; 267*bb4ee6a4SAndroid Build Coastguard Worker 268*bb4ee6a4SAndroid Build Coastguard Worker self.table_entries = snapshot.table_entries; 269*bb4ee6a4SAndroid Build Coastguard Worker self.pba_entries = snapshot.pba_entries; 270*bb4ee6a4SAndroid Build Coastguard Worker self.masked = snapshot.masked; 271*bb4ee6a4SAndroid Build Coastguard Worker self.enabled = snapshot.enabled; 272*bb4ee6a4SAndroid Build Coastguard Worker self.msix_num = snapshot.msix_num; 273*bb4ee6a4SAndroid Build Coastguard Worker self.pci_id = snapshot.pci_id; 274*bb4ee6a4SAndroid Build Coastguard Worker self.device_name = snapshot.device_name; 275*bb4ee6a4SAndroid Build Coastguard Worker 276*bb4ee6a4SAndroid Build Coastguard Worker self.msix_release_all()?; 277*bb4ee6a4SAndroid Build Coastguard Worker self.irq_vec 278*bb4ee6a4SAndroid Build Coastguard Worker .resize_with(snapshot.irq_gsi_vec.len(), || None::<IrqfdGsi>); 279*bb4ee6a4SAndroid Build Coastguard Worker for (vector, gsi) in snapshot.irq_gsi_vec.iter().enumerate() { 280*bb4ee6a4SAndroid Build Coastguard Worker if let Some(gsi_num) = gsi { 281*bb4ee6a4SAndroid Build Coastguard Worker self.msix_restore_one(vector, *gsi_num)?; 282*bb4ee6a4SAndroid Build Coastguard Worker } else { 283*bb4ee6a4SAndroid Build Coastguard Worker info!( 284*bb4ee6a4SAndroid Build Coastguard Worker "skipping restore of vector {} for device {}", 285*bb4ee6a4SAndroid Build Coastguard Worker vector, self.device_name 286*bb4ee6a4SAndroid Build Coastguard Worker ); 287*bb4ee6a4SAndroid Build Coastguard Worker } 288*bb4ee6a4SAndroid Build Coastguard Worker } 289*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 290*bb4ee6a4SAndroid Build Coastguard Worker } 291*bb4ee6a4SAndroid Build Coastguard Worker 292*bb4ee6a4SAndroid Build Coastguard Worker /// Restore the specified MSI-X vector. 293*bb4ee6a4SAndroid Build Coastguard Worker /// 294*bb4ee6a4SAndroid Build Coastguard Worker /// Note: we skip the checks from [MsixConfig::msix_enable_one] because for 295*bb4ee6a4SAndroid Build Coastguard Worker /// an interrupt to be present in [MsixConfigSnapshot::irq_gsi_vec], it must 296*bb4ee6a4SAndroid Build Coastguard Worker /// have passed those checks. msix_restore_one(&mut self, index: usize, gsi: u32) -> MsixResult<()>297*bb4ee6a4SAndroid Build Coastguard Worker fn msix_restore_one(&mut self, index: usize, gsi: u32) -> MsixResult<()> { 298*bb4ee6a4SAndroid Build Coastguard Worker let irqfd = Event::new().map_err(MsixError::AllocateOneMsi)?; 299*bb4ee6a4SAndroid Build Coastguard Worker let request = VmIrqRequest::AllocateOneMsiAtGsi { 300*bb4ee6a4SAndroid Build Coastguard Worker irqfd, 301*bb4ee6a4SAndroid Build Coastguard Worker gsi, 302*bb4ee6a4SAndroid Build Coastguard Worker device_id: self.pci_id, 303*bb4ee6a4SAndroid Build Coastguard Worker queue_id: index, 304*bb4ee6a4SAndroid Build Coastguard Worker device_name: self.device_name.clone(), 305*bb4ee6a4SAndroid Build Coastguard Worker }; 306*bb4ee6a4SAndroid Build Coastguard Worker self.msi_device_socket 307*bb4ee6a4SAndroid Build Coastguard Worker .send(&request) 308*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::AllocateOneMsiSend)?; 309*bb4ee6a4SAndroid Build Coastguard Worker if let VmIrqResponse::Err(e) = self 310*bb4ee6a4SAndroid Build Coastguard Worker .msi_device_socket 311*bb4ee6a4SAndroid Build Coastguard Worker .recv() 312*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::AllocateOneMsiRecv)? 313*bb4ee6a4SAndroid Build Coastguard Worker { 314*bb4ee6a4SAndroid Build Coastguard Worker return Err(MsixError::AllocateOneMsi(e)); 315*bb4ee6a4SAndroid Build Coastguard Worker }; 316*bb4ee6a4SAndroid Build Coastguard Worker 317*bb4ee6a4SAndroid Build Coastguard Worker self.irq_vec[index] = Some(IrqfdGsi { 318*bb4ee6a4SAndroid Build Coastguard Worker irqfd: match request { 319*bb4ee6a4SAndroid Build Coastguard Worker VmIrqRequest::AllocateOneMsiAtGsi { irqfd, .. } => irqfd, 320*bb4ee6a4SAndroid Build Coastguard Worker _ => unreachable!(), 321*bb4ee6a4SAndroid Build Coastguard Worker }, 322*bb4ee6a4SAndroid Build Coastguard Worker gsi, 323*bb4ee6a4SAndroid Build Coastguard Worker }); 324*bb4ee6a4SAndroid Build Coastguard Worker self.add_msi_route(index as u16, gsi)?; 325*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 326*bb4ee6a4SAndroid Build Coastguard Worker } 327*bb4ee6a4SAndroid Build Coastguard Worker 328*bb4ee6a4SAndroid Build Coastguard Worker /// On warm restore, there could already be MSIs registered. We need to 329*bb4ee6a4SAndroid Build Coastguard Worker /// release them in case the routing has changed (e.g. different 330*bb4ee6a4SAndroid Build Coastguard Worker /// data <-> GSI). msix_release_all(&mut self) -> MsixResult<()>331*bb4ee6a4SAndroid Build Coastguard Worker fn msix_release_all(&mut self) -> MsixResult<()> { 332*bb4ee6a4SAndroid Build Coastguard Worker for irqfd_gsi in self.irq_vec.drain(..).flatten() { 333*bb4ee6a4SAndroid Build Coastguard Worker let request = VmIrqRequest::ReleaseOneIrq { 334*bb4ee6a4SAndroid Build Coastguard Worker gsi: irqfd_gsi.gsi, 335*bb4ee6a4SAndroid Build Coastguard Worker irqfd: irqfd_gsi.irqfd, 336*bb4ee6a4SAndroid Build Coastguard Worker }; 337*bb4ee6a4SAndroid Build Coastguard Worker 338*bb4ee6a4SAndroid Build Coastguard Worker self.msi_device_socket 339*bb4ee6a4SAndroid Build Coastguard Worker .send(&request) 340*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::ReleaseOneIrqSend)?; 341*bb4ee6a4SAndroid Build Coastguard Worker if let VmIrqResponse::Err(e) = self 342*bb4ee6a4SAndroid Build Coastguard Worker .msi_device_socket 343*bb4ee6a4SAndroid Build Coastguard Worker .recv() 344*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::ReleaseOneIrqRecv)? 345*bb4ee6a4SAndroid Build Coastguard Worker { 346*bb4ee6a4SAndroid Build Coastguard Worker return Err(MsixError::ReleaseOneIrq(e)); 347*bb4ee6a4SAndroid Build Coastguard Worker } 348*bb4ee6a4SAndroid Build Coastguard Worker } 349*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 350*bb4ee6a4SAndroid Build Coastguard Worker } 351*bb4ee6a4SAndroid Build Coastguard Worker add_msi_route(&mut self, index: u16, gsi: u32) -> MsixResult<()>352*bb4ee6a4SAndroid Build Coastguard Worker fn add_msi_route(&mut self, index: u16, gsi: u32) -> MsixResult<()> { 353*bb4ee6a4SAndroid Build Coastguard Worker let mut data: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; 354*bb4ee6a4SAndroid Build Coastguard Worker self.read_msix_table((index * 16).into(), data.as_mut()); 355*bb4ee6a4SAndroid Build Coastguard Worker let msi_address: u64 = u64::from_le_bytes(data); 356*bb4ee6a4SAndroid Build Coastguard Worker let mut data: [u8; 4] = [0, 0, 0, 0]; 357*bb4ee6a4SAndroid Build Coastguard Worker self.read_msix_table((index * 16 + 8).into(), data.as_mut()); 358*bb4ee6a4SAndroid Build Coastguard Worker let msi_data: u32 = u32::from_le_bytes(data); 359*bb4ee6a4SAndroid Build Coastguard Worker 360*bb4ee6a4SAndroid Build Coastguard Worker if msi_address == 0 { 361*bb4ee6a4SAndroid Build Coastguard Worker return Ok(()); 362*bb4ee6a4SAndroid Build Coastguard Worker } 363*bb4ee6a4SAndroid Build Coastguard Worker 364*bb4ee6a4SAndroid Build Coastguard Worker self.msi_device_socket 365*bb4ee6a4SAndroid Build Coastguard Worker .send(&VmIrqRequest::AddMsiRoute { 366*bb4ee6a4SAndroid Build Coastguard Worker gsi, 367*bb4ee6a4SAndroid Build Coastguard Worker msi_address, 368*bb4ee6a4SAndroid Build Coastguard Worker msi_data, 369*bb4ee6a4SAndroid Build Coastguard Worker }) 370*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::AddMsiRouteSend)?; 371*bb4ee6a4SAndroid Build Coastguard Worker if let VmIrqResponse::Err(e) = self 372*bb4ee6a4SAndroid Build Coastguard Worker .msi_device_socket 373*bb4ee6a4SAndroid Build Coastguard Worker .recv() 374*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::AddMsiRouteRecv)? 375*bb4ee6a4SAndroid Build Coastguard Worker { 376*bb4ee6a4SAndroid Build Coastguard Worker return Err(MsixError::AddMsiRoute(e)); 377*bb4ee6a4SAndroid Build Coastguard Worker } 378*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 379*bb4ee6a4SAndroid Build Coastguard Worker } 380*bb4ee6a4SAndroid Build Coastguard Worker 381*bb4ee6a4SAndroid Build Coastguard Worker // Enable MSI-X msix_enable_all(&mut self) -> MsixResult<()>382*bb4ee6a4SAndroid Build Coastguard Worker fn msix_enable_all(&mut self) -> MsixResult<()> { 383*bb4ee6a4SAndroid Build Coastguard Worker for index in 0..self.irq_vec.len() { 384*bb4ee6a4SAndroid Build Coastguard Worker self.msix_enable_one(index)?; 385*bb4ee6a4SAndroid Build Coastguard Worker } 386*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 387*bb4ee6a4SAndroid Build Coastguard Worker } 388*bb4ee6a4SAndroid Build Coastguard Worker 389*bb4ee6a4SAndroid Build Coastguard Worker // Use a new MSI-X vector 390*bb4ee6a4SAndroid Build Coastguard Worker // Create a new eventfd and bind them to a new msi msix_enable_one(&mut self, index: usize) -> MsixResult<()>391*bb4ee6a4SAndroid Build Coastguard Worker fn msix_enable_one(&mut self, index: usize) -> MsixResult<()> { 392*bb4ee6a4SAndroid Build Coastguard Worker if self.irq_vec[index].is_some() 393*bb4ee6a4SAndroid Build Coastguard Worker || !self.enabled() 394*bb4ee6a4SAndroid Build Coastguard Worker || self.masked() 395*bb4ee6a4SAndroid Build Coastguard Worker || self.table_masked(index) 396*bb4ee6a4SAndroid Build Coastguard Worker { 397*bb4ee6a4SAndroid Build Coastguard Worker return Ok(()); 398*bb4ee6a4SAndroid Build Coastguard Worker } 399*bb4ee6a4SAndroid Build Coastguard Worker let irqfd = Event::new().map_err(MsixError::AllocateOneMsi)?; 400*bb4ee6a4SAndroid Build Coastguard Worker let request = VmIrqRequest::AllocateOneMsi { 401*bb4ee6a4SAndroid Build Coastguard Worker irqfd, 402*bb4ee6a4SAndroid Build Coastguard Worker device_id: self.pci_id, 403*bb4ee6a4SAndroid Build Coastguard Worker queue_id: index, 404*bb4ee6a4SAndroid Build Coastguard Worker device_name: self.device_name.clone(), 405*bb4ee6a4SAndroid Build Coastguard Worker }; 406*bb4ee6a4SAndroid Build Coastguard Worker self.msi_device_socket 407*bb4ee6a4SAndroid Build Coastguard Worker .send(&request) 408*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::AllocateOneMsiSend)?; 409*bb4ee6a4SAndroid Build Coastguard Worker let irq_num: u32 = match self 410*bb4ee6a4SAndroid Build Coastguard Worker .msi_device_socket 411*bb4ee6a4SAndroid Build Coastguard Worker .recv() 412*bb4ee6a4SAndroid Build Coastguard Worker .map_err(MsixError::AllocateOneMsiRecv)? 413*bb4ee6a4SAndroid Build Coastguard Worker { 414*bb4ee6a4SAndroid Build Coastguard Worker VmIrqResponse::AllocateOneMsi { gsi } => gsi, 415*bb4ee6a4SAndroid Build Coastguard Worker VmIrqResponse::Err(e) => return Err(MsixError::AllocateOneMsi(e)), 416*bb4ee6a4SAndroid Build Coastguard Worker _ => unreachable!(), 417*bb4ee6a4SAndroid Build Coastguard Worker }; 418*bb4ee6a4SAndroid Build Coastguard Worker self.irq_vec[index] = Some(IrqfdGsi { 419*bb4ee6a4SAndroid Build Coastguard Worker irqfd: match request { 420*bb4ee6a4SAndroid Build Coastguard Worker VmIrqRequest::AllocateOneMsi { irqfd, .. } => irqfd, 421*bb4ee6a4SAndroid Build Coastguard Worker _ => unreachable!(), 422*bb4ee6a4SAndroid Build Coastguard Worker }, 423*bb4ee6a4SAndroid Build Coastguard Worker gsi: irq_num, 424*bb4ee6a4SAndroid Build Coastguard Worker }); 425*bb4ee6a4SAndroid Build Coastguard Worker 426*bb4ee6a4SAndroid Build Coastguard Worker self.add_msi_route(index as u16, irq_num)?; 427*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 428*bb4ee6a4SAndroid Build Coastguard Worker } 429*bb4ee6a4SAndroid Build Coastguard Worker 430*bb4ee6a4SAndroid Build Coastguard Worker /// Read MSI-X table 431*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 432*bb4ee6a4SAndroid Build Coastguard Worker /// * 'offset' - the offset within the MSI-X Table 433*bb4ee6a4SAndroid Build Coastguard Worker /// * 'data' - used to store the read results 434*bb4ee6a4SAndroid Build Coastguard Worker /// 435*bb4ee6a4SAndroid Build Coastguard Worker /// For all accesses to MSI-X Table and MSI-X PBA fields, software must use aligned full 436*bb4ee6a4SAndroid Build Coastguard Worker /// DWORD or aligned full QWORD transactions; otherwise, the result is undefined. 437*bb4ee6a4SAndroid Build Coastguard Worker /// 438*bb4ee6a4SAndroid Build Coastguard Worker /// location: DWORD3 DWORD2 DWORD1 DWORD0 439*bb4ee6a4SAndroid Build Coastguard Worker /// entry 0: Vector Control Msg Data Msg Upper Addr Msg Addr 440*bb4ee6a4SAndroid Build Coastguard Worker /// entry 1: Vector Control Msg Data Msg Upper Addr Msg Addr 441*bb4ee6a4SAndroid Build Coastguard Worker /// entry 2: Vector Control Msg Data Msg Upper Addr Msg Addr 442*bb4ee6a4SAndroid Build Coastguard Worker /// ... read_msix_table(&self, offset: u64, data: &mut [u8])443*bb4ee6a4SAndroid Build Coastguard Worker pub fn read_msix_table(&self, offset: u64, data: &mut [u8]) { 444*bb4ee6a4SAndroid Build Coastguard Worker let index: usize = (offset / MSIX_TABLE_ENTRIES_MODULO) as usize; 445*bb4ee6a4SAndroid Build Coastguard Worker let modulo_offset = offset % MSIX_TABLE_ENTRIES_MODULO; 446*bb4ee6a4SAndroid Build Coastguard Worker 447*bb4ee6a4SAndroid Build Coastguard Worker match data.len() { 448*bb4ee6a4SAndroid Build Coastguard Worker 4 => { 449*bb4ee6a4SAndroid Build Coastguard Worker let value = match modulo_offset { 450*bb4ee6a4SAndroid Build Coastguard Worker 0x0 => self.table_entries[index].msg_addr_lo, 451*bb4ee6a4SAndroid Build Coastguard Worker 0x4 => self.table_entries[index].msg_addr_hi, 452*bb4ee6a4SAndroid Build Coastguard Worker 0x8 => self.table_entries[index].msg_data, 453*bb4ee6a4SAndroid Build Coastguard Worker 0xc => self.table_entries[index].vector_ctl, 454*bb4ee6a4SAndroid Build Coastguard Worker _ => { 455*bb4ee6a4SAndroid Build Coastguard Worker error!("invalid offset"); 456*bb4ee6a4SAndroid Build Coastguard Worker 0 457*bb4ee6a4SAndroid Build Coastguard Worker } 458*bb4ee6a4SAndroid Build Coastguard Worker }; 459*bb4ee6a4SAndroid Build Coastguard Worker 460*bb4ee6a4SAndroid Build Coastguard Worker data.copy_from_slice(&value.to_le_bytes()); 461*bb4ee6a4SAndroid Build Coastguard Worker } 462*bb4ee6a4SAndroid Build Coastguard Worker 8 => { 463*bb4ee6a4SAndroid Build Coastguard Worker let value = match modulo_offset { 464*bb4ee6a4SAndroid Build Coastguard Worker 0x0 => { 465*bb4ee6a4SAndroid Build Coastguard Worker (u64::from(self.table_entries[index].msg_addr_hi) << 32) 466*bb4ee6a4SAndroid Build Coastguard Worker | u64::from(self.table_entries[index].msg_addr_lo) 467*bb4ee6a4SAndroid Build Coastguard Worker } 468*bb4ee6a4SAndroid Build Coastguard Worker 0x8 => { 469*bb4ee6a4SAndroid Build Coastguard Worker (u64::from(self.table_entries[index].vector_ctl) << 32) 470*bb4ee6a4SAndroid Build Coastguard Worker | u64::from(self.table_entries[index].msg_data) 471*bb4ee6a4SAndroid Build Coastguard Worker } 472*bb4ee6a4SAndroid Build Coastguard Worker _ => { 473*bb4ee6a4SAndroid Build Coastguard Worker error!("invalid offset"); 474*bb4ee6a4SAndroid Build Coastguard Worker 0 475*bb4ee6a4SAndroid Build Coastguard Worker } 476*bb4ee6a4SAndroid Build Coastguard Worker }; 477*bb4ee6a4SAndroid Build Coastguard Worker 478*bb4ee6a4SAndroid Build Coastguard Worker data.copy_from_slice(&value.to_le_bytes()); 479*bb4ee6a4SAndroid Build Coastguard Worker } 480*bb4ee6a4SAndroid Build Coastguard Worker _ => error!("invalid data length"), 481*bb4ee6a4SAndroid Build Coastguard Worker }; 482*bb4ee6a4SAndroid Build Coastguard Worker } 483*bb4ee6a4SAndroid Build Coastguard Worker 484*bb4ee6a4SAndroid Build Coastguard Worker /// Write to MSI-X table 485*bb4ee6a4SAndroid Build Coastguard Worker /// 486*bb4ee6a4SAndroid Build Coastguard Worker /// Message Address: the contents of this field specifies the address 487*bb4ee6a4SAndroid Build Coastguard Worker /// for the memory write transaction; different MSI-X vectors have 488*bb4ee6a4SAndroid Build Coastguard Worker /// different Message Address values 489*bb4ee6a4SAndroid Build Coastguard Worker /// Message Data: the contents of this field specifies the data driven 490*bb4ee6a4SAndroid Build Coastguard Worker /// on AD\[31::00\] during the memory write transaction's data phase. 491*bb4ee6a4SAndroid Build Coastguard Worker /// Vector Control: only bit 0 (Mask Bit) is not reserved: when this bit 492*bb4ee6a4SAndroid Build Coastguard Worker /// is set, the function is prohibited from sending a message using 493*bb4ee6a4SAndroid Build Coastguard Worker /// this MSI-X Table entry. write_msix_table(&mut self, offset: u64, data: &[u8]) -> MsixStatus494*bb4ee6a4SAndroid Build Coastguard Worker pub fn write_msix_table(&mut self, offset: u64, data: &[u8]) -> MsixStatus { 495*bb4ee6a4SAndroid Build Coastguard Worker let index: usize = (offset / MSIX_TABLE_ENTRIES_MODULO) as usize; 496*bb4ee6a4SAndroid Build Coastguard Worker let modulo_offset = offset % MSIX_TABLE_ENTRIES_MODULO; 497*bb4ee6a4SAndroid Build Coastguard Worker 498*bb4ee6a4SAndroid Build Coastguard Worker // Store the value of the entry before modification 499*bb4ee6a4SAndroid Build Coastguard Worker let old_entry = self.table_entries[index].clone(); 500*bb4ee6a4SAndroid Build Coastguard Worker 501*bb4ee6a4SAndroid Build Coastguard Worker match data.len() { 502*bb4ee6a4SAndroid Build Coastguard Worker 4 => { 503*bb4ee6a4SAndroid Build Coastguard Worker let value = u32::from_le_bytes(data.try_into().unwrap()); 504*bb4ee6a4SAndroid Build Coastguard Worker match modulo_offset { 505*bb4ee6a4SAndroid Build Coastguard Worker 0x0 => self.table_entries[index].msg_addr_lo = value, 506*bb4ee6a4SAndroid Build Coastguard Worker 0x4 => self.table_entries[index].msg_addr_hi = value, 507*bb4ee6a4SAndroid Build Coastguard Worker 0x8 => self.table_entries[index].msg_data = value, 508*bb4ee6a4SAndroid Build Coastguard Worker 0xc => self.table_entries[index].vector_ctl = value, 509*bb4ee6a4SAndroid Build Coastguard Worker _ => error!("invalid offset"), 510*bb4ee6a4SAndroid Build Coastguard Worker }; 511*bb4ee6a4SAndroid Build Coastguard Worker } 512*bb4ee6a4SAndroid Build Coastguard Worker 8 => { 513*bb4ee6a4SAndroid Build Coastguard Worker let value = u64::from_le_bytes(data.try_into().unwrap()); 514*bb4ee6a4SAndroid Build Coastguard Worker match modulo_offset { 515*bb4ee6a4SAndroid Build Coastguard Worker 0x0 => { 516*bb4ee6a4SAndroid Build Coastguard Worker self.table_entries[index].msg_addr_lo = (value & 0xffff_ffffu64) as u32; 517*bb4ee6a4SAndroid Build Coastguard Worker self.table_entries[index].msg_addr_hi = (value >> 32) as u32; 518*bb4ee6a4SAndroid Build Coastguard Worker } 519*bb4ee6a4SAndroid Build Coastguard Worker 0x8 => { 520*bb4ee6a4SAndroid Build Coastguard Worker self.table_entries[index].msg_data = (value & 0xffff_ffffu64) as u32; 521*bb4ee6a4SAndroid Build Coastguard Worker self.table_entries[index].vector_ctl = (value >> 32) as u32; 522*bb4ee6a4SAndroid Build Coastguard Worker } 523*bb4ee6a4SAndroid Build Coastguard Worker _ => error!("invalid offset"), 524*bb4ee6a4SAndroid Build Coastguard Worker }; 525*bb4ee6a4SAndroid Build Coastguard Worker } 526*bb4ee6a4SAndroid Build Coastguard Worker _ => error!("invalid data length"), 527*bb4ee6a4SAndroid Build Coastguard Worker }; 528*bb4ee6a4SAndroid Build Coastguard Worker 529*bb4ee6a4SAndroid Build Coastguard Worker let new_entry = self.table_entries[index].clone(); 530*bb4ee6a4SAndroid Build Coastguard Worker 531*bb4ee6a4SAndroid Build Coastguard Worker // This MSI-X vector is enabled for the first time. 532*bb4ee6a4SAndroid Build Coastguard Worker if self.enabled() 533*bb4ee6a4SAndroid Build Coastguard Worker && !self.masked() 534*bb4ee6a4SAndroid Build Coastguard Worker && self.irq_vec[index].is_none() 535*bb4ee6a4SAndroid Build Coastguard Worker && old_entry.masked() 536*bb4ee6a4SAndroid Build Coastguard Worker && !new_entry.masked() 537*bb4ee6a4SAndroid Build Coastguard Worker { 538*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.msix_enable_one(index) { 539*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to enable MSI-X vector {}: {}", index, e); 540*bb4ee6a4SAndroid Build Coastguard Worker self.table_entries[index].vector_ctl |= MSIX_TABLE_ENTRY_MASK_BIT; 541*bb4ee6a4SAndroid Build Coastguard Worker } 542*bb4ee6a4SAndroid Build Coastguard Worker return MsixStatus::EntryChanged(index); 543*bb4ee6a4SAndroid Build Coastguard Worker } 544*bb4ee6a4SAndroid Build Coastguard Worker 545*bb4ee6a4SAndroid Build Coastguard Worker if self.enabled() 546*bb4ee6a4SAndroid Build Coastguard Worker && (old_entry.msg_addr_lo != new_entry.msg_addr_lo 547*bb4ee6a4SAndroid Build Coastguard Worker || old_entry.msg_addr_hi != new_entry.msg_addr_hi 548*bb4ee6a4SAndroid Build Coastguard Worker || old_entry.msg_data != new_entry.msg_data) 549*bb4ee6a4SAndroid Build Coastguard Worker { 550*bb4ee6a4SAndroid Build Coastguard Worker if let Some(irqfd_gsi) = &self.irq_vec[index] { 551*bb4ee6a4SAndroid Build Coastguard Worker let irq_num = irqfd_gsi.gsi; 552*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = self.add_msi_route(index as u16, irq_num) { 553*bb4ee6a4SAndroid Build Coastguard Worker error!("add_msi_route failed: {}", e); 554*bb4ee6a4SAndroid Build Coastguard Worker } 555*bb4ee6a4SAndroid Build Coastguard Worker } 556*bb4ee6a4SAndroid Build Coastguard Worker } 557*bb4ee6a4SAndroid Build Coastguard Worker 558*bb4ee6a4SAndroid Build Coastguard Worker // After the MSI-X table entry has been updated, it is necessary to 559*bb4ee6a4SAndroid Build Coastguard Worker // check if the vector control masking bit has changed. In case the 560*bb4ee6a4SAndroid Build Coastguard Worker // bit has been flipped from 1 to 0, we need to inject a MSI message 561*bb4ee6a4SAndroid Build Coastguard Worker // if the corresponding pending bit from the PBA is set. Once the MSI 562*bb4ee6a4SAndroid Build Coastguard Worker // has been injected, the pending bit in the PBA needs to be cleared. 563*bb4ee6a4SAndroid Build Coastguard Worker // All of this is valid only if MSI-X has not been masked for the whole 564*bb4ee6a4SAndroid Build Coastguard Worker // device. 565*bb4ee6a4SAndroid Build Coastguard Worker 566*bb4ee6a4SAndroid Build Coastguard Worker // Check if bit has been flipped 567*bb4ee6a4SAndroid Build Coastguard Worker if !self.masked() { 568*bb4ee6a4SAndroid Build Coastguard Worker if old_entry.masked() && !self.table_entries[index].masked() { 569*bb4ee6a4SAndroid Build Coastguard Worker if self.get_pba_bit(index as u16) == 1 { 570*bb4ee6a4SAndroid Build Coastguard Worker self.inject_msix_and_clear_pba(index); 571*bb4ee6a4SAndroid Build Coastguard Worker } 572*bb4ee6a4SAndroid Build Coastguard Worker return MsixStatus::EntryChanged(index); 573*bb4ee6a4SAndroid Build Coastguard Worker } else if !old_entry.masked() && self.table_entries[index].masked() { 574*bb4ee6a4SAndroid Build Coastguard Worker return MsixStatus::EntryChanged(index); 575*bb4ee6a4SAndroid Build Coastguard Worker } 576*bb4ee6a4SAndroid Build Coastguard Worker } 577*bb4ee6a4SAndroid Build Coastguard Worker MsixStatus::NothingToDo 578*bb4ee6a4SAndroid Build Coastguard Worker } 579*bb4ee6a4SAndroid Build Coastguard Worker 580*bb4ee6a4SAndroid Build Coastguard Worker /// Read PBA Entries 581*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 582*bb4ee6a4SAndroid Build Coastguard Worker /// * 'offset' - the offset within the PBA entries 583*bb4ee6a4SAndroid Build Coastguard Worker /// * 'data' - used to store the read results 584*bb4ee6a4SAndroid Build Coastguard Worker /// 585*bb4ee6a4SAndroid Build Coastguard Worker /// Pending Bits\[63::00\]: For each Pending Bit that is set, the function 586*bb4ee6a4SAndroid Build Coastguard Worker /// has a pending message for the associated MSI-X Table entry. read_pba_entries(&self, offset: u64, data: &mut [u8])587*bb4ee6a4SAndroid Build Coastguard Worker pub fn read_pba_entries(&self, offset: u64, data: &mut [u8]) { 588*bb4ee6a4SAndroid Build Coastguard Worker let index: usize = (offset / MSIX_PBA_ENTRIES_MODULO) as usize; 589*bb4ee6a4SAndroid Build Coastguard Worker let modulo_offset = offset % MSIX_PBA_ENTRIES_MODULO; 590*bb4ee6a4SAndroid Build Coastguard Worker 591*bb4ee6a4SAndroid Build Coastguard Worker match data.len() { 592*bb4ee6a4SAndroid Build Coastguard Worker 4 => { 593*bb4ee6a4SAndroid Build Coastguard Worker let value: u32 = match modulo_offset { 594*bb4ee6a4SAndroid Build Coastguard Worker 0x0 => (self.pba_entries[index] & 0xffff_ffffu64) as u32, 595*bb4ee6a4SAndroid Build Coastguard Worker 0x4 => (self.pba_entries[index] >> 32) as u32, 596*bb4ee6a4SAndroid Build Coastguard Worker _ => { 597*bb4ee6a4SAndroid Build Coastguard Worker error!("invalid offset"); 598*bb4ee6a4SAndroid Build Coastguard Worker 0 599*bb4ee6a4SAndroid Build Coastguard Worker } 600*bb4ee6a4SAndroid Build Coastguard Worker }; 601*bb4ee6a4SAndroid Build Coastguard Worker 602*bb4ee6a4SAndroid Build Coastguard Worker data.copy_from_slice(&value.to_le_bytes()); 603*bb4ee6a4SAndroid Build Coastguard Worker } 604*bb4ee6a4SAndroid Build Coastguard Worker 8 => { 605*bb4ee6a4SAndroid Build Coastguard Worker let value: u64 = match modulo_offset { 606*bb4ee6a4SAndroid Build Coastguard Worker 0x0 => self.pba_entries[index], 607*bb4ee6a4SAndroid Build Coastguard Worker _ => { 608*bb4ee6a4SAndroid Build Coastguard Worker error!("invalid offset"); 609*bb4ee6a4SAndroid Build Coastguard Worker 0 610*bb4ee6a4SAndroid Build Coastguard Worker } 611*bb4ee6a4SAndroid Build Coastguard Worker }; 612*bb4ee6a4SAndroid Build Coastguard Worker 613*bb4ee6a4SAndroid Build Coastguard Worker data.copy_from_slice(&value.to_le_bytes()); 614*bb4ee6a4SAndroid Build Coastguard Worker } 615*bb4ee6a4SAndroid Build Coastguard Worker _ => error!("invalid data length"), 616*bb4ee6a4SAndroid Build Coastguard Worker } 617*bb4ee6a4SAndroid Build Coastguard Worker } 618*bb4ee6a4SAndroid Build Coastguard Worker 619*bb4ee6a4SAndroid Build Coastguard Worker /// Write to PBA Entries 620*bb4ee6a4SAndroid Build Coastguard Worker /// 621*bb4ee6a4SAndroid Build Coastguard Worker /// Software should never write, and should only read Pending Bits. 622*bb4ee6a4SAndroid Build Coastguard Worker /// If software writes to Pending Bits, the result is undefined. write_pba_entries(&mut self, _offset: u64, _data: &[u8])623*bb4ee6a4SAndroid Build Coastguard Worker pub fn write_pba_entries(&mut self, _offset: u64, _data: &[u8]) { 624*bb4ee6a4SAndroid Build Coastguard Worker error!("Pending Bit Array is read only"); 625*bb4ee6a4SAndroid Build Coastguard Worker } 626*bb4ee6a4SAndroid Build Coastguard Worker set_pba_bit(&mut self, vector: u16, set: bool)627*bb4ee6a4SAndroid Build Coastguard Worker fn set_pba_bit(&mut self, vector: u16, set: bool) { 628*bb4ee6a4SAndroid Build Coastguard Worker assert!(vector < MAX_MSIX_VECTORS_PER_DEVICE); 629*bb4ee6a4SAndroid Build Coastguard Worker 630*bb4ee6a4SAndroid Build Coastguard Worker let index: usize = (vector as usize) / BITS_PER_PBA_ENTRY; 631*bb4ee6a4SAndroid Build Coastguard Worker let shift: usize = (vector as usize) % BITS_PER_PBA_ENTRY; 632*bb4ee6a4SAndroid Build Coastguard Worker let mut mask: u64 = (1 << shift) as u64; 633*bb4ee6a4SAndroid Build Coastguard Worker 634*bb4ee6a4SAndroid Build Coastguard Worker if set { 635*bb4ee6a4SAndroid Build Coastguard Worker self.pba_entries[index] |= mask; 636*bb4ee6a4SAndroid Build Coastguard Worker } else { 637*bb4ee6a4SAndroid Build Coastguard Worker mask = !mask; 638*bb4ee6a4SAndroid Build Coastguard Worker self.pba_entries[index] &= mask; 639*bb4ee6a4SAndroid Build Coastguard Worker } 640*bb4ee6a4SAndroid Build Coastguard Worker } 641*bb4ee6a4SAndroid Build Coastguard Worker get_pba_bit(&self, vector: u16) -> u8642*bb4ee6a4SAndroid Build Coastguard Worker fn get_pba_bit(&self, vector: u16) -> u8 { 643*bb4ee6a4SAndroid Build Coastguard Worker assert!(vector < MAX_MSIX_VECTORS_PER_DEVICE); 644*bb4ee6a4SAndroid Build Coastguard Worker 645*bb4ee6a4SAndroid Build Coastguard Worker let index: usize = (vector as usize) / BITS_PER_PBA_ENTRY; 646*bb4ee6a4SAndroid Build Coastguard Worker let shift: usize = (vector as usize) % BITS_PER_PBA_ENTRY; 647*bb4ee6a4SAndroid Build Coastguard Worker 648*bb4ee6a4SAndroid Build Coastguard Worker ((self.pba_entries[index] >> shift) & 0x0000_0001u64) as u8 649*bb4ee6a4SAndroid Build Coastguard Worker } 650*bb4ee6a4SAndroid Build Coastguard Worker inject_msix_and_clear_pba(&mut self, vector: usize)651*bb4ee6a4SAndroid Build Coastguard Worker fn inject_msix_and_clear_pba(&mut self, vector: usize) { 652*bb4ee6a4SAndroid Build Coastguard Worker if let Some(irq) = &self.irq_vec[vector] { 653*bb4ee6a4SAndroid Build Coastguard Worker irq.irqfd.signal().unwrap(); 654*bb4ee6a4SAndroid Build Coastguard Worker } 655*bb4ee6a4SAndroid Build Coastguard Worker 656*bb4ee6a4SAndroid Build Coastguard Worker // Clear the bit from PBA 657*bb4ee6a4SAndroid Build Coastguard Worker self.set_pba_bit(vector as u16, false); 658*bb4ee6a4SAndroid Build Coastguard Worker } 659*bb4ee6a4SAndroid Build Coastguard Worker 660*bb4ee6a4SAndroid Build Coastguard Worker /// Inject virtual interrupt to the guest 661*bb4ee6a4SAndroid Build Coastguard Worker /// 662*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 663*bb4ee6a4SAndroid Build Coastguard Worker /// * 'vector' - the index to the MSI-X Table entry 664*bb4ee6a4SAndroid Build Coastguard Worker /// 665*bb4ee6a4SAndroid Build Coastguard Worker /// PCI Spec 3.0 6.8.3.5: while a vector is masked, the function is 666*bb4ee6a4SAndroid Build Coastguard Worker /// prohibited from sending the associated message, and the function 667*bb4ee6a4SAndroid Build Coastguard Worker /// must set the associated Pending bit whenever the function would 668*bb4ee6a4SAndroid Build Coastguard Worker /// otherwise send the message. When software unmasks a vector whose 669*bb4ee6a4SAndroid Build Coastguard Worker /// associated Pending bit is set, the function must schedule sending 670*bb4ee6a4SAndroid Build Coastguard Worker /// the associated message, and clear the Pending bit as soon as the 671*bb4ee6a4SAndroid Build Coastguard Worker /// message has been sent. 672*bb4ee6a4SAndroid Build Coastguard Worker /// 673*bb4ee6a4SAndroid Build Coastguard Worker /// If the vector is unmasked, writing to irqfd which wakes up KVM to 674*bb4ee6a4SAndroid Build Coastguard Worker /// inject virtual interrupt to the guest. trigger(&mut self, vector: u16)675*bb4ee6a4SAndroid Build Coastguard Worker pub fn trigger(&mut self, vector: u16) { 676*bb4ee6a4SAndroid Build Coastguard Worker if self.table_entries[vector as usize].masked() || self.masked() { 677*bb4ee6a4SAndroid Build Coastguard Worker self.set_pba_bit(vector, true); 678*bb4ee6a4SAndroid Build Coastguard Worker } else if let Some(irq) = self.irq_vec.get(vector as usize).unwrap_or(&None) { 679*bb4ee6a4SAndroid Build Coastguard Worker irq.irqfd.signal().unwrap(); 680*bb4ee6a4SAndroid Build Coastguard Worker } 681*bb4ee6a4SAndroid Build Coastguard Worker } 682*bb4ee6a4SAndroid Build Coastguard Worker 683*bb4ee6a4SAndroid Build Coastguard Worker /// Return the raw descriptor of the MSI device socket get_msi_socket(&self) -> RawDescriptor684*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_msi_socket(&self) -> RawDescriptor { 685*bb4ee6a4SAndroid Build Coastguard Worker self.msi_device_socket.as_raw_descriptor() 686*bb4ee6a4SAndroid Build Coastguard Worker } 687*bb4ee6a4SAndroid Build Coastguard Worker 688*bb4ee6a4SAndroid Build Coastguard Worker /// Return irqfd of MSI-X Table entry 689*bb4ee6a4SAndroid Build Coastguard Worker /// 690*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments 691*bb4ee6a4SAndroid Build Coastguard Worker /// * 'vector' - the index to the MSI-X table entry get_irqfd(&self, vector: usize) -> Option<&Event>692*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_irqfd(&self, vector: usize) -> Option<&Event> { 693*bb4ee6a4SAndroid Build Coastguard Worker match self.irq_vec.get(vector).unwrap_or(&None) { 694*bb4ee6a4SAndroid Build Coastguard Worker Some(irq) => Some(&irq.irqfd), 695*bb4ee6a4SAndroid Build Coastguard Worker None => None, 696*bb4ee6a4SAndroid Build Coastguard Worker } 697*bb4ee6a4SAndroid Build Coastguard Worker } 698*bb4ee6a4SAndroid Build Coastguard Worker destroy(&mut self)699*bb4ee6a4SAndroid Build Coastguard Worker pub fn destroy(&mut self) { 700*bb4ee6a4SAndroid Build Coastguard Worker while let Some(irq) = self.irq_vec.pop() { 701*bb4ee6a4SAndroid Build Coastguard Worker if let Some(irq) = irq { 702*bb4ee6a4SAndroid Build Coastguard Worker let request = VmIrqRequest::ReleaseOneIrq { 703*bb4ee6a4SAndroid Build Coastguard Worker gsi: irq.gsi, 704*bb4ee6a4SAndroid Build Coastguard Worker irqfd: irq.irqfd, 705*bb4ee6a4SAndroid Build Coastguard Worker }; 706*bb4ee6a4SAndroid Build Coastguard Worker if self.msi_device_socket.send(&request).is_err() { 707*bb4ee6a4SAndroid Build Coastguard Worker continue; 708*bb4ee6a4SAndroid Build Coastguard Worker } 709*bb4ee6a4SAndroid Build Coastguard Worker let _ = self.msi_device_socket.recv::<VmIrqResponse>(); 710*bb4ee6a4SAndroid Build Coastguard Worker } 711*bb4ee6a4SAndroid Build Coastguard Worker } 712*bb4ee6a4SAndroid Build Coastguard Worker } 713*bb4ee6a4SAndroid Build Coastguard Worker } 714*bb4ee6a4SAndroid Build Coastguard Worker 715*bb4ee6a4SAndroid Build Coastguard Worker const MSIX_CONFIG_READ_MASK: [u32; 3] = [0xc000_0000, 0, 0]; 716*bb4ee6a4SAndroid Build Coastguard Worker 717*bb4ee6a4SAndroid Build Coastguard Worker impl PciCapConfig for MsixConfig { read_mask(&self) -> &'static [u32]718*bb4ee6a4SAndroid Build Coastguard Worker fn read_mask(&self) -> &'static [u32] { 719*bb4ee6a4SAndroid Build Coastguard Worker &MSIX_CONFIG_READ_MASK 720*bb4ee6a4SAndroid Build Coastguard Worker } 721*bb4ee6a4SAndroid Build Coastguard Worker read_reg(&self, reg_idx: usize) -> u32722*bb4ee6a4SAndroid Build Coastguard Worker fn read_reg(&self, reg_idx: usize) -> u32 { 723*bb4ee6a4SAndroid Build Coastguard Worker if reg_idx == 0 { 724*bb4ee6a4SAndroid Build Coastguard Worker self.read_msix_capability(0) 725*bb4ee6a4SAndroid Build Coastguard Worker } else { 726*bb4ee6a4SAndroid Build Coastguard Worker 0 727*bb4ee6a4SAndroid Build Coastguard Worker } 728*bb4ee6a4SAndroid Build Coastguard Worker } 729*bb4ee6a4SAndroid Build Coastguard Worker write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>730*bb4ee6a4SAndroid Build Coastguard Worker fn write_reg( 731*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 732*bb4ee6a4SAndroid Build Coastguard Worker reg_idx: usize, 733*bb4ee6a4SAndroid Build Coastguard Worker offset: u64, 734*bb4ee6a4SAndroid Build Coastguard Worker data: &[u8], 735*bb4ee6a4SAndroid Build Coastguard Worker ) -> Option<Box<dyn PciCapConfigWriteResult>> { 736*bb4ee6a4SAndroid Build Coastguard Worker let status = if reg_idx == 0 { 737*bb4ee6a4SAndroid Build Coastguard Worker self.write_msix_capability(offset, data) 738*bb4ee6a4SAndroid Build Coastguard Worker } else { 739*bb4ee6a4SAndroid Build Coastguard Worker MsixStatus::NothingToDo 740*bb4ee6a4SAndroid Build Coastguard Worker }; 741*bb4ee6a4SAndroid Build Coastguard Worker Some(Box::new(status)) 742*bb4ee6a4SAndroid Build Coastguard Worker } 743*bb4ee6a4SAndroid Build Coastguard Worker } 744*bb4ee6a4SAndroid Build Coastguard Worker 745*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for MsixConfig { as_raw_descriptor(&self) -> RawDescriptor746*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor { 747*bb4ee6a4SAndroid Build Coastguard Worker self.msi_device_socket.as_raw_descriptor() 748*bb4ee6a4SAndroid Build Coastguard Worker } 749*bb4ee6a4SAndroid Build Coastguard Worker } 750*bb4ee6a4SAndroid Build Coastguard Worker 751*bb4ee6a4SAndroid Build Coastguard Worker /// Message Control Register 752*bb4ee6a4SAndroid Build Coastguard Worker // 10-0: MSI-X Table size 753*bb4ee6a4SAndroid Build Coastguard Worker // 13-11: Reserved 754*bb4ee6a4SAndroid Build Coastguard Worker // 14: Mask. Mask all MSI-X when set. 755*bb4ee6a4SAndroid Build Coastguard Worker // 15: Enable. Enable all MSI-X when set. 756*bb4ee6a4SAndroid Build Coastguard Worker // See <https://wiki.osdev.org/PCI#Enabling_MSI-X> for the details. 757*bb4ee6a4SAndroid Build Coastguard Worker #[bitfield] 758*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Default, AsBytes, FromZeroes, FromBytes)] 759*bb4ee6a4SAndroid Build Coastguard Worker pub struct MsixCtrl { 760*bb4ee6a4SAndroid Build Coastguard Worker table_size: B10, 761*bb4ee6a4SAndroid Build Coastguard Worker reserved: B4, 762*bb4ee6a4SAndroid Build Coastguard Worker mask: B1, 763*bb4ee6a4SAndroid Build Coastguard Worker enable: B1, 764*bb4ee6a4SAndroid Build Coastguard Worker } 765*bb4ee6a4SAndroid Build Coastguard Worker 766*bb4ee6a4SAndroid Build Coastguard Worker #[allow(dead_code)] 767*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)] 768*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Default, AsBytes, FromZeroes, FromBytes)] 769*bb4ee6a4SAndroid Build Coastguard Worker /// MSI-X Capability Structure 770*bb4ee6a4SAndroid Build Coastguard Worker pub struct MsixCap { 771*bb4ee6a4SAndroid Build Coastguard Worker // To make add_capability() happy 772*bb4ee6a4SAndroid Build Coastguard Worker _cap_vndr: u8, 773*bb4ee6a4SAndroid Build Coastguard Worker _cap_next: u8, 774*bb4ee6a4SAndroid Build Coastguard Worker // Message Control Register 775*bb4ee6a4SAndroid Build Coastguard Worker msg_ctl: MsixCtrl, 776*bb4ee6a4SAndroid Build Coastguard Worker // Table. Contains the offset and the BAR indicator (BIR) 777*bb4ee6a4SAndroid Build Coastguard Worker // 2-0: Table BAR indicator (BIR). Can be 0 to 5. 778*bb4ee6a4SAndroid Build Coastguard Worker // 31-3: Table offset in the BAR pointed by the BIR. 779*bb4ee6a4SAndroid Build Coastguard Worker table: u32, 780*bb4ee6a4SAndroid Build Coastguard Worker // Pending Bit Array. Contains the offset and the BAR indicator (BIR) 781*bb4ee6a4SAndroid Build Coastguard Worker // 2-0: PBA BAR indicator (BIR). Can be 0 to 5. 782*bb4ee6a4SAndroid Build Coastguard Worker // 31-3: PBA offset in the BAR pointed by the BIR. 783*bb4ee6a4SAndroid Build Coastguard Worker pba: u32, 784*bb4ee6a4SAndroid Build Coastguard Worker } 785*bb4ee6a4SAndroid Build Coastguard Worker 786*bb4ee6a4SAndroid Build Coastguard Worker impl PciCapability for MsixCap { bytes(&self) -> &[u8]787*bb4ee6a4SAndroid Build Coastguard Worker fn bytes(&self) -> &[u8] { 788*bb4ee6a4SAndroid Build Coastguard Worker self.as_bytes() 789*bb4ee6a4SAndroid Build Coastguard Worker } 790*bb4ee6a4SAndroid Build Coastguard Worker id(&self) -> PciCapabilityID791*bb4ee6a4SAndroid Build Coastguard Worker fn id(&self) -> PciCapabilityID { 792*bb4ee6a4SAndroid Build Coastguard Worker PciCapabilityID::Msix 793*bb4ee6a4SAndroid Build Coastguard Worker } 794*bb4ee6a4SAndroid Build Coastguard Worker writable_bits(&self) -> Vec<u32>795*bb4ee6a4SAndroid Build Coastguard Worker fn writable_bits(&self) -> Vec<u32> { 796*bb4ee6a4SAndroid Build Coastguard Worker // Only msg_ctl[15:14] is writable 797*bb4ee6a4SAndroid Build Coastguard Worker vec![0x3000_0000, 0, 0] 798*bb4ee6a4SAndroid Build Coastguard Worker } 799*bb4ee6a4SAndroid Build Coastguard Worker } 800*bb4ee6a4SAndroid Build Coastguard Worker 801*bb4ee6a4SAndroid Build Coastguard Worker impl MsixCap { new( table_pci_bar: u8, table_size: u16, table_off: u32, pba_pci_bar: u8, pba_off: u32, ) -> Self802*bb4ee6a4SAndroid Build Coastguard Worker pub fn new( 803*bb4ee6a4SAndroid Build Coastguard Worker table_pci_bar: u8, 804*bb4ee6a4SAndroid Build Coastguard Worker table_size: u16, 805*bb4ee6a4SAndroid Build Coastguard Worker table_off: u32, 806*bb4ee6a4SAndroid Build Coastguard Worker pba_pci_bar: u8, 807*bb4ee6a4SAndroid Build Coastguard Worker pba_off: u32, 808*bb4ee6a4SAndroid Build Coastguard Worker ) -> Self { 809*bb4ee6a4SAndroid Build Coastguard Worker assert!(table_size < MAX_MSIX_VECTORS_PER_DEVICE); 810*bb4ee6a4SAndroid Build Coastguard Worker 811*bb4ee6a4SAndroid Build Coastguard Worker // Set the table size and enable MSI-X. 812*bb4ee6a4SAndroid Build Coastguard Worker let mut msg_ctl = MsixCtrl::new(); 813*bb4ee6a4SAndroid Build Coastguard Worker msg_ctl.set_enable(1); 814*bb4ee6a4SAndroid Build Coastguard Worker // Table Size is N - 1 encoded. 815*bb4ee6a4SAndroid Build Coastguard Worker msg_ctl.set_table_size(table_size - 1); 816*bb4ee6a4SAndroid Build Coastguard Worker 817*bb4ee6a4SAndroid Build Coastguard Worker MsixCap { 818*bb4ee6a4SAndroid Build Coastguard Worker _cap_vndr: 0, 819*bb4ee6a4SAndroid Build Coastguard Worker _cap_next: 0, 820*bb4ee6a4SAndroid Build Coastguard Worker msg_ctl, 821*bb4ee6a4SAndroid Build Coastguard Worker table: (table_off & 0xffff_fff8u32) | u32::from(table_pci_bar & 0x7u8), 822*bb4ee6a4SAndroid Build Coastguard Worker pba: (pba_off & 0xffff_fff8u32) | u32::from(pba_pci_bar & 0x7u8), 823*bb4ee6a4SAndroid Build Coastguard Worker } 824*bb4ee6a4SAndroid Build Coastguard Worker } 825*bb4ee6a4SAndroid Build Coastguard Worker } 826*bb4ee6a4SAndroid Build Coastguard Worker 827*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 828*bb4ee6a4SAndroid Build Coastguard Worker mod tests { 829*bb4ee6a4SAndroid Build Coastguard Worker 830*bb4ee6a4SAndroid Build Coastguard Worker use std::thread; 831*bb4ee6a4SAndroid Build Coastguard Worker 832*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 833*bb4ee6a4SAndroid Build Coastguard Worker 834*bb4ee6a4SAndroid Build Coastguard Worker #[track_caller] recv_allocate_msi(t: &Tube) -> u32835*bb4ee6a4SAndroid Build Coastguard Worker fn recv_allocate_msi(t: &Tube) -> u32 { 836*bb4ee6a4SAndroid Build Coastguard Worker match t.recv::<VmIrqRequest>().unwrap() { 837*bb4ee6a4SAndroid Build Coastguard Worker VmIrqRequest::AllocateOneMsiAtGsi { gsi, .. } => gsi, 838*bb4ee6a4SAndroid Build Coastguard Worker msg => panic!("unexpected irqchip message: {:?}", msg), 839*bb4ee6a4SAndroid Build Coastguard Worker } 840*bb4ee6a4SAndroid Build Coastguard Worker } 841*bb4ee6a4SAndroid Build Coastguard Worker 842*bb4ee6a4SAndroid Build Coastguard Worker struct MsiRouteDetails { 843*bb4ee6a4SAndroid Build Coastguard Worker gsi: u32, 844*bb4ee6a4SAndroid Build Coastguard Worker msi_address: u64, 845*bb4ee6a4SAndroid Build Coastguard Worker msi_data: u32, 846*bb4ee6a4SAndroid Build Coastguard Worker } 847*bb4ee6a4SAndroid Build Coastguard Worker 848*bb4ee6a4SAndroid Build Coastguard Worker #[track_caller] recv_add_msi_route(t: &Tube) -> MsiRouteDetails849*bb4ee6a4SAndroid Build Coastguard Worker fn recv_add_msi_route(t: &Tube) -> MsiRouteDetails { 850*bb4ee6a4SAndroid Build Coastguard Worker match t.recv::<VmIrqRequest>().unwrap() { 851*bb4ee6a4SAndroid Build Coastguard Worker VmIrqRequest::AddMsiRoute { 852*bb4ee6a4SAndroid Build Coastguard Worker gsi, 853*bb4ee6a4SAndroid Build Coastguard Worker msi_address, 854*bb4ee6a4SAndroid Build Coastguard Worker msi_data, 855*bb4ee6a4SAndroid Build Coastguard Worker } => MsiRouteDetails { 856*bb4ee6a4SAndroid Build Coastguard Worker gsi, 857*bb4ee6a4SAndroid Build Coastguard Worker msi_address, 858*bb4ee6a4SAndroid Build Coastguard Worker msi_data, 859*bb4ee6a4SAndroid Build Coastguard Worker }, 860*bb4ee6a4SAndroid Build Coastguard Worker msg => panic!("unexpected irqchip message: {:?}", msg), 861*bb4ee6a4SAndroid Build Coastguard Worker } 862*bb4ee6a4SAndroid Build Coastguard Worker } 863*bb4ee6a4SAndroid Build Coastguard Worker 864*bb4ee6a4SAndroid Build Coastguard Worker #[track_caller] recv_release_one_irq(t: &Tube) -> u32865*bb4ee6a4SAndroid Build Coastguard Worker fn recv_release_one_irq(t: &Tube) -> u32 { 866*bb4ee6a4SAndroid Build Coastguard Worker match t.recv::<VmIrqRequest>().unwrap() { 867*bb4ee6a4SAndroid Build Coastguard Worker VmIrqRequest::ReleaseOneIrq { gsi, irqfd: _ } => gsi, 868*bb4ee6a4SAndroid Build Coastguard Worker msg => panic!("unexpected irqchip message: {:?}", msg), 869*bb4ee6a4SAndroid Build Coastguard Worker } 870*bb4ee6a4SAndroid Build Coastguard Worker } 871*bb4ee6a4SAndroid Build Coastguard Worker 872*bb4ee6a4SAndroid Build Coastguard Worker #[track_caller] send_ok(t: &Tube)873*bb4ee6a4SAndroid Build Coastguard Worker fn send_ok(t: &Tube) { 874*bb4ee6a4SAndroid Build Coastguard Worker t.send(&VmIrqResponse::Ok).unwrap(); 875*bb4ee6a4SAndroid Build Coastguard Worker } 876*bb4ee6a4SAndroid Build Coastguard Worker 877*bb4ee6a4SAndroid Build Coastguard Worker /// Tests a cold restore where there are no existing vectors at the time 878*bb4ee6a4SAndroid Build Coastguard Worker /// restore is called. 879*bb4ee6a4SAndroid Build Coastguard Worker #[test] verify_msix_restore_cold_smoke()880*bb4ee6a4SAndroid Build Coastguard Worker fn verify_msix_restore_cold_smoke() { 881*bb4ee6a4SAndroid Build Coastguard Worker let (irqchip_tube, msix_config_tube) = Tube::pair().unwrap(); 882*bb4ee6a4SAndroid Build Coastguard Worker let (_unused, unused_config_tube) = Tube::pair().unwrap(); 883*bb4ee6a4SAndroid Build Coastguard Worker 884*bb4ee6a4SAndroid Build Coastguard Worker let mut cfg = MsixConfig::new(2, unused_config_tube, 0, "test_device".to_owned()); 885*bb4ee6a4SAndroid Build Coastguard Worker 886*bb4ee6a4SAndroid Build Coastguard Worker // Set up two MSI-X vectors (0 and 1). 887*bb4ee6a4SAndroid Build Coastguard Worker // Data is 0xdVEC_NUM. Address is 0xaVEC_NUM. 888*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[0].msg_data = 0xd0; 889*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[0].msg_addr_lo = 0xa0; 890*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[0].msg_addr_hi = 0; 891*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[1].msg_data = 0xd1; 892*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[1].msg_addr_lo = 0xa1; 893*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[1].msg_addr_hi = 0; 894*bb4ee6a4SAndroid Build Coastguard Worker 895*bb4ee6a4SAndroid Build Coastguard Worker // Pretend that these vectors were hooked up to GSIs 10 & 20, 896*bb4ee6a4SAndroid Build Coastguard Worker // respectively. 897*bb4ee6a4SAndroid Build Coastguard Worker cfg.irq_vec = vec![ 898*bb4ee6a4SAndroid Build Coastguard Worker Some(IrqfdGsi { 899*bb4ee6a4SAndroid Build Coastguard Worker gsi: 10, 900*bb4ee6a4SAndroid Build Coastguard Worker irqfd: Event::new().unwrap(), 901*bb4ee6a4SAndroid Build Coastguard Worker }), 902*bb4ee6a4SAndroid Build Coastguard Worker Some(IrqfdGsi { 903*bb4ee6a4SAndroid Build Coastguard Worker gsi: 20, 904*bb4ee6a4SAndroid Build Coastguard Worker irqfd: Event::new().unwrap(), 905*bb4ee6a4SAndroid Build Coastguard Worker }), 906*bb4ee6a4SAndroid Build Coastguard Worker ]; 907*bb4ee6a4SAndroid Build Coastguard Worker 908*bb4ee6a4SAndroid Build Coastguard Worker // Take a snapshot of MsixConfig. 909*bb4ee6a4SAndroid Build Coastguard Worker let snapshot = cfg.snapshot().unwrap(); 910*bb4ee6a4SAndroid Build Coastguard Worker 911*bb4ee6a4SAndroid Build Coastguard Worker // Create a fake irqchip to respond to our requests 912*bb4ee6a4SAndroid Build Coastguard Worker let irqchip_fake = thread::spawn(move || { 913*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(recv_allocate_msi(&irqchip_tube), 10); 914*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 915*bb4ee6a4SAndroid Build Coastguard Worker let route_one = recv_add_msi_route(&irqchip_tube); 916*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_one.gsi, 10); 917*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_one.msi_address, 0xa0); 918*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_one.msi_data, 0xd0); 919*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 920*bb4ee6a4SAndroid Build Coastguard Worker 921*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(recv_allocate_msi(&irqchip_tube), 20); 922*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 923*bb4ee6a4SAndroid Build Coastguard Worker let route_two = recv_add_msi_route(&irqchip_tube); 924*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_two.gsi, 20); 925*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_two.msi_address, 0xa1); 926*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_two.msi_data, 0xd1); 927*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 928*bb4ee6a4SAndroid Build Coastguard Worker irqchip_tube 929*bb4ee6a4SAndroid Build Coastguard Worker }); 930*bb4ee6a4SAndroid Build Coastguard Worker 931*bb4ee6a4SAndroid Build Coastguard Worker let mut restored_cfg = MsixConfig::new(10, msix_config_tube, 10, "some_device".to_owned()); 932*bb4ee6a4SAndroid Build Coastguard Worker restored_cfg.restore(snapshot).unwrap(); 933*bb4ee6a4SAndroid Build Coastguard Worker irqchip_fake.join().unwrap(); 934*bb4ee6a4SAndroid Build Coastguard Worker 935*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(restored_cfg.pci_id, 0); 936*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(restored_cfg.device_name, "test_device"); 937*bb4ee6a4SAndroid Build Coastguard Worker } 938*bb4ee6a4SAndroid Build Coastguard Worker 939*bb4ee6a4SAndroid Build Coastguard Worker /// Tests a warm restore where there are existing vectors at the time 940*bb4ee6a4SAndroid Build Coastguard Worker /// restore is called. These vectors need to be released first. 941*bb4ee6a4SAndroid Build Coastguard Worker #[test] verify_msix_restore_warm_smoke()942*bb4ee6a4SAndroid Build Coastguard Worker fn verify_msix_restore_warm_smoke() { 943*bb4ee6a4SAndroid Build Coastguard Worker let (irqchip_tube, msix_config_tube) = Tube::pair().unwrap(); 944*bb4ee6a4SAndroid Build Coastguard Worker 945*bb4ee6a4SAndroid Build Coastguard Worker let mut cfg = MsixConfig::new(2, msix_config_tube, 0, "test_device".to_owned()); 946*bb4ee6a4SAndroid Build Coastguard Worker 947*bb4ee6a4SAndroid Build Coastguard Worker // Set up two MSI-X vectors (0 and 1). 948*bb4ee6a4SAndroid Build Coastguard Worker // Data is 0xdVEC_NUM. Address is 0xaVEC_NUM. 949*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[0].msg_data = 0xd0; 950*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[0].msg_addr_lo = 0xa0; 951*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[0].msg_addr_hi = 0; 952*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[1].msg_data = 0xd1; 953*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[1].msg_addr_lo = 0xa1; 954*bb4ee6a4SAndroid Build Coastguard Worker cfg.table_entries[1].msg_addr_hi = 0; 955*bb4ee6a4SAndroid Build Coastguard Worker 956*bb4ee6a4SAndroid Build Coastguard Worker // Pretend that these vectors were hooked up to GSIs 10 & 20, 957*bb4ee6a4SAndroid Build Coastguard Worker // respectively. 958*bb4ee6a4SAndroid Build Coastguard Worker cfg.irq_vec = vec![ 959*bb4ee6a4SAndroid Build Coastguard Worker Some(IrqfdGsi { 960*bb4ee6a4SAndroid Build Coastguard Worker gsi: 10, 961*bb4ee6a4SAndroid Build Coastguard Worker irqfd: Event::new().unwrap(), 962*bb4ee6a4SAndroid Build Coastguard Worker }), 963*bb4ee6a4SAndroid Build Coastguard Worker Some(IrqfdGsi { 964*bb4ee6a4SAndroid Build Coastguard Worker gsi: 20, 965*bb4ee6a4SAndroid Build Coastguard Worker irqfd: Event::new().unwrap(), 966*bb4ee6a4SAndroid Build Coastguard Worker }), 967*bb4ee6a4SAndroid Build Coastguard Worker ]; 968*bb4ee6a4SAndroid Build Coastguard Worker 969*bb4ee6a4SAndroid Build Coastguard Worker // Take a snapshot of MsixConfig. 970*bb4ee6a4SAndroid Build Coastguard Worker let snapshot = cfg.snapshot().unwrap(); 971*bb4ee6a4SAndroid Build Coastguard Worker 972*bb4ee6a4SAndroid Build Coastguard Worker // Create a fake irqchip to respond to our requests 973*bb4ee6a4SAndroid Build Coastguard Worker let irqchip_fake = thread::spawn(move || { 974*bb4ee6a4SAndroid Build Coastguard Worker // First, we free the existing vectors / GSIs. 975*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(recv_release_one_irq(&irqchip_tube), 10); 976*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 977*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(recv_release_one_irq(&irqchip_tube), 20); 978*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 979*bb4ee6a4SAndroid Build Coastguard Worker 980*bb4ee6a4SAndroid Build Coastguard Worker // Now we re-allocate them. 981*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(recv_allocate_msi(&irqchip_tube), 10); 982*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 983*bb4ee6a4SAndroid Build Coastguard Worker let route_one = recv_add_msi_route(&irqchip_tube); 984*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_one.gsi, 10); 985*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_one.msi_address, 0xa0); 986*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_one.msi_data, 0xd0); 987*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 988*bb4ee6a4SAndroid Build Coastguard Worker 989*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(recv_allocate_msi(&irqchip_tube), 20); 990*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 991*bb4ee6a4SAndroid Build Coastguard Worker let route_two = recv_add_msi_route(&irqchip_tube); 992*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_two.gsi, 20); 993*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_two.msi_address, 0xa1); 994*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(route_two.msi_data, 0xd1); 995*bb4ee6a4SAndroid Build Coastguard Worker send_ok(&irqchip_tube); 996*bb4ee6a4SAndroid Build Coastguard Worker irqchip_tube 997*bb4ee6a4SAndroid Build Coastguard Worker }); 998*bb4ee6a4SAndroid Build Coastguard Worker 999*bb4ee6a4SAndroid Build Coastguard Worker cfg.restore(snapshot).unwrap(); 1000*bb4ee6a4SAndroid Build Coastguard Worker irqchip_fake.join().unwrap(); 1001*bb4ee6a4SAndroid Build Coastguard Worker 1002*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(cfg.pci_id, 0); 1003*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(cfg.device_name, "test_device"); 1004*bb4ee6a4SAndroid Build Coastguard Worker } 1005*bb4ee6a4SAndroid Build Coastguard Worker } 1006