device_virtio_net/
pci_hotplug.rs

1// Copyright 2023 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use base::AsRawDescriptor;
6use base::AsRawDescriptors;
7use base::RawDescriptor;
8use base::Tube;
9use devices::IntxParameter;
10use devices::IrqLevelEvent;
11use devices::PciAddress;
12use devices::PciDeviceError;
13use devices::PciInterruptPin;
14use serde::Deserialize;
15use serde::Serialize;
16use vm_control::api::VmMemoryClient;
17
18use crate::NetParameters;
19
20pub type Result<T> = std::result::Result<T, PciDeviceError>;
21
22/// A NetPciHotplugResourceCarrier is a ResourceCarrier specialization for virtio-net devices.
23///
24/// TODO(b/289155315): make members private.
25#[derive(Serialize, Deserialize)]
26pub struct NetPciHotplugResourceCarrier {
27    /// NetParameters for constructing tap device
28    pub net_param: NetParameters,
29    /// msi_device_tube for VirtioPciDevice constructor
30    pub msi_device_tube: Tube,
31    /// ioevent_vm_memory_client for VirtioPciDevice constructor
32    pub ioevent_vm_memory_client: VmMemoryClient,
33    /// pci_address for the hotplugged device
34    pub pci_address: Option<PciAddress>,
35    /// intx_parameter for assign_irq
36    pub intx_parameter: Option<IntxParameter>,
37    /// vm_control_tube for VirtioPciDevice constructor
38    pub vm_control_tube: Tube,
39}
40
41impl NetPciHotplugResourceCarrier {
42    ///Constructs NetPciHotplugResourceCarrier.
43    pub fn new(
44        net_param: NetParameters,
45        msi_device_tube: Tube,
46        ioevent_vm_memory_client: VmMemoryClient,
47        vm_control_tube: Tube,
48    ) -> Self {
49        Self {
50            net_param,
51            msi_device_tube,
52            ioevent_vm_memory_client,
53            pci_address: None,
54            intx_parameter: None,
55            vm_control_tube,
56        }
57    }
58
59    pub fn debug_label(&self) -> String {
60        "virtio-net".to_owned()
61    }
62
63    pub fn keep_rds(&self) -> Vec<RawDescriptor> {
64        let mut keep_rds = vec![
65            self.msi_device_tube.as_raw_descriptor(),
66            self.ioevent_vm_memory_client.as_raw_descriptor(),
67        ];
68        if let Some(intx_parameter) = &self.intx_parameter {
69            keep_rds.extend(intx_parameter.irq_evt.as_raw_descriptors());
70        }
71        keep_rds
72    }
73
74    pub fn allocate_address(
75        &mut self,
76        preferred_address: PciAddress,
77        resources: &mut resources::SystemAllocator,
78    ) -> Result<()> {
79        match self.pci_address {
80            None => {
81                if resources.reserve_pci(preferred_address, self.debug_label()) {
82                    self.pci_address = Some(preferred_address);
83                } else {
84                    return Err(PciDeviceError::PciAllocationFailed);
85                }
86            }
87            Some(pci_address) => {
88                if pci_address != preferred_address {
89                    return Err(PciDeviceError::PciAllocationFailed);
90                }
91            }
92        }
93        Ok(())
94    }
95
96    pub fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
97        self.intx_parameter = Some(IntxParameter {
98            irq_evt,
99            pin,
100            irq_num,
101        });
102    }
103}