xref: /DragonOS/kernel/src/arch/x86_64/pci/pci.rs (revision 2b7818e80e00fcfe4d03533f587cc125ea5e4bec)
1*2b7818e8SLoGin use crate::arch::io::PortIOArch;
2*2b7818e8SLoGin use crate::arch::{CurrentPortIOArch, TraitPciArch};
38b3d1688Syuyi2439 use crate::driver::acpi::acpi_manager;
4370472f7SLoGin use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo};
578bf93f0SYJwu2023 use crate::driver::pci::pci::{
6bde08cdeSMingtao Huang     pci_init, BusDeviceFunction, PciAddr, PciCam, PciError, PORT_PCI_CONFIG_ADDRESS,
7bde08cdeSMingtao Huang     PORT_PCI_CONFIG_DATA,
878bf93f0SYJwu2023 };
9bde08cdeSMingtao Huang use crate::driver::pci::root::{pci_root_manager, PciRoot};
10370472f7SLoGin use crate::init::initcall::INITCALL_SUBSYS;
112dd9f0c7SLoGin use crate::mm::PhysAddr;
1278bf93f0SYJwu2023 
138b3d1688Syuyi2439 use acpi::mcfg::Mcfg;
146f189d27Slinfeng use log::warn;
15370472f7SLoGin use system_error::SystemError;
16370472f7SLoGin use unified_init::macros::unified_init;
178b3d1688Syuyi2439 
188b3d1688Syuyi2439 pub struct X86_64PciArch;
19bde08cdeSMingtao Huang 
20bde08cdeSMingtao Huang impl X86_64PciArch {
21bde08cdeSMingtao Huang     /// # 在早期引导阶段直接访问PCI配置空间的函数
22bde08cdeSMingtao Huang     /// 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/early.c?fi=read_pci_config_byte#19
read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u823bde08cdeSMingtao Huang     fn read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u8 {
24bde08cdeSMingtao Huang         unsafe {
25*2b7818e8SLoGin             CurrentPortIOArch::out32(
26bde08cdeSMingtao Huang                 PORT_PCI_CONFIG_ADDRESS,
27bde08cdeSMingtao Huang                 0x80000000
28bde08cdeSMingtao Huang                     | ((bus as u32) << 16)
29bde08cdeSMingtao Huang                     | ((slot as u32) << 11)
30bde08cdeSMingtao Huang                     | ((func as u32) << 8)
31bde08cdeSMingtao Huang                     | offset as u32,
32bde08cdeSMingtao Huang             );
33bde08cdeSMingtao Huang         }
34*2b7818e8SLoGin         let value = unsafe { CurrentPortIOArch::in8(PORT_PCI_CONFIG_DATA + (offset & 3) as u16) };
35bde08cdeSMingtao Huang         return value;
36bde08cdeSMingtao Huang     }
37bde08cdeSMingtao Huang }
38bde08cdeSMingtao Huang 
3978bf93f0SYJwu2023 impl TraitPciArch for X86_64PciArch {
read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u324078bf93f0SYJwu2023     fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 {
4178bf93f0SYJwu2023         // 构造pci配置空间地址
4278bf93f0SYJwu2023         let address = ((bus_device_function.bus as u32) << 16)
4378bf93f0SYJwu2023             | ((bus_device_function.device as u32) << 11)
4478bf93f0SYJwu2023             | ((bus_device_function.function as u32 & 7) << 8)
4578bf93f0SYJwu2023             | (offset & 0xfc) as u32
4678bf93f0SYJwu2023             | (0x80000000);
4778bf93f0SYJwu2023         let ret = unsafe {
48*2b7818e8SLoGin             CurrentPortIOArch::out32(PORT_PCI_CONFIG_ADDRESS, address);
49*2b7818e8SLoGin             let temp = CurrentPortIOArch::in32(PORT_PCI_CONFIG_DATA);
5078bf93f0SYJwu2023             temp
5178bf93f0SYJwu2023         };
5278bf93f0SYJwu2023         return ret;
5378bf93f0SYJwu2023     }
5478bf93f0SYJwu2023 
write_config(bus_device_function: &BusDeviceFunction, offset: u8, data: u32)5578bf93f0SYJwu2023     fn write_config(bus_device_function: &BusDeviceFunction, offset: u8, data: u32) {
5678bf93f0SYJwu2023         let address = ((bus_device_function.bus as u32) << 16)
5778bf93f0SYJwu2023             | ((bus_device_function.device as u32) << 11)
5878bf93f0SYJwu2023             | ((bus_device_function.function as u32 & 7) << 8)
5978bf93f0SYJwu2023             | (offset & 0xfc) as u32
6078bf93f0SYJwu2023             | (0x80000000);
6178bf93f0SYJwu2023         unsafe {
62*2b7818e8SLoGin             CurrentPortIOArch::out32(PORT_PCI_CONFIG_ADDRESS, address);
6378bf93f0SYJwu2023             // 写入数据
64*2b7818e8SLoGin             CurrentPortIOArch::out32(PORT_PCI_CONFIG_DATA, data);
6578bf93f0SYJwu2023         }
6678bf93f0SYJwu2023     }
6778bf93f0SYJwu2023 
address_pci_to_physical(pci_address: PciAddr) -> PhysAddr682dd9f0c7SLoGin     fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr {
692dd9f0c7SLoGin         return PhysAddr::new(pci_address.data());
7078bf93f0SYJwu2023     }
71370472f7SLoGin }
7278bf93f0SYJwu2023 
73370472f7SLoGin #[unified_init(INITCALL_SUBSYS)]
x86_64_pci_init() -> Result<(), SystemError>74370472f7SLoGin fn x86_64_pci_init() -> Result<(), SystemError> {
75bde08cdeSMingtao Huang     if discover_ecam_root().is_err() {
76bde08cdeSMingtao Huang         // ecam初始化失败,使用portio访问pci配置空间
77bde08cdeSMingtao Huang         // 参考:https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/pci/broadcom_bus.c#27
78bde08cdeSMingtao Huang         let bus_begin = X86_64PciArch::read_config_early(0, 0, 0, 0x44);
79bde08cdeSMingtao Huang         let bus_end = X86_64PciArch::read_config_early(0, 0, 0, 0x45);
80bde08cdeSMingtao Huang 
81bde08cdeSMingtao Huang         if !pci_root_manager().has_root(bus_begin as u16) {
82bde08cdeSMingtao Huang             let root = PciRoot::new(None, PciCam::Portiocam, bus_begin, bus_end);
83bde08cdeSMingtao Huang             pci_root_manager().add_pci_root(root.unwrap());
84bde08cdeSMingtao Huang         } else {
85bde08cdeSMingtao Huang             warn!("x86_64_pci_init(): pci_root_manager {}", bus_begin);
86bde08cdeSMingtao Huang         }
87370472f7SLoGin     }
88370472f7SLoGin     pci_init();
89370472f7SLoGin 
90370472f7SLoGin     return Ok(());
91370472f7SLoGin }
92370472f7SLoGin 
93370472f7SLoGin /// # discover_ecam_root - 发现使用ECAM的PCI root device
94370472f7SLoGin ///
95370472f7SLoGin /// 该函数用于从ACPI管理器获取MCFG表,并从中发现使用ECAM的PCI root device。
96370472f7SLoGin /// 然后,本函数将这些信息添加到pci_ecam_root_info_manager
97370472f7SLoGin ///
98370472f7SLoGin /// ## 返回值
99370472f7SLoGin ///
100370472f7SLoGin /// - Ok(()): 成功发现并添加了所有ECAM根信息
101370472f7SLoGin /// - Err(PciError): 在获取ACPI管理器表或发现MCFG表时发生错误
discover_ecam_root() -> Result<(), PciError>102370472f7SLoGin fn discover_ecam_root() -> Result<(), PciError> {
103cc5feaf6SJomo     let mcfg = acpi_manager()
1048b3d1688Syuyi2439         .tables()
1058b3d1688Syuyi2439         .expect("get acpi_manager table error")
106cc5feaf6SJomo         .find_table::<Mcfg>()
107cc5feaf6SJomo         .map_err(|_| PciError::McfgTableNotFound)?;
1088b3d1688Syuyi2439     for mcfg_entry in mcfg.entries() {
109370472f7SLoGin         pci_ecam_root_info_manager().add_ecam_root_info(EcamRootInfo::new(
110370472f7SLoGin             mcfg_entry.pci_segment_group,
111370472f7SLoGin             mcfg_entry.bus_number_start,
112370472f7SLoGin             mcfg_entry.bus_number_end,
113370472f7SLoGin             PhysAddr::new(mcfg_entry.base_address as usize),
114370472f7SLoGin         ));
11578bf93f0SYJwu2023     }
116370472f7SLoGin 
117370472f7SLoGin     Ok(())
11878bf93f0SYJwu2023 }
119