diff --git a/kernel/comps/pci/src/capability/mod.rs b/kernel/comps/pci/src/capability/mod.rs index 4422d4907..6726f9325 100644 --- a/kernel/comps/pci/src/capability/mod.rs +++ b/kernel/comps/pci/src/capability/mod.rs @@ -9,10 +9,8 @@ use alloc::vec::Vec; use align_ext::AlignExt; use self::{msix::CapabilityMsixData, vendor::CapabilityVndrData}; -use super::{ - cfg_space::{PciDeviceCommonCfgOffset, Status}, - common_device::PciCommonDevice, -}; +use super::{cfg_space::Status, common_device::PciCommonDevice}; +use crate::cfg_space::PciGeneralDeviceCfgOffset; pub mod msix; pub mod vendor; @@ -91,18 +89,21 @@ impl Capability { if !dev.status().contains(Status::CAPABILITIES_LIST) { return Vec::new(); } - let mut capabilities = Vec::new(); + + // The offset of the first capability pointer is the same for PCI general devices and PCI bridge devices. + const CAP_OFFSET: u16 = PciGeneralDeviceCfgOffset::CapabilitiesPointer as u16; let mut cap_ptr = - (dev.location() - .read8(PciDeviceCommonCfgOffset::CapabilitiesPointer as u16) as u16) - .align_down(align_of::() as _); + (dev.location().read8(CAP_OFFSET) as u16).align_down(align_of::() as _); let mut cap_ptr_vec = Vec::new(); + let mut capabilities = Vec::new(); + // read all cap_ptr so that it is easy for us to get the length. while cap_ptr > 0 { cap_ptr_vec.push(cap_ptr); cap_ptr = (dev.location().read8(cap_ptr + 1) as u16).align_down(align_of::() as _); } cap_ptr_vec.sort(); + // Push here so that we can calculate the length of the last capability. cap_ptr_vec.push(Self::CAPABILITY_TOP); let length = cap_ptr_vec.len(); @@ -143,6 +144,7 @@ impl Capability { cap_data: data, }); } + capabilities } } diff --git a/kernel/comps/pci/src/cfg_space.rs b/kernel/comps/pci/src/cfg_space.rs index c7eb9f4a4..3daf0b16f 100644 --- a/kernel/comps/pci/src/cfg_space.rs +++ b/kernel/comps/pci/src/cfg_space.rs @@ -17,9 +17,9 @@ use spin::Once; use super::PciDeviceLocation; -/// Offset in PCI device's common configuration space(Not the PCI bridge). +/// Offset in PCI device's common configuration space. #[repr(u16)] -pub enum PciDeviceCommonCfgOffset { +pub enum PciCommonCfgOffset { /// Vendor ID VendorId = 0x00, /// Device ID @@ -30,8 +30,12 @@ pub enum PciDeviceCommonCfgOffset { Status = 0x06, /// Revision ID RevisionId = 0x08, - /// Class code - ClassCode = 0x09, + /// Programming Interface + ProgIf = 0x09, + /// Subclass code + SubclassCode = 0x0A, + /// Base class code + BaseClassCode = 0x0B, /// Cache Line Size CacheLineSize = 0x0C, /// Latency Timer @@ -40,6 +44,15 @@ pub enum PciDeviceCommonCfgOffset { HeaderType = 0x0E, /// BIST: Represents the status and allows control of a devices BIST(built-in self test). Bist = 0x0F, + /// Interrupt Line + InterruptLine = 0x3C, + /// Interrupt Pin + InterruptPin = 0x3D, +} + +/// Offset in PCI general device's configuration space (Not the PCI bridge or Cardbus bridge). +#[repr(u16)] +pub enum PciGeneralDeviceCfgOffset { /// Base Address Register #0 Bar0 = 0x10, /// Base Address Register #1 @@ -62,16 +75,92 @@ pub enum PciDeviceCommonCfgOffset { XromBar = 0x30, /// Capabilities pointer CapabilitiesPointer = 0x34, - /// Interrupt Line - InterruptLine = 0x3C, - /// INterrupt PIN - InterruptPin = 0x3D, /// Min Grant MinGrant = 0x3E, /// Max latency MaxLatency = 0x3F, } +/// Offset in PCI-to-PCI bridge's configuration space. +#[repr(u16)] +pub enum PciBridgeCfgOffset { + /// Base Address Register #0 + Bar0 = 0x10, + /// Base Address Register #1 + Bar1 = 0x14, + /// Primary bus number + PrimaryBusNumber = 0x18, + /// Secondary bus number + SecondaryBusNumber = 0x19, + /// Subordinate bus number + SubordinateBusNumber = 0x1A, + /// Secondary latency timer + SecondaryLatencyTimer = 0x1B, + /// I/O base + IoBase = 0x1C, + /// I/O limit + IoLimit = 0x1D, + /// Secondary status + SecondaryStatus = 0x1E, + /// Memory base + MemoryBase = 0x20, + /// Memory limit + MemoryLimit = 0x22, + /// Prefetchable memory base + PrefetchableMemoryBase = 0x24, + /// Prefetchable memory limit + PrefetchableMemoryLimit = 0x26, + /// Prefetchable memory base upper 32 bits + PrefetchableMemoryBaseUpper32 = 0x28, + /// Prefetchable memory limit upper 32 bits + PrefetchableMemoryLimitUpper32 = 0x2C, + /// I/O base upper 16 bits + IoBaseUpper16 = 0x30, + /// I/O limit upper 16 bits + IoLimitUpper16 = 0x32, + /// Capabilities pointer + CapabilitiesPointer = 0x34, + /// Bridge control + BridgeControl = 0x3E, +} + +/// Offset in PCI-to-Cardbus bridge's configuration space. +#[repr(u16)] +pub enum PciCardbusBridgeCfgOffset { + /// Cardbus socket/ExCA base address + CardbusSocketExcaBaseAddress = 0x10, + /// Capabilities pointer + CapabilitiesPointer = 0x14, + /// Secondary status + SecondaryStatus = 0x16, + /// Cardbus latency timer + CardbusLatencyTimer = 0x17, + /// Memory base 0 + MemoryBase0 = 0x18, + /// Memory limit 0 + MemoryLimit0 = 0x1C, + /// Memory base 1 + MemoryBase1 = 0x20, + /// Memory limit 1 + MemoryLimit1 = 0x24, + /// I/O base 0 + IoBase0 = 0x28, + /// I/O limit 0 + IoLimit0 = 0x2C, + /// I/O base 1 + IoBase1 = 0x30, + /// I/O limit 1 + IoLimit1 = 0x34, + /// Bridge control + BridgeControl = 0x3E, + /// Subsystem device ID + SubsystemDeviceId = 0x40, + /// Subsystem Vendor ID + SubsystemVendorId = 0x42, + /// Legacy mode base address + LegacyModeBaseAddress = 0x44, +} + bitflags! { /// PCI device common config space command register. pub struct Command: u16 { @@ -163,7 +252,7 @@ impl Bar { return Err(Error::InvalidArgs); } - let offset = index as u16 * 4 + PciDeviceCommonCfgOffset::Bar0 as u16; + let offset = index as u16 * 4 + PciGeneralDeviceCfgOffset::Bar0 as u16; let raw = location.read32(offset); // Check the "Space Indicator" bit. @@ -254,7 +343,7 @@ impl MemoryBar { _ => return Err(Error::InvalidArgs), }; - let offset = index as u16 * 4 + PciDeviceCommonCfgOffset::Bar0 as u16; + let offset = index as u16 * 4 + PciGeneralDeviceCfgOffset::Bar0 as u16; // "Software saves the original value of the Base Address register, writes a value of all // 1's to the register, then reads it back." @@ -396,7 +485,7 @@ impl IoBar { fn new(location: &PciDeviceLocation, index: u8, raw: u32) -> Result { debug_assert_eq!(raw & 1, 1); - let offset = index as u16 * 4 + PciDeviceCommonCfgOffset::Bar0 as u16; + let offset = index as u16 * 4 + PciGeneralDeviceCfgOffset::Bar0 as u16; // "Software saves the original value of the Base Address register, writes a value of all // 1's to the register, then reads it back." diff --git a/kernel/comps/pci/src/common_device.rs b/kernel/comps/pci/src/common_device.rs index 5487597ef..4f218aaa0 100644 --- a/kernel/comps/pci/src/common_device.rs +++ b/kernel/comps/pci/src/common_device.rs @@ -8,7 +8,7 @@ use alloc::vec::Vec; use super::{ capability::Capability, - cfg_space::{AddrLen, Bar, Command, PciDeviceCommonCfgOffset, Status}, + cfg_space::{AddrLen, Bar, Command, PciCommonCfgOffset, Status}, device_info::PciDeviceId, }; use crate::device_info::PciDeviceLocation; @@ -45,24 +45,18 @@ impl PciCommonDevice { /// Gets the PCI Command pub fn command(&self) -> Command { - Command::from_bits_truncate( - self.location - .read16(PciDeviceCommonCfgOffset::Command as u16), - ) + Command::from_bits_truncate(self.location.read16(PciCommonCfgOffset::Command as u16)) } /// Sets the PCI Command pub fn set_command(&self, command: Command) { self.location - .write16(PciDeviceCommonCfgOffset::Command as u16, command.bits()) + .write16(PciCommonCfgOffset::Command as u16, command.bits()) } /// Gets the PCI status pub fn status(&self) -> Status { - Status::from_bits_truncate( - self.location - .read16(PciDeviceCommonCfgOffset::Status as u16), - ) + Status::from_bits_truncate(self.location.read16(PciCommonCfgOffset::Status as u16)) } pub(super) fn new(location: PciDeviceLocation) -> Option { @@ -114,7 +108,7 @@ impl BarManager { /// Parse the BAR space by PCI device location. fn new(location: PciDeviceLocation) -> Self { - let header_type = location.read8(PciDeviceCommonCfgOffset::HeaderType as u16) & !(1 << 7); + let header_type = location.read8(PciCommonCfgOffset::HeaderType as u16) & !(1 << 7); // Get the max bar amount, header type=0 => end device; header type=1 => PCI bridge. let max = match header_type { 0 => 6, diff --git a/kernel/comps/pci/src/device_info.rs b/kernel/comps/pci/src/device_info.rs index ce584aba1..41ea52e03 100644 --- a/kernel/comps/pci/src/device_info.rs +++ b/kernel/comps/pci/src/device_info.rs @@ -2,7 +2,7 @@ //! PCI device Information -use super::cfg_space::PciDeviceCommonCfgOffset; +use crate::cfg_space::PciCommonCfgOffset; /// PCI device Location #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -129,23 +129,16 @@ pub struct PciDeviceId { pub subclass: u8, /// Specifies the type of function the device performs. pub class: u8, - /// Subsystem Vendor ID - pub subsystem_vendor_id: u16, - /// Subsystem ID - pub subsystem_id: u16, } impl PciDeviceId { pub(super) fn new(location: PciDeviceLocation) -> Self { - let vendor_id = location.read16(PciDeviceCommonCfgOffset::VendorId as u16); - let device_id = location.read16(PciDeviceCommonCfgOffset::DeviceId as u16); - let revision_id = location.read8(PciDeviceCommonCfgOffset::RevisionId as u16); - let prog_if = location.read8(PciDeviceCommonCfgOffset::ClassCode as u16); - let subclass = location.read8(PciDeviceCommonCfgOffset::ClassCode as u16 + 1); - let class = location.read8(PciDeviceCommonCfgOffset::ClassCode as u16 + 2); - let subsystem_vendor_id = - location.read16(PciDeviceCommonCfgOffset::SubsystemVendorId as u16); - let subsystem_id = location.read16(PciDeviceCommonCfgOffset::SubsystemId as u16); + let vendor_id = location.read16(PciCommonCfgOffset::VendorId as u16); + let device_id = location.read16(PciCommonCfgOffset::DeviceId as u16); + let revision_id = location.read8(PciCommonCfgOffset::RevisionId as u16); + let prog_if = location.read8(PciCommonCfgOffset::ProgIf as u16); + let subclass = location.read8(PciCommonCfgOffset::SubclassCode as u16); + let class = location.read8(PciCommonCfgOffset::BaseClassCode as u16); Self { vendor_id, device_id, @@ -153,8 +146,6 @@ impl PciDeviceId { prog_if, subclass, class, - subsystem_vendor_id, - subsystem_id, } } }