devices: pci: add MMIO config access mechanism

This will be used on ARM.

Change-Id: I61206b761f49f963f0cce706268379ceae1a0239
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1241540
Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Daniel Verkamp 2018-09-24 14:11:55 -07:00 committed by chrome-bot
parent 28a671a95f
commit f3a3a870b1
3 changed files with 52 additions and 2 deletions

View file

@ -32,7 +32,7 @@ pub use self::bus::Error as BusError;
pub use self::cmos::Cmos;
pub use self::pl030::Pl030;
pub use self::i8042::I8042Device;
pub use self::pci::{PciConfigIo, PciDevice, PciDeviceError, PciInterruptPin, PciRoot};
pub use self::pci::{PciConfigIo, PciConfigMmio, PciDevice, PciDeviceError, PciInterruptPin, PciRoot};
pub use self::proxy::ProxyDevice;
pub use self::proxy::Error as ProxyError;
pub use self::serial::Serial;

View file

@ -11,7 +11,7 @@ mod pci_root;
pub use self::pci_configuration::{PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface, PciSubclass};
pub use self::pci_device::Error as PciDeviceError;
pub use self::pci_device::PciDevice;
pub use self::pci_root::{PciConfigIo, PciRoot};
pub use self::pci_root::{PciConfigIo, PciConfigMmio, PciRoot};
/// PCI has four interrupt pins A->D.
#[derive(Copy, Clone)]

View file

@ -222,6 +222,56 @@ impl BusDevice for PciConfigIo {
}
}
/// Emulates PCI memory-mapped configuration access mechanism.
pub struct PciConfigMmio {
/// PCI root bridge.
pci_root: PciRoot,
}
impl PciConfigMmio {
pub fn new(pci_root: PciRoot) -> Self {
PciConfigMmio {
pci_root,
}
}
fn config_space_read(&self, config_address: u32) -> u32 {
let (bus, device, function, register) = parse_config_address(config_address);
self.pci_root.config_space_read(bus, device, function, register)
}
fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
let (bus, device, function, register) = parse_config_address(config_address);
self.pci_root.config_space_write(bus, device, function, register, offset, data)
}
}
impl BusDevice for PciConfigMmio {
fn read(&mut self, offset: u64, data: &mut [u8]) {
// Only allow reads to the register boundary.
let start = offset as usize % 4;
let end = start + data.len();
if end > 4 || offset > u32::max_value() as u64 {
for d in data {
*d = 0xff;
}
return;
}
let value = self.config_space_read(offset as u32);
for i in start..end {
data[i - start] = (value >> (i * 8)) as u8;
}
}
fn write(&mut self, offset: u64, data: &[u8]) {
if offset > u32::max_value() as u64 {
return;
}
self.config_space_write(offset as u32, offset % 4, data)
}
}
// Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
const BUS_NUMBER_OFFSET: usize = 16;