178bf93f0SYJwu2023 use crate::arch::TraitPciArch; 28b3d1688Syuyi2439 use crate::driver::acpi::acpi_manager; 3370472f7SLoGin use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo}; 478bf93f0SYJwu2023 use crate::driver::pci::pci::{ 5bde08cdeSMingtao Huang pci_init, BusDeviceFunction, PciAddr, PciCam, PciError, PORT_PCI_CONFIG_ADDRESS, 6bde08cdeSMingtao Huang PORT_PCI_CONFIG_DATA, 778bf93f0SYJwu2023 }; 8bde08cdeSMingtao Huang use crate::driver::pci::root::{pci_root_manager, PciRoot}; 9bde08cdeSMingtao Huang use crate::include::bindings::bindings::{io_in32, io_in8, io_out32}; 10370472f7SLoGin use crate::init::initcall::INITCALL_SUBSYS; 112dd9f0c7SLoGin use crate::mm::PhysAddr; 1278bf93f0SYJwu2023 138b3d1688Syuyi2439 use acpi::mcfg::Mcfg; 14*6f189d27Slinfeng 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 23bde08cdeSMingtao Huang fn read_config_early(bus: u8, slot: u8, func: u8, offset: u8) -> u8 { 24bde08cdeSMingtao Huang unsafe { 25bde08cdeSMingtao Huang io_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 } 34bde08cdeSMingtao Huang let value = unsafe { io_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 { 4078bf93f0SYJwu2023 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 { 4878bf93f0SYJwu2023 io_out32(PORT_PCI_CONFIG_ADDRESS, address); 4978bf93f0SYJwu2023 let temp = io_in32(PORT_PCI_CONFIG_DATA); 5078bf93f0SYJwu2023 temp 5178bf93f0SYJwu2023 }; 5278bf93f0SYJwu2023 return ret; 5378bf93f0SYJwu2023 } 5478bf93f0SYJwu2023 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 { 6278bf93f0SYJwu2023 io_out32(PORT_PCI_CONFIG_ADDRESS, address); 6378bf93f0SYJwu2023 // 写入数据 6478bf93f0SYJwu2023 io_out32(PORT_PCI_CONFIG_DATA, data); 6578bf93f0SYJwu2023 } 6678bf93f0SYJwu2023 } 6778bf93f0SYJwu2023 682dd9f0c7SLoGin fn address_pci_to_physical(pci_address: PciAddr) -> PhysAddr { 692dd9f0c7SLoGin return PhysAddr::new(pci_address.data()); 7078bf93f0SYJwu2023 } 71370472f7SLoGin } 7278bf93f0SYJwu2023 73370472f7SLoGin #[unified_init(INITCALL_SUBSYS)] 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表时发生错误 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