devices/pci/
pci_hotplug.rs1#![deny(missing_docs)]
8
9use base::AsRawDescriptor;
10use base::AsRawDescriptors;
11use base::RawDescriptor;
12use base::Tube;
13use serde::Deserialize;
14use serde::Serialize;
15use vm_control::api::VmMemoryClient;
16
17use crate::virtio::NetParameters;
18use crate::IrqLevelEvent;
19use crate::PciAddress;
20use crate::PciDevice;
21use crate::PciDeviceError;
22use crate::PciInterruptPin;
23
24pub type Result<T> = std::result::Result<T, PciDeviceError>;
25
26#[derive(Serialize, Deserialize)]
31pub enum ResourceCarrier {
32 VirtioNet(NetResourceCarrier),
34}
35
36impl ResourceCarrier {
37 pub fn debug_label(&self) -> String {
39 match self {
40 ResourceCarrier::VirtioNet(c) => c.debug_label(),
41 }
42 }
43
44 pub fn keep_rds(&self) -> Vec<RawDescriptor> {
47 match self {
48 ResourceCarrier::VirtioNet(c) => c.keep_rds(),
49 }
50 }
51 pub fn allocate_address(
53 &mut self,
54 preferred_address: PciAddress,
55 resources: &mut resources::SystemAllocator,
56 ) -> Result<()> {
57 match self {
58 ResourceCarrier::VirtioNet(c) => c.allocate_address(preferred_address, resources),
59 }
60 }
61 pub fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
65 match self {
66 ResourceCarrier::VirtioNet(c) => c.assign_irq(irq_evt, pin, irq_num),
67 }
68 }
69}
70
71pub trait HotPluggable: PciDevice {
74 fn set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()>;
76
77 fn configure_io_bars(&mut self) -> Result<()>;
79
80 fn configure_device_bars(&mut self) -> Result<()>;
82}
83
84impl<T: HotPluggable + ?Sized> HotPluggable for Box<T> {
85 fn set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()> {
86 (**self).set_pci_address(pci_addr)
87 }
88
89 fn configure_io_bars(&mut self) -> Result<()> {
90 (**self).configure_io_bars()
91 }
92
93 fn configure_device_bars(&mut self) -> Result<()> {
94 (**self).configure_device_bars()
95 }
96}
97
98#[derive(Serialize, Deserialize)]
102pub struct NetResourceCarrier {
103 pub net_param: NetParameters,
105 pub msi_device_tube: Tube,
107 pub ioevent_vm_memory_client: VmMemoryClient,
109 pub pci_address: Option<PciAddress>,
111 pub intx_parameter: Option<IntxParameter>,
113 pub vm_control_tube: Tube,
115}
116
117impl NetResourceCarrier {
118 pub fn new(
120 net_param: NetParameters,
121 msi_device_tube: Tube,
122 ioevent_vm_memory_client: VmMemoryClient,
123 vm_control_tube: Tube,
124 ) -> Self {
125 Self {
126 net_param,
127 msi_device_tube,
128 ioevent_vm_memory_client,
129 pci_address: None,
130 intx_parameter: None,
131 vm_control_tube,
132 }
133 }
134
135 fn debug_label(&self) -> String {
136 "virtio-net".to_owned()
137 }
138
139 fn keep_rds(&self) -> Vec<RawDescriptor> {
140 let mut keep_rds = vec![
141 self.msi_device_tube.as_raw_descriptor(),
142 self.ioevent_vm_memory_client.as_raw_descriptor(),
143 ];
144 if let Some(intx_parameter) = &self.intx_parameter {
145 keep_rds.extend(intx_parameter.irq_evt.as_raw_descriptors());
146 }
147 keep_rds
148 }
149
150 fn allocate_address(
151 &mut self,
152 preferred_address: PciAddress,
153 resources: &mut resources::SystemAllocator,
154 ) -> Result<()> {
155 match self.pci_address {
156 None => {
157 if resources.reserve_pci(preferred_address, self.debug_label()) {
158 self.pci_address = Some(preferred_address);
159 } else {
160 return Err(PciDeviceError::PciAllocationFailed);
161 }
162 }
163 Some(pci_address) => {
164 if pci_address != preferred_address {
165 return Err(PciDeviceError::PciAllocationFailed);
166 }
167 }
168 }
169 Ok(())
170 }
171
172 fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
173 self.intx_parameter = Some(IntxParameter {
174 irq_evt,
175 pin,
176 irq_num,
177 });
178 }
179}
180
181#[derive(Serialize, Deserialize)]
183pub struct IntxParameter {
184 pub irq_evt: IrqLevelEvent,
186 pub pin: PciInterruptPin,
188 pub irq_num: u32,
190}