#![deny(missing_docs)]
use base::AsRawDescriptor;
use base::AsRawDescriptors;
use base::RawDescriptor;
use base::Tube;
use serde::Deserialize;
use serde::Serialize;
use vm_control::api::VmMemoryClient;
use crate::virtio::NetParameters;
use crate::IrqLevelEvent;
use crate::PciAddress;
use crate::PciDevice;
use crate::PciDeviceError;
use crate::PciInterruptPin;
pub type Result<T> = std::result::Result<T, PciDeviceError>;
#[derive(Serialize, Deserialize)]
pub enum ResourceCarrier {
VirtioNet(NetResourceCarrier),
}
impl ResourceCarrier {
pub fn debug_label(&self) -> String {
match self {
ResourceCarrier::VirtioNet(c) => c.debug_label(),
}
}
pub fn keep_rds(&self) -> Vec<RawDescriptor> {
match self {
ResourceCarrier::VirtioNet(c) => c.keep_rds(),
}
}
pub fn allocate_address(
&mut self,
preferred_address: PciAddress,
resources: &mut resources::SystemAllocator,
) -> Result<()> {
match self {
ResourceCarrier::VirtioNet(c) => c.allocate_address(preferred_address, resources),
}
}
pub fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
match self {
ResourceCarrier::VirtioNet(c) => c.assign_irq(irq_evt, pin, irq_num),
}
}
}
pub trait HotPluggable: PciDevice {
fn set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()>;
fn configure_io_bars(&mut self) -> Result<()>;
fn configure_device_bars(&mut self) -> Result<()>;
}
impl<T: HotPluggable + ?Sized> HotPluggable for Box<T> {
fn set_pci_address(&mut self, pci_addr: PciAddress) -> Result<()> {
(**self).set_pci_address(pci_addr)
}
fn configure_io_bars(&mut self) -> Result<()> {
(**self).configure_io_bars()
}
fn configure_device_bars(&mut self) -> Result<()> {
(**self).configure_device_bars()
}
}
#[derive(Serialize, Deserialize)]
pub struct NetResourceCarrier {
pub net_param: NetParameters,
pub msi_device_tube: Tube,
pub ioevent_vm_memory_client: VmMemoryClient,
pub pci_address: Option<PciAddress>,
pub intx_parameter: Option<IntxParameter>,
pub vm_control_tube: Tube,
}
impl NetResourceCarrier {
pub fn new(
net_param: NetParameters,
msi_device_tube: Tube,
ioevent_vm_memory_client: VmMemoryClient,
vm_control_tube: Tube,
) -> Self {
Self {
net_param,
msi_device_tube,
ioevent_vm_memory_client,
pci_address: None,
intx_parameter: None,
vm_control_tube,
}
}
fn debug_label(&self) -> String {
"virtio-net".to_owned()
}
fn keep_rds(&self) -> Vec<RawDescriptor> {
let mut keep_rds = vec![
self.msi_device_tube.as_raw_descriptor(),
self.ioevent_vm_memory_client.as_raw_descriptor(),
];
if let Some(intx_parameter) = &self.intx_parameter {
keep_rds.extend(intx_parameter.irq_evt.as_raw_descriptors());
}
keep_rds
}
fn allocate_address(
&mut self,
preferred_address: PciAddress,
resources: &mut resources::SystemAllocator,
) -> Result<()> {
match self.pci_address {
None => {
if resources.reserve_pci(preferred_address, self.debug_label()) {
self.pci_address = Some(preferred_address);
} else {
return Err(PciDeviceError::PciAllocationFailed);
}
}
Some(pci_address) => {
if pci_address != preferred_address {
return Err(PciDeviceError::PciAllocationFailed);
}
}
}
Ok(())
}
fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
self.intx_parameter = Some(IntxParameter {
irq_evt,
pin,
irq_num,
});
}
}
#[derive(Serialize, Deserialize)]
pub struct IntxParameter {
pub irq_evt: IrqLevelEvent,
pub pin: PciInterruptPin,
pub irq_num: u32,
}