1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 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 //! Trait definitions and implementations for PCI hotplug. 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker #![deny(missing_docs)] 8*bb4ee6a4SAndroid Build Coastguard Worker 9*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor; 10*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptors; 11*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor; 12*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube; 13*bb4ee6a4SAndroid Build Coastguard Worker use resources::Alloc; 14*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize; 15*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize; 16*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::api::VmMemoryClient; 17*bb4ee6a4SAndroid Build Coastguard Worker 18*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::NetParameters; 19*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqLevelEvent; 20*bb4ee6a4SAndroid Build Coastguard Worker use crate::PciAddress; 21*bb4ee6a4SAndroid Build Coastguard Worker use crate::PciDevice; 22*bb4ee6a4SAndroid Build Coastguard Worker use crate::PciDeviceError; 23*bb4ee6a4SAndroid Build Coastguard Worker use crate::PciInterruptPin; 24*bb4ee6a4SAndroid Build Coastguard Worker 25*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, PciDeviceError>; 26*bb4ee6a4SAndroid Build Coastguard Worker 27*bb4ee6a4SAndroid Build Coastguard Worker /// A ResourceCarrier moves resources for PCI device across process boundary. 28*bb4ee6a4SAndroid Build Coastguard Worker /// 29*bb4ee6a4SAndroid Build Coastguard Worker /// ResourceCarrier can be sent across processes using De/Serialize. All the variants shall be able 30*bb4ee6a4SAndroid Build Coastguard Worker /// to convert into a HotPlugPluggable device. 31*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)] 32*bb4ee6a4SAndroid Build Coastguard Worker pub enum ResourceCarrier { 33*bb4ee6a4SAndroid Build Coastguard Worker /// virtio-net device. 34*bb4ee6a4SAndroid Build Coastguard Worker VirtioNet(NetResourceCarrier), 35*bb4ee6a4SAndroid Build Coastguard Worker } 36*bb4ee6a4SAndroid Build Coastguard Worker 37*bb4ee6a4SAndroid Build Coastguard Worker impl ResourceCarrier { 38*bb4ee6a4SAndroid Build Coastguard Worker /// Returns debug label for the target device. debug_label(&self) -> String39*bb4ee6a4SAndroid Build Coastguard Worker pub fn debug_label(&self) -> String { 40*bb4ee6a4SAndroid Build Coastguard Worker match self { 41*bb4ee6a4SAndroid Build Coastguard Worker ResourceCarrier::VirtioNet(c) => c.debug_label(), 42*bb4ee6a4SAndroid Build Coastguard Worker } 43*bb4ee6a4SAndroid Build Coastguard Worker } 44*bb4ee6a4SAndroid Build Coastguard Worker 45*bb4ee6a4SAndroid Build Coastguard Worker /// A vector of device-specific file descriptors that must be kept open 46*bb4ee6a4SAndroid Build Coastguard Worker /// after jailing. Must be called before the process is jailed. keep_rds(&self) -> Vec<RawDescriptor>47*bb4ee6a4SAndroid Build Coastguard Worker pub fn keep_rds(&self) -> Vec<RawDescriptor> { 48*bb4ee6a4SAndroid Build Coastguard Worker match self { 49*bb4ee6a4SAndroid Build Coastguard Worker ResourceCarrier::VirtioNet(c) => c.keep_rds(), 50*bb4ee6a4SAndroid Build Coastguard Worker } 51*bb4ee6a4SAndroid Build Coastguard Worker } 52*bb4ee6a4SAndroid Build Coastguard Worker /// Allocate the preferred address to the device. allocate_address( &mut self, preferred_address: PciAddress, resources: &mut resources::SystemAllocator, ) -> Result<()>53*bb4ee6a4SAndroid Build Coastguard Worker pub fn allocate_address( 54*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 55*bb4ee6a4SAndroid Build Coastguard Worker preferred_address: PciAddress, 56*bb4ee6a4SAndroid Build Coastguard Worker resources: &mut resources::SystemAllocator, 57*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 58*bb4ee6a4SAndroid Build Coastguard Worker match self { 59*bb4ee6a4SAndroid Build Coastguard Worker ResourceCarrier::VirtioNet(c) => c.allocate_address(preferred_address, resources), 60*bb4ee6a4SAndroid Build Coastguard Worker } 61*bb4ee6a4SAndroid Build Coastguard Worker } 62*bb4ee6a4SAndroid Build Coastguard Worker /// Assign a legacy PCI IRQ to this device. 63*bb4ee6a4SAndroid Build Coastguard Worker /// The device may write to `irq_evt` to trigger an interrupt. 64*bb4ee6a4SAndroid Build Coastguard Worker /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary. assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32)65*bb4ee6a4SAndroid Build Coastguard Worker pub fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) { 66*bb4ee6a4SAndroid Build Coastguard Worker match self { 67*bb4ee6a4SAndroid Build Coastguard Worker ResourceCarrier::VirtioNet(c) => c.assign_irq(irq_evt, pin, irq_num), 68*bb4ee6a4SAndroid Build Coastguard Worker } 69*bb4ee6a4SAndroid Build Coastguard Worker } 70*bb4ee6a4SAndroid Build Coastguard Worker } 71*bb4ee6a4SAndroid Build Coastguard Worker 72*bb4ee6a4SAndroid Build Coastguard Worker /// Additional requirements for a PciDevice to support hotplug. 73*bb4ee6a4SAndroid Build Coastguard Worker /// A hotplug device can be configured without access to the SystemAllocator. 74*bb4ee6a4SAndroid Build Coastguard Worker pub trait HotPluggable: PciDevice { 75*bb4ee6a4SAndroid Build Coastguard Worker /// Sets PciAddress to pci_addr. Replaces allocate_address. set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()>76*bb4ee6a4SAndroid Build Coastguard Worker fn set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()>; 77*bb4ee6a4SAndroid Build Coastguard Worker 78*bb4ee6a4SAndroid Build Coastguard Worker /// Configures IO BAR layout without memory alloc. Replaces allocate_io_bars. configure_io_bars(&mut self) -> Result<()>79*bb4ee6a4SAndroid Build Coastguard Worker fn configure_io_bars(&mut self) -> Result<()>; 80*bb4ee6a4SAndroid Build Coastguard Worker 81*bb4ee6a4SAndroid Build Coastguard Worker /// Configure device BAR layout without memory alloc. Replaces allocate_device_bars. configure_device_bars(&mut self) -> Result<()>82*bb4ee6a4SAndroid Build Coastguard Worker fn configure_device_bars(&mut self) -> Result<()>; 83*bb4ee6a4SAndroid Build Coastguard Worker } 84*bb4ee6a4SAndroid Build Coastguard Worker 85*bb4ee6a4SAndroid Build Coastguard Worker impl<T: HotPluggable + ?Sized> HotPluggable for Box<T> { set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()>86*bb4ee6a4SAndroid Build Coastguard Worker fn set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()> { 87*bb4ee6a4SAndroid Build Coastguard Worker (**self).set_pci_address(pci_addr) 88*bb4ee6a4SAndroid Build Coastguard Worker } 89*bb4ee6a4SAndroid Build Coastguard Worker configure_io_bars(&mut self) -> Result<()>90*bb4ee6a4SAndroid Build Coastguard Worker fn configure_io_bars(&mut self) -> Result<()> { 91*bb4ee6a4SAndroid Build Coastguard Worker (**self).configure_io_bars() 92*bb4ee6a4SAndroid Build Coastguard Worker } 93*bb4ee6a4SAndroid Build Coastguard Worker configure_device_bars(&mut self) -> Result<()>94*bb4ee6a4SAndroid Build Coastguard Worker fn configure_device_bars(&mut self) -> Result<()> { 95*bb4ee6a4SAndroid Build Coastguard Worker (**self).configure_device_bars() 96*bb4ee6a4SAndroid Build Coastguard Worker } 97*bb4ee6a4SAndroid Build Coastguard Worker } 98*bb4ee6a4SAndroid Build Coastguard Worker 99*bb4ee6a4SAndroid Build Coastguard Worker /// A NetResourceCarrier is a ResourceCarrier specialization for virtio-net devices. 100*bb4ee6a4SAndroid Build Coastguard Worker /// 101*bb4ee6a4SAndroid Build Coastguard Worker /// TODO(b/289155315): make members private. 102*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)] 103*bb4ee6a4SAndroid Build Coastguard Worker pub struct NetResourceCarrier { 104*bb4ee6a4SAndroid Build Coastguard Worker /// NetParameters for constructing tap device 105*bb4ee6a4SAndroid Build Coastguard Worker pub net_param: NetParameters, 106*bb4ee6a4SAndroid Build Coastguard Worker /// msi_device_tube for VirtioPciDevice constructor 107*bb4ee6a4SAndroid Build Coastguard Worker pub msi_device_tube: Tube, 108*bb4ee6a4SAndroid Build Coastguard Worker /// ioevent_vm_memory_client for VirtioPciDevice constructor 109*bb4ee6a4SAndroid Build Coastguard Worker pub ioevent_vm_memory_client: VmMemoryClient, 110*bb4ee6a4SAndroid Build Coastguard Worker /// pci_address for the hotplugged device 111*bb4ee6a4SAndroid Build Coastguard Worker pub pci_address: Option<PciAddress>, 112*bb4ee6a4SAndroid Build Coastguard Worker /// intx_parameter for assign_irq 113*bb4ee6a4SAndroid Build Coastguard Worker pub intx_parameter: Option<IntxParameter>, 114*bb4ee6a4SAndroid Build Coastguard Worker /// vm_control_tube for VirtioPciDevice constructor 115*bb4ee6a4SAndroid Build Coastguard Worker pub vm_control_tube: Tube, 116*bb4ee6a4SAndroid Build Coastguard Worker } 117*bb4ee6a4SAndroid Build Coastguard Worker 118*bb4ee6a4SAndroid Build Coastguard Worker impl NetResourceCarrier { 119*bb4ee6a4SAndroid Build Coastguard Worker ///Constructs NetResourceCarrier. new( net_param: NetParameters, msi_device_tube: Tube, ioevent_vm_memory_client: VmMemoryClient, vm_control_tube: Tube, ) -> Self120*bb4ee6a4SAndroid Build Coastguard Worker pub fn new( 121*bb4ee6a4SAndroid Build Coastguard Worker net_param: NetParameters, 122*bb4ee6a4SAndroid Build Coastguard Worker msi_device_tube: Tube, 123*bb4ee6a4SAndroid Build Coastguard Worker ioevent_vm_memory_client: VmMemoryClient, 124*bb4ee6a4SAndroid Build Coastguard Worker vm_control_tube: Tube, 125*bb4ee6a4SAndroid Build Coastguard Worker ) -> Self { 126*bb4ee6a4SAndroid Build Coastguard Worker Self { 127*bb4ee6a4SAndroid Build Coastguard Worker net_param, 128*bb4ee6a4SAndroid Build Coastguard Worker msi_device_tube, 129*bb4ee6a4SAndroid Build Coastguard Worker ioevent_vm_memory_client, 130*bb4ee6a4SAndroid Build Coastguard Worker pci_address: None, 131*bb4ee6a4SAndroid Build Coastguard Worker intx_parameter: None, 132*bb4ee6a4SAndroid Build Coastguard Worker vm_control_tube, 133*bb4ee6a4SAndroid Build Coastguard Worker } 134*bb4ee6a4SAndroid Build Coastguard Worker } 135*bb4ee6a4SAndroid Build Coastguard Worker debug_label(&self) -> String136*bb4ee6a4SAndroid Build Coastguard Worker fn debug_label(&self) -> String { 137*bb4ee6a4SAndroid Build Coastguard Worker "virtio-net".to_owned() 138*bb4ee6a4SAndroid Build Coastguard Worker } 139*bb4ee6a4SAndroid Build Coastguard Worker keep_rds(&self) -> Vec<RawDescriptor>140*bb4ee6a4SAndroid Build Coastguard Worker fn keep_rds(&self) -> Vec<RawDescriptor> { 141*bb4ee6a4SAndroid Build Coastguard Worker let mut keep_rds = vec![ 142*bb4ee6a4SAndroid Build Coastguard Worker self.msi_device_tube.as_raw_descriptor(), 143*bb4ee6a4SAndroid Build Coastguard Worker self.ioevent_vm_memory_client.as_raw_descriptor(), 144*bb4ee6a4SAndroid Build Coastguard Worker ]; 145*bb4ee6a4SAndroid Build Coastguard Worker if let Some(intx_parameter) = &self.intx_parameter { 146*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.extend(intx_parameter.irq_evt.as_raw_descriptors()); 147*bb4ee6a4SAndroid Build Coastguard Worker } 148*bb4ee6a4SAndroid Build Coastguard Worker keep_rds 149*bb4ee6a4SAndroid Build Coastguard Worker } 150*bb4ee6a4SAndroid Build Coastguard Worker allocate_address( &mut self, preferred_address: PciAddress, resources: &mut resources::SystemAllocator, ) -> Result<()>151*bb4ee6a4SAndroid Build Coastguard Worker fn allocate_address( 152*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 153*bb4ee6a4SAndroid Build Coastguard Worker preferred_address: PciAddress, 154*bb4ee6a4SAndroid Build Coastguard Worker resources: &mut resources::SystemAllocator, 155*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 156*bb4ee6a4SAndroid Build Coastguard Worker match self.pci_address { 157*bb4ee6a4SAndroid Build Coastguard Worker None => { 158*bb4ee6a4SAndroid Build Coastguard Worker if resources.reserve_pci( 159*bb4ee6a4SAndroid Build Coastguard Worker Alloc::PciBar { 160*bb4ee6a4SAndroid Build Coastguard Worker bus: preferred_address.bus, 161*bb4ee6a4SAndroid Build Coastguard Worker dev: preferred_address.dev, 162*bb4ee6a4SAndroid Build Coastguard Worker func: preferred_address.func, 163*bb4ee6a4SAndroid Build Coastguard Worker bar: 0, 164*bb4ee6a4SAndroid Build Coastguard Worker }, 165*bb4ee6a4SAndroid Build Coastguard Worker self.debug_label(), 166*bb4ee6a4SAndroid Build Coastguard Worker ) { 167*bb4ee6a4SAndroid Build Coastguard Worker self.pci_address = Some(preferred_address); 168*bb4ee6a4SAndroid Build Coastguard Worker } else { 169*bb4ee6a4SAndroid Build Coastguard Worker return Err(PciDeviceError::PciAllocationFailed); 170*bb4ee6a4SAndroid Build Coastguard Worker } 171*bb4ee6a4SAndroid Build Coastguard Worker } 172*bb4ee6a4SAndroid Build Coastguard Worker Some(pci_address) => { 173*bb4ee6a4SAndroid Build Coastguard Worker if pci_address != preferred_address { 174*bb4ee6a4SAndroid Build Coastguard Worker return Err(PciDeviceError::PciAllocationFailed); 175*bb4ee6a4SAndroid Build Coastguard Worker } 176*bb4ee6a4SAndroid Build Coastguard Worker } 177*bb4ee6a4SAndroid Build Coastguard Worker } 178*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 179*bb4ee6a4SAndroid Build Coastguard Worker } 180*bb4ee6a4SAndroid Build Coastguard Worker assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32)181*bb4ee6a4SAndroid Build Coastguard Worker fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) { 182*bb4ee6a4SAndroid Build Coastguard Worker self.intx_parameter = Some(IntxParameter { 183*bb4ee6a4SAndroid Build Coastguard Worker irq_evt, 184*bb4ee6a4SAndroid Build Coastguard Worker pin, 185*bb4ee6a4SAndroid Build Coastguard Worker irq_num, 186*bb4ee6a4SAndroid Build Coastguard Worker }); 187*bb4ee6a4SAndroid Build Coastguard Worker } 188*bb4ee6a4SAndroid Build Coastguard Worker } 189*bb4ee6a4SAndroid Build Coastguard Worker 190*bb4ee6a4SAndroid Build Coastguard Worker /// Parameters for legacy INTx interrrupt. 191*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)] 192*bb4ee6a4SAndroid Build Coastguard Worker pub struct IntxParameter { 193*bb4ee6a4SAndroid Build Coastguard Worker /// interrupt level event 194*bb4ee6a4SAndroid Build Coastguard Worker pub irq_evt: IrqLevelEvent, 195*bb4ee6a4SAndroid Build Coastguard Worker /// INTx interrupt pin 196*bb4ee6a4SAndroid Build Coastguard Worker pub pin: PciInterruptPin, 197*bb4ee6a4SAndroid Build Coastguard Worker /// irq num 198*bb4ee6a4SAndroid Build Coastguard Worker pub irq_num: u32, 199*bb4ee6a4SAndroid Build Coastguard Worker } 200