diff options
author | Daniel Verkamp <dverkamp@chromium.org> | 2019-10-24 16:27:12 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-11-17 22:34:22 +0000 |
commit | 8ec87d6d334126f0a3c235e19470f707dc5f02e4 (patch) | |
tree | a21298cc9d74cccf9dd223984a53b85e9dc5524a /devices/src/pci | |
parent | 8958407dcb3ba19cddf65579932ccad3d99bb9d5 (diff) | |
download | crosvm-8ec87d6d334126f0a3c235e19470f707dc5f02e4.tar crosvm-8ec87d6d334126f0a3c235e19470f707dc5f02e4.tar.gz crosvm-8ec87d6d334126f0a3c235e19470f707dc5f02e4.tar.bz2 crosvm-8ec87d6d334126f0a3c235e19470f707dc5f02e4.tar.lz crosvm-8ec87d6d334126f0a3c235e19470f707dc5f02e4.tar.xz crosvm-8ec87d6d334126f0a3c235e19470f707dc5f02e4.tar.zst crosvm-8ec87d6d334126f0a3c235e19470f707dc5f02e4.zip |
devices: pci: make get_bar_addr work for all BAR types
Previously, PciConfiguration::get_bar_addr would only correctly return the value of a 32-bit memory region; implement support for the other valid BAR types as well. BUG=None TEST=cargo test -p devices Change-Id: I221187dfb96b31d7fead73eccf605a0886021d8b Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1880164 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'devices/src/pci')
-rw-r--r-- | devices/src/pci/ac97.rs | 8 | ||||
-rw-r--r-- | devices/src/pci/pci_configuration.rs | 123 |
2 files changed, 124 insertions, 7 deletions
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs index 9a3c7e5..eb19b5f 100644 --- a/devices/src/pci/ac97.rs +++ b/devices/src/pci/ac97.rs @@ -203,8 +203,8 @@ impl PciDevice for Ac97Dev { } fn read_bar(&mut self, addr: u64, data: &mut [u8]) { - let bar0 = u64::from(self.config_regs.get_bar_addr(0)); - let bar1 = u64::from(self.config_regs.get_bar_addr(1)); + let bar0 = self.config_regs.get_bar_addr(0); + let bar1 = self.config_regs.get_bar_addr(1); match addr { a if a >= bar0 && a < bar0 + MIXER_REGS_SIZE => self.read_mixer(addr - bar0, data), a if a >= bar1 && a < bar1 + MASTER_REGS_SIZE => { @@ -215,8 +215,8 @@ impl PciDevice for Ac97Dev { } fn write_bar(&mut self, addr: u64, data: &[u8]) { - let bar0 = u64::from(self.config_regs.get_bar_addr(0)); - let bar1 = u64::from(self.config_regs.get_bar_addr(1)); + let bar0 = self.config_regs.get_bar_addr(0); + let bar1 = self.config_regs.get_bar_addr(1); match addr { a if a >= bar0 && a < bar0 + MIXER_REGS_SIZE => self.write_mixer(addr - bar0, data), a if a >= bar1 && a < bar1 + MASTER_REGS_SIZE => { diff --git a/devices/src/pci/pci_configuration.rs b/devices/src/pci/pci_configuration.rs index 5e268fe..0deee54 100644 --- a/devices/src/pci/pci_configuration.rs +++ b/devices/src/pci/pci_configuration.rs @@ -177,7 +177,7 @@ pub struct PciConfiguration { } /// See pci_regs.h in kernel -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum PciBarRegionType { Memory32BitRegion = 0, IORegion = 0x01, @@ -430,11 +430,38 @@ impl PciConfiguration { Ok(config.reg_idx) } + /// Returns the type of the given BAR region. + pub fn get_bar_type(&self, bar_num: usize) -> Option<PciBarRegionType> { + let reg_idx = BAR0_REG + bar_num; + let reg_value = self.registers.get(reg_idx)?; + + match (reg_value & 1, (reg_value >> 1u32) & 3) { + (1, _) => Some(PciBarRegionType::IORegion), + (0, 0b00) => Some(PciBarRegionType::Memory32BitRegion), + (0, 0b10) => Some(PciBarRegionType::Memory64BitRegion), + _ => None, + } + } + /// Returns the address of the given BAR region. - pub fn get_bar_addr(&self, bar_num: usize) -> u32 { + pub fn get_bar_addr(&self, bar_num: usize) -> u64 { let bar_idx = BAR0_REG + bar_num; - self.registers[bar_idx] & BAR_MEM_ADDR_MASK + let bar_type = match self.get_bar_type(bar_num) { + Some(t) => t, + None => return 0, + }; + + match bar_type { + PciBarRegionType::IORegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK), + PciBarRegionType::Memory32BitRegion => { + u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK) + } + PciBarRegionType::Memory64BitRegion => { + u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK) + | u64::from(self.registers[bar_idx + 1]) << 32 + } + } } /// Configures the IRQ line and pin used by this device. @@ -667,4 +694,94 @@ mod tests { // The original vendor and device ID should remain. assert_eq!(cfg.read_reg(0), 0x56781234); } + + #[test] + fn add_pci_bar_mem_64bit() { + let mut cfg = PciConfiguration::new( + 0x1234, + 0x5678, + PciClassCode::MultimediaController, + &PciMultimediaSubclass::AudioController, + Some(&TestPI::Test), + PciHeaderType::Device, + 0xABCD, + 0x2468, + ); + + cfg.add_pci_bar( + &PciBarConfiguration::new( + 0, + 0x4, + PciBarRegionType::Memory64BitRegion, + PciBarPrefetchable::NotPrefetchable, + ) + .set_address(0x01234567_89ABCDE0), + ) + .expect("add_pci_bar failed"); + + assert_eq!( + cfg.get_bar_type(0), + Some(PciBarRegionType::Memory64BitRegion) + ); + assert_eq!(cfg.get_bar_addr(0), 0x01234567_89ABCDE0); + } + + #[test] + fn add_pci_bar_mem_32bit() { + let mut cfg = PciConfiguration::new( + 0x1234, + 0x5678, + PciClassCode::MultimediaController, + &PciMultimediaSubclass::AudioController, + Some(&TestPI::Test), + PciHeaderType::Device, + 0xABCD, + 0x2468, + ); + + cfg.add_pci_bar( + &PciBarConfiguration::new( + 0, + 0x4, + PciBarRegionType::Memory32BitRegion, + PciBarPrefetchable::NotPrefetchable, + ) + .set_address(0x12345670), + ) + .expect("add_pci_bar failed"); + + assert_eq!( + cfg.get_bar_type(0), + Some(PciBarRegionType::Memory32BitRegion) + ); + assert_eq!(cfg.get_bar_addr(0), 0x12345670); + } + + #[test] + fn add_pci_bar_io() { + let mut cfg = PciConfiguration::new( + 0x1234, + 0x5678, + PciClassCode::MultimediaController, + &PciMultimediaSubclass::AudioController, + Some(&TestPI::Test), + PciHeaderType::Device, + 0xABCD, + 0x2468, + ); + + cfg.add_pci_bar( + &PciBarConfiguration::new( + 0, + 0x4, + PciBarRegionType::IORegion, + PciBarPrefetchable::NotPrefetchable, + ) + .set_address(0x1230), + ) + .expect("add_pci_bar failed"); + + assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IORegion)); + assert_eq!(cfg.get_bar_addr(0), 0x1230); + } } |