devices: PCI: add capabilities callback

virtio devices should be able to specify capabilities

BUG=chromium:936567
TEST=boot vm

Change-Id: I049f9967eb59a7904528fff5aea844e30c636e28
Reviewed-on: https://chromium-review.googlesource.com/1493012
Commit-Ready: Daniel Prilik <prilik@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Stephen Barber <smbarber@chromium.org>
This commit is contained in:
Daniel Prilik 2019-02-26 17:28:26 -08:00 committed by chrome-bot
parent be03426408
commit 7374f32ba4
4 changed files with 43 additions and 21 deletions

View file

@ -177,6 +177,7 @@ pub fn generate_pci_root(
let device_ranges = device
.allocate_device_bars(resources)
.map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
device.register_device_capabilities();
for (event, addr, datamatch) in device.ioeventfds() {
let io_addr = IoeventAddress::Mmio(addr);
vm.register_ioevent(&event, io_addr, datamatch)

View file

@ -76,6 +76,11 @@ pub trait PciDevice: Send {
Ok(Vec::new())
}
/// Register any capabilties specified by the device.
fn register_device_capabilities(&mut self) -> Result<()> {
Ok(())
}
/// Gets a list of ioeventfds that should be registered with the running VM. The list is
/// returned as a Vec of (eventfd, addr, datamatch) tuples.
fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
@ -160,6 +165,9 @@ impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
(**self).allocate_device_bars(resources)
}
fn register_device_capabilities(&mut self) -> Result<()> {
(**self).register_device_capabilities()
}
fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
(**self).ioeventfds()
}

View file

@ -7,7 +7,7 @@ use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use super::*;
use pci::PciBarConfiguration;
use pci::{PciBarConfiguration, PciCapability};
use sys_util::{EventFd, GuestMemory};
/// Trait for virtio devices to be driven by a virtio transport.
@ -79,4 +79,9 @@ pub trait VirtioDevice: Send {
fn get_device_bars(&self) -> Option<Vec<PciBarConfiguration>> {
None
}
/// Optionally returns additional capabiltiies needed by device
fn get_device_caps(&self) -> Option<Vec<Box<PciCapability>>> {
None
}
}

View file

@ -19,7 +19,7 @@ use sys_util::{EventFd, GuestMemory, Result};
use self::virtio_pci_common_config::VirtioPciCommonConfig;
enum PciCapabilityType {
pub enum PciCapabilityType {
CommonConfig = 1,
NotifyConfig = 2,
IsrConfig = 3,
@ -69,7 +69,7 @@ impl VirtioPciCap {
#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Copy)]
struct VirtioPciNotifyCap {
pub struct VirtioPciNotifyCap {
cap: VirtioPciCap,
notify_off_multiplier: Le32,
}
@ -231,7 +231,7 @@ impl VirtioPciDevice {
}
}
fn add_pci_capabilities(
fn add_settings_pci_capabilities(
&mut self,
settings_bar: u8,
) -> std::result::Result<(), PciDeviceError> {
@ -338,7 +338,7 @@ impl PciDevice for VirtioPciDevice {
ranges.push((settings_config_addr, CAPABILITY_BAR_SIZE));
// Once the BARs are allocated, the capabilities can be added to the PCI configuration.
self.add_pci_capabilities(settings_bar)?;
self.add_settings_pci_capabilities(settings_bar)?;
Ok(ranges)
}
@ -348,26 +348,34 @@ impl PciDevice for VirtioPciDevice {
resources: &mut SystemAllocator,
) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
let mut ranges = Vec::new();
let configs = self.device.get_device_bars();
match configs {
Some(configs) => {
for mut config in configs {
let device_addr = resources
.allocate_device_addresses(config.get_size())
.ok_or(PciDeviceError::IoAllocationFailed(config.get_size()))?;
config.set_address(device_addr);
let _device_bar = self
.config_regs
.add_pci_bar(&config)
.map_err(|e| PciDeviceError::IoRegistrationFailed(device_addr, e))?;
ranges.push((device_addr, config.get_size()));
}
if let Some(configs) = self.device.get_device_bars() {
for mut config in configs {
let device_addr = resources
.allocate_device_addresses(config.get_size())
.ok_or(PciDeviceError::IoAllocationFailed(config.get_size()))?;
config.set_address(device_addr);
let _device_bar = self
.config_regs
.add_pci_bar(&config)
.map_err(|e| PciDeviceError::IoRegistrationFailed(device_addr, e))?;
ranges.push((device_addr, config.get_size()));
}
None => (),
};
}
Ok(ranges)
}
fn register_device_capabilities(&mut self) -> std::result::Result<(), PciDeviceError> {
if let Some(caps) = self.device.get_device_caps() {
for cap in caps {
self.config_regs
.add_capability(&*cap)
.map_err(|e| PciDeviceError::CapabilitiesSetup(e))?;
}
}
Ok(())
}
fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
let notify_base = bar0 + NOTIFICATION_BAR_OFFSET;