diff options
author | Gurchetan Singh <gurchetansingh@chromium.org> | 2019-02-20 16:30:48 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-03-01 01:08:27 -0800 |
commit | 036ba3390bfd31a3eeae07186cb9e4933fa5ddc3 (patch) | |
tree | 64aab291c5b555338297badfff30d7ebbaf6d263 /devices/src/pci | |
parent | 948a3ab6b5c67bd6fa46e6bdd9b49de59ccadf36 (diff) | |
download | crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.gz crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.bz2 crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.lz crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.xz crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.tar.zst crosvm-036ba3390bfd31a3eeae07186cb9e4933fa5ddc3.zip |
devices: use PCI bar configuration when adding regions
This removes add_memory_region and add_io_region, and replaces it with the add_pci_bar function. BUG=chromium:924405 TEST=boot VM Change-Id: Ifc637d174d3f8b1255cf13725a1a224b4cdf0a30 Reviewed-on: https://chromium-review.googlesource.com/1480741 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: kokoro <noreply+kokoro@google.com> Tested-by: Gurchetan Singh <gurchetansingh@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'devices/src/pci')
-rw-r--r-- | devices/src/pci/ac97.rs | 15 | ||||
-rw-r--r-- | devices/src/pci/pci_configuration.rs | 82 |
2 files changed, 59 insertions, 38 deletions
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs index c8eb8ca..68dfe3c 100644 --- a/devices/src/pci/ac97.rs +++ b/devices/src/pci/ac97.rs @@ -9,7 +9,7 @@ use pci::ac97_bus_master::Ac97BusMaster; use pci::ac97_mixer::Ac97Mixer; use pci::ac97_regs::*; use pci::pci_configuration::{ - PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass, + PciBarConfiguration, PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass, }; use pci::pci_device::{self, PciDevice, Result}; use pci::PciInterruptPin; @@ -141,15 +141,24 @@ impl PciDevice for Ac97Dev { let mixer_regs_addr = resources .allocate_mmio_addresses(MIXER_REGS_SIZE) .ok_or(pci_device::Error::IoAllocationFailed(MIXER_REGS_SIZE))?; + let config: PciBarConfiguration = PciBarConfiguration::default() + .set_register_index(0) + .set_address(mixer_regs_addr) + .set_size(MIXER_REGS_SIZE); self.config_regs - .add_memory_region(mixer_regs_addr, MIXER_REGS_SIZE) + .add_pci_bar(&config) .ok_or_else(|| pci_device::Error::IoRegistrationFailed(mixer_regs_addr))?; ranges.push((mixer_regs_addr, MIXER_REGS_SIZE)); + let master_regs_addr = resources .allocate_mmio_addresses(MASTER_REGS_SIZE) .ok_or_else(|| pci_device::Error::IoAllocationFailed(MASTER_REGS_SIZE))?; + config + .set_register_index(1) + .set_address(master_regs_addr) + .set_size(MASTER_REGS_SIZE); self.config_regs - .add_memory_region(master_regs_addr, MASTER_REGS_SIZE) + .add_pci_bar(&config) .ok_or_else(|| pci_device::Error::IoRegistrationFailed(master_regs_addr))?; ranges.push((master_regs_addr, MASTER_REGS_SIZE)); Ok(ranges) diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs index b2bf90d..d93ae03 100644 --- a/devices/src/pci/pci_configuration.rs +++ b/devices/src/pci/pci_configuration.rs @@ -11,7 +11,6 @@ const STATUS_REG: usize = 1; const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000; const BAR0_REG: usize = 4; const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc; -const BAR_IO_BIT: u32 = 0x0000_0001; const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0; const NUM_BAR_REGS: usize = 6; const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34; @@ -167,13 +166,12 @@ pub trait PciCapability { pub struct PciConfiguration { registers: [u32; NUM_CONFIGURATION_REGISTERS], writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register. - num_bars: usize, + bar_used: [bool; NUM_BAR_REGS], // Contains the byte offset and size of the last capability. last_capability: Option<(usize, usize)>, } /// See pci_regs.h in kernel -#[allow(dead_code)] #[derive(Copy, Clone)] pub enum PciBarRegionType { Memory32BitRegion = 0, @@ -181,14 +179,12 @@ pub enum PciBarRegionType { Memory64BitRegion = 0x04, } -#[allow(dead_code)] #[derive(Copy, Clone)] pub enum PciBarPrefetchable { NotPrefetchable = 0, Prefetchable = 0x08, } -#[allow(dead_code)] #[derive(Copy, Clone)] pub struct PciBarConfiguration { addr: u64, @@ -239,7 +235,7 @@ impl PciConfiguration { PciConfiguration { registers, writable_bits, - num_bars: 0, + bar_used: [false; NUM_BAR_REGS], last_capability: None, } } @@ -304,44 +300,61 @@ impl PciConfiguration { } } - // Add either an IO or memory region, depending on `mem_type` mask, which is ORed in to the - // value before saving it. - fn add_bar(&mut self, addr: u64, size: u64, addr_mask: u32, mem_type: u32) -> Option<usize> { - if self.num_bars >= NUM_BAR_REGS { + /// Adds a region specified by `config`. Configures the specified BAR(s) to + /// report this region and size to the guest kernel. Enforces a few constraints + /// (i.e, region size must be power of two, register not already used). Returns 'None' on + /// failure all, `Some(BarIndex)` on success. + pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Option<usize> { + if self.bar_used[config.reg_idx] { return None; } - if size.count_ones() != 1 { + + if config.size.count_ones() != 1 { return None; } - // TODO(dgreid) Allow 64 bit address and size. - if addr.checked_add(size)? > u64::from(u32::max_value()) { + if config.reg_idx >= NUM_BAR_REGS { return None; } - let this_bar = self.num_bars; - let bar_idx = BAR0_REG + this_bar; - - self.registers[bar_idx] = addr as u32 & addr_mask | mem_type; - // The first writable bit represents the size of the region. - self.writable_bits[bar_idx] = !(size - 1) as u32; - - self.num_bars += 1; - Some(this_bar) - } + let bar_idx = BAR0_REG + config.reg_idx; + match config.region_type { + PciBarRegionType::Memory32BitRegion | PciBarRegionType::IORegion => { + if config.addr.checked_add(config.size)? > u64::from(u32::max_value()) { + return None; + } + } + PciBarRegionType::Memory64BitRegion => { + if config.reg_idx + 1 >= NUM_BAR_REGS { + return None; + } + + if config.addr.checked_add(config.size)? > u64::max_value() { + return None; + } + + if self.bar_used[config.reg_idx + 1] { + return None; + } + + self.registers[bar_idx + 1] = (config.addr >> 32) as u32; + self.writable_bits[bar_idx + 1] = !((config.size >> 32) - 1) as u32; + self.bar_used[config.reg_idx + 1] = true; + } + } - /// Adds a memory region of `size` at `addr`. Configures the next available BAR register to - /// report this region and size to the guest kernel. Returns 'None' if all BARs are full, or - /// `Some(BarIndex)` on success. `size` must be a power of 2. - pub fn add_memory_region(&mut self, addr: u64, size: u64) -> Option<usize> { - self.add_bar(addr, size, BAR_MEM_ADDR_MASK, 0) - } + let (mask, lower_bits) = match config.region_type { + PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => ( + BAR_MEM_ADDR_MASK, + config.prefetchable as u32 | config.region_type as u32, + ), + PciBarRegionType::IORegion => (BAR_IO_ADDR_MASK, config.region_type as u32), + }; - /// Adds an IO region of `size` at `addr`. Configures the next available BAR register to - /// report this region and size to the guest kernel. Returns 'None' if all BARs are full, or - /// `Some(BarIndex)` on success. `size` must be a power of 2. - pub fn add_io_region(&mut self, addr: u64, size: u64) -> Option<usize> { - self.add_bar(addr, size, BAR_IO_ADDR_MASK, BAR_IO_BIT) + self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits; + self.writable_bits[bar_idx] = !(config.size - 1) as u32; + self.bar_used[config.reg_idx] = true; + Some(config.reg_idx) } /// Returns the address of the given BAR region. @@ -407,7 +420,6 @@ impl Default for PciBarConfiguration { } } -#[allow(dead_code)] impl PciBarConfiguration { pub fn new( reg_idx: usize, |