Prechádzať zdrojové kódy

feat(driver/pci): 完善pci root结构体,增加portio的pci配置空间访问 (#818)

* feat(driver/pci): 完善pci root结构体,增加portio的pci配置空间访问
Mingtao Huang 10 mesiacov pred
rodič
commit
bde08cded6

+ 37 - 6
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();
 

+ 14 - 10
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
             );
         }
     }

+ 3 - 0
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,
         }

+ 64 - 41
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<Arc<MMIOSpaceGuard>>,  //映射后的虚拟地址,为方便访问数据这里转化成指针
-    pub segment_group_number: SegmentGroupNumber, //segement greoup的id
-    pub bus_begin: u8,                            //该分组中的最小bus
-    pub bus_end: u8,                              //该分组中的最大bus
+    pub ecam_root_info: Option<EcamRootInfo>,
+    pub mmio_guard: Option<Arc<MMIOSpaceGuard>>, //映射后的虚拟地址,为方便访问数据这里转化成指针
     /// 配置空间访问机制
     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<EcamRootInfo>,
         cam: PciCam,
-        phys_base: PhysAddr,
         bus_begin: u8,
         bus_end: u8,
     ) -> Result<Arc<Self>, 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<u8, PciError> {
         //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>,要添加的PciRoot的Arc指针
     pub fn add_pci_root(&self, pci_root: Arc<PciRoot>) {
         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