xref: /aosp_15_r20/external/crosvm/devices/src/pci/pci_hotplug.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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