mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 12:34:31 +00:00
vfio_pci: add support for runtime power management
Allow devices to perform runtime power management via VFIO_DEVICE_FEATURE IOCTL. BUG=b:194390621 TEST=host's VFIO_DEVICE_FEATURE can be triggered from guest Change-Id: Id649a1e5fe317dfb315f841a152ec8b81fab8e7c Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3822004 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Victor Ding <victording@chromium.org>
This commit is contained in:
parent
d4ec52642a
commit
ec820fc4ae
5 changed files with 65 additions and 8 deletions
|
@ -2026,12 +2026,24 @@ impl PciDevice for VfioPciDevice {
|
|||
0
|
||||
}
|
||||
|
||||
fn write_virtual_config_register(&mut self, reg_idx: usize, _value: u32) {
|
||||
warn!(
|
||||
"{} write unsupported register {}",
|
||||
self.debug_label(),
|
||||
reg_idx
|
||||
)
|
||||
fn write_virtual_config_register(&mut self, reg_idx: usize, value: u32) {
|
||||
match reg_idx {
|
||||
0 => {
|
||||
match value {
|
||||
0 => {
|
||||
let _ = self.device.pm_low_power_enter();
|
||||
}
|
||||
_ => {
|
||||
let _ = self.device.pm_low_power_exit();
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => warn!(
|
||||
"{} write unsupported register {}",
|
||||
self.debug_label(),
|
||||
reg_idx
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
|
||||
|
|
|
@ -104,6 +104,10 @@ pub enum VfioError {
|
|||
VfioIrqMask(Error),
|
||||
#[error("failed to unmask vfio deviece's irq: {0}")]
|
||||
VfioIrqUnmask(Error),
|
||||
#[error("failed to enter vfio deviece's low power state: {0}")]
|
||||
VfioPmLowPowerEnter(Error),
|
||||
#[error("failed to exit vfio deviece's low power state: {0}")]
|
||||
VfioPmLowPowerExit(Error),
|
||||
#[error("container dones't support VfioType1V2 IOMMU driver type")]
|
||||
VfioType1V2,
|
||||
}
|
||||
|
@ -849,6 +853,34 @@ impl VfioDevice {
|
|||
&self.name
|
||||
}
|
||||
|
||||
/// enter the device's low power state
|
||||
pub fn pm_low_power_enter(&self) -> Result<()> {
|
||||
let mut device_feature = vec_with_array_field::<vfio_device_feature, u8>(0);
|
||||
device_feature[0].argsz = mem::size_of::<vfio_device_feature>() as u32;
|
||||
device_feature[0].flags = VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY;
|
||||
// Safe as we are the owner of self and power_management which are valid value
|
||||
let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_FEATURE(), &device_feature[0]) };
|
||||
if ret < 0 {
|
||||
Err(VfioError::VfioPmLowPowerEnter(get_error()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// exit the device's low power state
|
||||
pub fn pm_low_power_exit(&self) -> Result<()> {
|
||||
let mut device_feature = vec_with_array_field::<vfio_device_feature, u8>(0);
|
||||
device_feature[0].argsz = mem::size_of::<vfio_device_feature>() as u32;
|
||||
device_feature[0].flags = VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_LOW_POWER_EXIT;
|
||||
// Safe as we are the owner of self and power_management which are valid value
|
||||
let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_FEATURE(), &device_feature[0]) };
|
||||
if ret < 0 {
|
||||
Err(VfioError::VfioPmLowPowerExit(get_error()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable vfio device's irq and associate Irqfd Event with device.
|
||||
/// When MSIx is enabled, multi vectors will be supported, and vectors starting from subindex to subindex +
|
||||
/// descriptors length will be assigned with irqfd in the descriptors array.
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
|
||||
@include /usr/share/policy/crosvm/common_device.policy
|
||||
|
||||
# VFIO_DEVICE_SET_IRQS, VFIO_IOMMU_MAP/UNMAP_DMA
|
||||
ioctl: arg1 == 0x3B6E || arg1 == 0x3B71 || arg1 == 0x3B72
|
||||
# 0x3B6E: VFIO_DEVICE_SET_IRQS
|
||||
# 0x3B71: VFIO_IOMMU_MAP_DMA
|
||||
# 0x3B72: VFIO_IOMMU_UNMAP_DMA
|
||||
# 0x3B75: VFIO_DEVICE_FEATURE
|
||||
ioctl: arg1 == 0x3B6E || arg1 == 0x3B71 || arg1 == 0x3B72 || arg1 == 0x3B75
|
||||
open: return ENOENT
|
||||
openat: return ENOENT
|
||||
pread64: 1
|
||||
|
|
|
@ -43,6 +43,7 @@ ioctl_io_nr!(VFIO_IOMMU_MAP_DMA, VFIO_TYPE, VFIO_BASE + 13);
|
|||
ioctl_io_nr!(VFIO_IOMMU_UNMAP_DMA, VFIO_TYPE, VFIO_BASE + 14);
|
||||
ioctl_io_nr!(VFIO_IOMMU_ENABLE, VFIO_TYPE, VFIO_BASE + 15);
|
||||
ioctl_io_nr!(VFIO_IOMMU_DISABLE, VFIO_TYPE, VFIO_BASE + 16);
|
||||
ioctl_io_nr!(VFIO_DEVICE_FEATURE, VFIO_TYPE, VFIO_BASE + 17);
|
||||
|
||||
ioctl_io_nr!(
|
||||
PLAT_IRQ_FORWARD_SET,
|
||||
|
|
|
@ -147,6 +147,9 @@ pub const VFIO_DEVICE_FEATURE_GET: u32 = 65536;
|
|||
pub const VFIO_DEVICE_FEATURE_SET: u32 = 131072;
|
||||
pub const VFIO_DEVICE_FEATURE_PROBE: u32 = 262144;
|
||||
pub const VFIO_DEVICE_FEATURE_PCI_VF_TOKEN: u32 = 0;
|
||||
pub const VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY: u32 = 3;
|
||||
pub const VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY_WITH_WAKEUP: u32 = 4;
|
||||
pub const VFIO_DEVICE_FEATURE_LOW_POWER_EXIT: u32 = 5;
|
||||
pub const VFIO_IOMMU_INFO_PGSIZES: u32 = 1;
|
||||
pub const VFIO_IOMMU_INFO_CAPS: u32 = 2;
|
||||
pub const VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE: u32 = 1;
|
||||
|
@ -390,6 +393,12 @@ pub struct vfio_device_feature {
|
|||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct vfio_device_low_power_entry_with_wakeup {
|
||||
pub wakeup_eventfd: i32,
|
||||
pub reserved: u32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct vfio_iommu_type1_info {
|
||||
pub argsz: u32,
|
||||
pub flags: u32,
|
||||
|
|
Loading…
Reference in a new issue