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

* feat(driver/pci): 完善pci root结构体,增加portio的pci配置空间访问
This commit is contained in:
Mingtao Huang 2024-05-16 17:47:01 +08:00 committed by GitHub
parent 0897bd8e75
commit bde08cded6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 118 additions and 57 deletions

View File

@ -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();

View File

@ -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
);
}
}

View File

@ -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,
}

View File

@ -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 ecam_root_info: Option<EcamRootInfo>,
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 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 {
if let Some(ecam_root_info) = &self.ecam_root_info {
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
"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,
};
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,6 +163,7 @@ impl PciRoot {
///
/// - `u32`: 寄存器读值结果
pub fn read_config(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 {
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.
@ -161,6 +171,9 @@ impl PciRoot {
.add((address >> 2) as usize))
.read_volatile()
}
} else {
PciArch::read_config(&bus_device_function, register_offset as u8)
}
}
/// # write_config - 通过bus_device_function和offset写入相应位置寄存器值32位
@ -178,6 +191,7 @@ impl PciRoot {
register_offset: u16,
data: u32,
) {
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.
@ -187,7 +201,11 @@ impl PciRoot {
.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();
if let Some(ecam_root_info) = pci_root.ecam_root_info {
inner
.pci_root
.insert(pci_root.segment_group_number, 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