From bde08cded6c6cbcaf00f6191fe257ae27e5db073 Mon Sep 17 00:00:00 2001 From: Mingtao Huang <114841534+1037827920@users.noreply.github.com> Date: Thu, 16 May 2024 17:47:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(driver/pci):=20=E5=AE=8C=E5=96=84pci=20roo?= =?UTF-8?q?t=E7=BB=93=E6=9E=84=E4=BD=93=EF=BC=8C=E5=A2=9E=E5=8A=A0portio?= =?UTF-8?q?=E7=9A=84pci=E9=85=8D=E7=BD=AE=E7=A9=BA=E9=97=B4=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=20(#818)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(driver/pci): 完善pci root结构体,增加portio的pci配置空间访问 --- kernel/src/arch/x86_64/pci/pci.rs | 43 ++++++++++-- kernel/src/driver/pci/ecam.rs | 24 ++++--- kernel/src/driver/pci/pci.rs | 3 + kernel/src/driver/pci/root.rs | 105 ++++++++++++++++++------------ 4 files changed, 118 insertions(+), 57 deletions(-) diff --git a/kernel/src/arch/x86_64/pci/pci.rs b/kernel/src/arch/x86_64/pci/pci.rs index dd08deec..521fa9f0 100644 --- a/kernel/src/arch/x86_64/pci/pci.rs +++ b/kernel/src/arch/x86_64/pci/pci.rs @@ -2,19 +2,40 @@ use crate::arch::TraitPciArch; use crate::driver::acpi::acpi_manager; use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo}; use crate::driver::pci::pci::{ - pci_init, BusDeviceFunction, PciAddr, PciError, PORT_PCI_CONFIG_ADDRESS, PORT_PCI_CONFIG_DATA, + pci_init, BusDeviceFunction, PciAddr, PciCam, PciError, PORT_PCI_CONFIG_ADDRESS, + PORT_PCI_CONFIG_DATA, }; -use crate::include::bindings::bindings::{io_in32, io_out32}; +use crate::driver::pci::root::{pci_root_manager, PciRoot}; +use crate::include::bindings::bindings::{io_in32, io_in8, io_out32}; use crate::init::initcall::INITCALL_SUBSYS; - use crate::mm::PhysAddr; use acpi::mcfg::Mcfg; -use log::error; +use log::{error, warn}; use system_error::SystemError; use unified_init::macros::unified_init; pub struct X86_64PciArch; + +impl X86_64PciArch { + /// # 在早期引导阶段直接访问PCI配置空间的函数 + /// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/early.c?fi=read_pci_config_byte#19 + fn read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u8 { + unsafe { + io_out32( + PORT_PCI_CONFIG_ADDRESS, + 0x80000000 + | ((bus as u32) << 16) + | ((slot as u32) << 11) + | ((func as u32) << 8) + | offset as u32, + ); + } + let value = unsafe { io_in8(PORT_PCI_CONFIG_DATA + (offset & 3) as u16) }; + return value; + } +} + impl TraitPciArch for X86_64PciArch { fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 { // 构造pci配置空间地址 @@ -51,8 +72,18 @@ impl TraitPciArch for X86_64PciArch { #[unified_init(INITCALL_SUBSYS)] fn x86_64_pci_init() -> Result<(), SystemError> { - if let Err(e) = discover_ecam_root() { - error!("x86_64_pci_init(): discover_ecam_root error: {:?}", e); + if discover_ecam_root().is_err() { + // ecam初始化失败,使用portio访问pci配置空间 + // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/broadcom_bus.c#27 + let bus_begin = X86_64PciArch::read_config_early(0, 0, 0, 0x44); + let bus_end = X86_64PciArch::read_config_early(0, 0, 0, 0x45); + + if !pci_root_manager().has_root(bus_begin as u16) { + let root = PciRoot::new(None, PciCam::Portiocam, bus_begin, bus_end); + pci_root_manager().add_pci_root(root.unwrap()); + } else { + warn!("x86_64_pci_init(): pci_root_manager {}", bus_begin); + } } pci_init(); diff --git a/kernel/src/driver/pci/ecam.rs b/kernel/src/driver/pci/ecam.rs index e3403416..e5f1f86c 100644 --- a/kernel/src/driver/pci/ecam.rs +++ b/kernel/src/driver/pci/ecam.rs @@ -13,27 +13,32 @@ pub fn pci_ecam_root_info_manager() -> &'static EcamRootInfoManager { } /// Ecam pci root info -#[derive(Clone, Copy)] +#[derive(Clone, Debug, Copy)] pub struct EcamRootInfo { - pub segement_group_number: SegmentGroupNumber, + /// 段组号 + pub segment_group_number: SegmentGroupNumber, + /// 该分组中的最小bus pub bus_begin: u8, + /// 该分组中的最大bus pub bus_end: u8, + /// 物理基地址 pub physical_address_base: PhysAddr, } impl EcamRootInfo { pub fn new( - segement_group_number: SegmentGroupNumber, + segment_group_number: SegmentGroupNumber, bus_begin: u8, bus_end: u8, physical_address_base: PhysAddr, ) -> Self { - Self { - segement_group_number, + let ecam_root_info = Self { + segment_group_number, bus_begin, bus_end, physical_address_base, - } + }; + return ecam_root_info; } } @@ -48,11 +53,10 @@ impl EcamRootInfoManager { /// /// - `ecam_root_info`: EcamRootInfo - 要添加的EcamRootInfo实例 pub fn add_ecam_root_info(&self, ecam_root_info: EcamRootInfo) { - if !pci_root_manager().has_root(ecam_root_info.segement_group_number) { + if !pci_root_manager().has_root(ecam_root_info.segment_group_number) { let root = PciRoot::new( - ecam_root_info.segement_group_number, + Some(ecam_root_info), PciCam::Ecam, - ecam_root_info.physical_address_base, ecam_root_info.bus_begin, ecam_root_info.bus_end, ); @@ -66,7 +70,7 @@ impl EcamRootInfoManager { } else { warn!( "add_ecam_root_info(): root {} already exists", - ecam_root_info.segement_group_number + ecam_root_info.segment_group_number ); } } diff --git a/kernel/src/driver/pci/pci.rs b/kernel/src/driver/pci/pci.rs index 3b5c97e8..b339529f 100644 --- a/kernel/src/driver/pci/pci.rs +++ b/kernel/src/driver/pci/pci.rs @@ -639,6 +639,8 @@ impl PciDeviceStructure for PciDeviceStructurePciToCardbusBridge { /// 用于访问PCI设备的功能配置空间的一组机制。 #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum PciCam { + /// PortIO配置访问机制 + Portiocam, /// PCI内存映射配置访问机制 /// /// 为每个设备功能提供256字节的配置空间访问。 @@ -653,6 +655,7 @@ impl PciCam { /// Returns the total size in bytes of the memory-mapped region. pub const fn size(self) -> u32 { match self { + Self::Portiocam => 0x100000, Self::MmioCam => 0x1000000, Self::Ecam => 0x10000000, } diff --git a/kernel/src/driver/pci/root.rs b/kernel/src/driver/pci/root.rs index 2deb1cb6..c74c6cf9 100644 --- a/kernel/src/driver/pci/root.rs +++ b/kernel/src/driver/pci/root.rs @@ -4,16 +4,17 @@ use alloc::sync::Arc; use hashbrown::HashMap; use crate::{ + arch::{PciArch, TraitPciArch}, libs::spinlock::{SpinLock, SpinLockGuard}, mm::{ mmio_buddy::{mmio_pool, MMIOSpaceGuard}, page::PAGE_2M_SIZE, - PhysAddr, }, }; -use super::pci::{ - BusDeviceFunction, ExternalCapabilityIterator, PciCam, PciError, SegmentGroupNumber, +use super::{ + ecam::EcamRootInfo, + pci::{BusDeviceFunction, ExternalCapabilityIterator, PciCam, PciError, SegmentGroupNumber}, }; lazy_static! { @@ -28,13 +29,14 @@ pub fn pci_root_manager() -> &'static PciRootManager { /// 代表一个PCI segement greoup. #[derive(Clone, Debug)] pub struct PciRoot { - pub physical_address_base: PhysAddr, //物理地址,acpi获取 - pub mmio_guard: Option>, //映射后的虚拟地址,为方便访问数据这里转化成指针 - pub segment_group_number: SegmentGroupNumber, //segement greoup的id - pub bus_begin: u8, //该分组中的最小bus - pub bus_end: u8, //该分组中的最大bus + pub ecam_root_info: Option, + pub mmio_guard: Option>, //映射后的虚拟地址,为方便访问数据这里转化成指针 /// 配置空间访问机制 pub cam: PciCam, + /// bus起始位置 + pub bus_begin: u8, + /// bus结束位置 + pub bus_end: u8, } ///线程间共享需要,该结构体只需要在初始化时写入数据,无需读写锁保证线程安全 @@ -43,11 +45,15 @@ unsafe impl Sync for PciRoot {} ///实现PciRoot的Display trait,自定义输出 impl core::fmt::Display for PciRoot { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - write!( - f, - "PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {:?},mapped at {:?}", - self.segment_group_number, self.bus_begin, self.bus_end, self.physical_address_base, self.mmio_guard - ) + if let Some(ecam_root_info) = &self.ecam_root_info { + write!( + f, + "PCI Eacm Root with segment:{}, bus begin at {}, bus end at {}, physical address at {:?},mapped at {:?}", + ecam_root_info.segment_group_number, ecam_root_info.bus_begin, ecam_root_info.bus_end, ecam_root_info.physical_address_base, self.mmio_guard + ) + } else { + write!(f, "PCI Root cam is {:?}", self.cam,) + } } } @@ -69,27 +75,28 @@ impl PciRoot { /// /// - 成功执行后,结构体的内部状态将被初始化为包含映射后的虚拟地址。 pub fn new( - segment_group_number: SegmentGroupNumber, + ecam_root_info: Option, cam: PciCam, - phys_base: PhysAddr, bus_begin: u8, bus_end: u8, ) -> Result, PciError> { - assert_eq!(cam, PciCam::Ecam); let mut pci_root = Self { - physical_address_base: phys_base, + ecam_root_info, mmio_guard: None, - segment_group_number, + cam, bus_begin, bus_end, - cam, }; - pci_root.map()?; + + if ecam_root_info.is_some() { + pci_root.map()?; + } Ok(Arc::new(pci_root)) } - /// @brief 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量 - /// @return 返回错误或Ok(0) + + /// # 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量 + /// ## return 返回错误或Ok(0) fn map(&mut self) -> Result { //debug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end); let bus_number = (self.bus_end - self.bus_begin) as u32 + 1; @@ -104,7 +111,7 @@ impl PciRoot { self.mmio_guard = Some(space_guard.clone()); assert!(space_guard - .map_phys(self.physical_address_base, size) + .map_phys(self.ecam_root_info.unwrap().physical_address_base, size) .is_ok()); } return Ok(0); @@ -129,11 +136,12 @@ impl PciRoot { /// - 此函数计算出的地址需要是字对齐的(即地址与0x3对齐)。如果不是,将panic。 fn cam_offset(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 { assert!(bus_device_function.valid()); - let bdf = ((bus_device_function.bus - self.bus_begin) as u32) << 8 + let bdf = ((bus_device_function.bus - self.ecam_root_info.unwrap().bus_begin) as u32) << 8 | (bus_device_function.device as u32) << 3 | bus_device_function.function as u32; let address = bdf << match self.cam { + PciCam::Portiocam => 4, PciCam::MmioCam => 8, PciCam::Ecam => 12, } | register_offset as u32; @@ -141,6 +149,7 @@ impl PciRoot { assert!(address & 0x3 == 0); address } + /// # read_config - 通过bus_device_function和offset读取相应位置寄存器的值(32位) /// /// 此函数用于通过指定的bus_device_function和register_offset读取PCI设备中相应位置的寄存器值。 @@ -154,12 +163,16 @@ impl PciRoot { /// /// - `u32`: 寄存器读值结果 pub fn read_config(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 { - let address = self.cam_offset(bus_device_function, register_offset); - unsafe { - // Right shift to convert from byte offset to word offset. - ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) - .add((address >> 2) as usize)) - .read_volatile() + if self.ecam_root_info.is_some() { + let address = self.cam_offset(bus_device_function, register_offset); + unsafe { + // Right shift to convert from byte offset to word offset. + ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) + .add((address >> 2) as usize)) + .read_volatile() + } + } else { + PciArch::read_config(&bus_device_function, register_offset as u8) } } @@ -178,16 +191,21 @@ impl PciRoot { register_offset: u16, data: u32, ) { - let address = self.cam_offset(bus_device_function, register_offset); - // Safe because both the `mmio_base` and the address offset are properly aligned, and the - // resulting pointer is within the MMIO range of the CAM. - unsafe { - // Right shift to convert from byte offset to word offset. - ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) - .add((address >> 2) as usize)) - .write_volatile(data) + if self.ecam_root_info.is_some() { + let address = self.cam_offset(bus_device_function, register_offset); + // Safe because both the `mmio_base` and the address offset are properly aligned, and the + // resulting pointer is within the MMIO range of the CAM. + unsafe { + // Right shift to convert from byte offset to word offset. + ((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32) + .add((address >> 2) as usize)) + .write_volatile(data) + } + } else { + PciArch::write_config(&bus_device_function, register_offset as u8, data); } } + /// 返回迭代器,遍历pcie设备的external_capabilities #[allow(dead_code)] pub fn external_capabilities( @@ -233,9 +251,14 @@ impl PciRootManager { /// - `pci_root`: Arc,要添加的PciRoot的Arc指针 pub fn add_pci_root(&self, pci_root: Arc) { let mut inner = self.inner.lock(); - inner - .pci_root - .insert(pci_root.segment_group_number, pci_root); + + if let Some(ecam_root_info) = pci_root.ecam_root_info { + inner + .pci_root + .insert(ecam_root_info.segment_group_number, pci_root); + } else { + inner.pci_root.insert(pci_root.bus_begin as u16, pci_root); + } } /// # 检查是否存在PciRoot - 检查PciRootManager中是否存在指定segment_group_number的PciRoot