mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
feat(driver/pci): 完善pci root结构体,增加portio的pci配置空间访问 (#818)
* feat(driver/pci): 完善pci root结构体,增加portio的pci配置空间访问
This commit is contained in:
parent
0897bd8e75
commit
bde08cded6
@ -2,19 +2,40 @@ use crate::arch::TraitPciArch;
|
|||||||
use crate::driver::acpi::acpi_manager;
|
use crate::driver::acpi::acpi_manager;
|
||||||
use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo};
|
use crate::driver::pci::ecam::{pci_ecam_root_info_manager, EcamRootInfo};
|
||||||
use crate::driver::pci::pci::{
|
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::init::initcall::INITCALL_SUBSYS;
|
||||||
|
|
||||||
use crate::mm::PhysAddr;
|
use crate::mm::PhysAddr;
|
||||||
|
|
||||||
use acpi::mcfg::Mcfg;
|
use acpi::mcfg::Mcfg;
|
||||||
use log::error;
|
use log::{error, warn};
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
use unified_init::macros::unified_init;
|
use unified_init::macros::unified_init;
|
||||||
|
|
||||||
pub struct X86_64PciArch;
|
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 {
|
impl TraitPciArch for X86_64PciArch {
|
||||||
fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 {
|
fn read_config(bus_device_function: &BusDeviceFunction, offset: u8) -> u32 {
|
||||||
// 构造pci配置空间地址
|
// 构造pci配置空间地址
|
||||||
@ -51,8 +72,18 @@ impl TraitPciArch for X86_64PciArch {
|
|||||||
|
|
||||||
#[unified_init(INITCALL_SUBSYS)]
|
#[unified_init(INITCALL_SUBSYS)]
|
||||||
fn x86_64_pci_init() -> Result<(), SystemError> {
|
fn x86_64_pci_init() -> Result<(), SystemError> {
|
||||||
if let Err(e) = discover_ecam_root() {
|
if discover_ecam_root().is_err() {
|
||||||
error!("x86_64_pci_init(): discover_ecam_root error: {:?}", e);
|
// 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();
|
pci_init();
|
||||||
|
|
||||||
|
@ -13,27 +13,32 @@ pub fn pci_ecam_root_info_manager() -> &'static EcamRootInfoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ecam pci root info
|
/// Ecam pci root info
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Debug, Copy)]
|
||||||
pub struct EcamRootInfo {
|
pub struct EcamRootInfo {
|
||||||
pub segement_group_number: SegmentGroupNumber,
|
/// 段组号
|
||||||
|
pub segment_group_number: SegmentGroupNumber,
|
||||||
|
/// 该分组中的最小bus
|
||||||
pub bus_begin: u8,
|
pub bus_begin: u8,
|
||||||
|
/// 该分组中的最大bus
|
||||||
pub bus_end: u8,
|
pub bus_end: u8,
|
||||||
|
/// 物理基地址
|
||||||
pub physical_address_base: PhysAddr,
|
pub physical_address_base: PhysAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EcamRootInfo {
|
impl EcamRootInfo {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
segement_group_number: SegmentGroupNumber,
|
segment_group_number: SegmentGroupNumber,
|
||||||
bus_begin: u8,
|
bus_begin: u8,
|
||||||
bus_end: u8,
|
bus_end: u8,
|
||||||
physical_address_base: PhysAddr,
|
physical_address_base: PhysAddr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
let ecam_root_info = Self {
|
||||||
segement_group_number,
|
segment_group_number,
|
||||||
bus_begin,
|
bus_begin,
|
||||||
bus_end,
|
bus_end,
|
||||||
physical_address_base,
|
physical_address_base,
|
||||||
}
|
};
|
||||||
|
return ecam_root_info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,11 +53,10 @@ impl EcamRootInfoManager {
|
|||||||
///
|
///
|
||||||
/// - `ecam_root_info`: EcamRootInfo - 要添加的EcamRootInfo实例
|
/// - `ecam_root_info`: EcamRootInfo - 要添加的EcamRootInfo实例
|
||||||
pub fn add_ecam_root_info(&self, ecam_root_info: 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(
|
let root = PciRoot::new(
|
||||||
ecam_root_info.segement_group_number,
|
Some(ecam_root_info),
|
||||||
PciCam::Ecam,
|
PciCam::Ecam,
|
||||||
ecam_root_info.physical_address_base,
|
|
||||||
ecam_root_info.bus_begin,
|
ecam_root_info.bus_begin,
|
||||||
ecam_root_info.bus_end,
|
ecam_root_info.bus_end,
|
||||||
);
|
);
|
||||||
@ -66,7 +70,7 @@ impl EcamRootInfoManager {
|
|||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
"add_ecam_root_info(): root {} already exists",
|
"add_ecam_root_info(): root {} already exists",
|
||||||
ecam_root_info.segement_group_number
|
ecam_root_info.segment_group_number
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -639,6 +639,8 @@ impl PciDeviceStructure for PciDeviceStructurePciToCardbusBridge {
|
|||||||
/// 用于访问PCI设备的功能配置空间的一组机制。
|
/// 用于访问PCI设备的功能配置空间的一组机制。
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum PciCam {
|
pub enum PciCam {
|
||||||
|
/// PortIO配置访问机制
|
||||||
|
Portiocam,
|
||||||
/// PCI内存映射配置访问机制
|
/// PCI内存映射配置访问机制
|
||||||
///
|
///
|
||||||
/// 为每个设备功能提供256字节的配置空间访问。
|
/// 为每个设备功能提供256字节的配置空间访问。
|
||||||
@ -653,6 +655,7 @@ impl PciCam {
|
|||||||
/// Returns the total size in bytes of the memory-mapped region.
|
/// Returns the total size in bytes of the memory-mapped region.
|
||||||
pub const fn size(self) -> u32 {
|
pub const fn size(self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Portiocam => 0x100000,
|
||||||
Self::MmioCam => 0x1000000,
|
Self::MmioCam => 0x1000000,
|
||||||
Self::Ecam => 0x10000000,
|
Self::Ecam => 0x10000000,
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,17 @@ use alloc::sync::Arc;
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
arch::{PciArch, TraitPciArch},
|
||||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||||
mm::{
|
mm::{
|
||||||
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
||||||
page::PAGE_2M_SIZE,
|
page::PAGE_2M_SIZE,
|
||||||
PhysAddr,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::pci::{
|
use super::{
|
||||||
BusDeviceFunction, ExternalCapabilityIterator, PciCam, PciError, SegmentGroupNumber,
|
ecam::EcamRootInfo,
|
||||||
|
pci::{BusDeviceFunction, ExternalCapabilityIterator, PciCam, PciError, SegmentGroupNumber},
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -28,13 +29,14 @@ pub fn pci_root_manager() -> &'static PciRootManager {
|
|||||||
/// 代表一个PCI segement greoup.
|
/// 代表一个PCI segement greoup.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PciRoot {
|
pub struct PciRoot {
|
||||||
pub physical_address_base: PhysAddr, //物理地址,acpi获取
|
pub ecam_root_info: Option<EcamRootInfo>,
|
||||||
pub mmio_guard: Option<Arc<MMIOSpaceGuard>>, //映射后的虚拟地址,为方便访问数据这里转化成指针
|
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,
|
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,自定义输出
|
///实现PciRoot的Display trait,自定义输出
|
||||||
impl core::fmt::Display for PciRoot {
|
impl core::fmt::Display for PciRoot {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
write!(
|
if let Some(ecam_root_info) = &self.ecam_root_info {
|
||||||
f,
|
write!(
|
||||||
"PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {:?},mapped at {:?}",
|
f,
|
||||||
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(
|
pub fn new(
|
||||||
segment_group_number: SegmentGroupNumber,
|
ecam_root_info: Option<EcamRootInfo>,
|
||||||
cam: PciCam,
|
cam: PciCam,
|
||||||
phys_base: PhysAddr,
|
|
||||||
bus_begin: u8,
|
bus_begin: u8,
|
||||||
bus_end: u8,
|
bus_end: u8,
|
||||||
) -> Result<Arc<Self>, PciError> {
|
) -> Result<Arc<Self>, PciError> {
|
||||||
assert_eq!(cam, PciCam::Ecam);
|
|
||||||
let mut pci_root = Self {
|
let mut pci_root = Self {
|
||||||
physical_address_base: phys_base,
|
ecam_root_info,
|
||||||
mmio_guard: None,
|
mmio_guard: None,
|
||||||
segment_group_number,
|
cam,
|
||||||
bus_begin,
|
bus_begin,
|
||||||
bus_end,
|
bus_end,
|
||||||
cam,
|
|
||||||
};
|
};
|
||||||
pci_root.map()?;
|
|
||||||
|
if ecam_root_info.is_some() {
|
||||||
|
pci_root.map()?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Arc::new(pci_root))
|
Ok(Arc::new(pci_root))
|
||||||
}
|
}
|
||||||
/// @brief 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量
|
|
||||||
/// @return 返回错误或Ok(0)
|
/// # 完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量
|
||||||
|
/// ## return 返回错误或Ok(0)
|
||||||
fn map(&mut self) -> Result<u8, PciError> {
|
fn map(&mut self) -> Result<u8, PciError> {
|
||||||
//debug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end);
|
//debug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end);
|
||||||
let bus_number = (self.bus_end - self.bus_begin) as u32 + 1;
|
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());
|
self.mmio_guard = Some(space_guard.clone());
|
||||||
|
|
||||||
assert!(space_guard
|
assert!(space_guard
|
||||||
.map_phys(self.physical_address_base, size)
|
.map_phys(self.ecam_root_info.unwrap().physical_address_base, size)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
@ -129,11 +136,12 @@ impl PciRoot {
|
|||||||
/// - 此函数计算出的地址需要是字对齐的(即地址与0x3对齐)。如果不是,将panic。
|
/// - 此函数计算出的地址需要是字对齐的(即地址与0x3对齐)。如果不是,将panic。
|
||||||
fn cam_offset(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 {
|
fn cam_offset(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 {
|
||||||
assert!(bus_device_function.valid());
|
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.device as u32) << 3
|
||||||
| bus_device_function.function as u32;
|
| bus_device_function.function as u32;
|
||||||
let address =
|
let address =
|
||||||
bdf << match self.cam {
|
bdf << match self.cam {
|
||||||
|
PciCam::Portiocam => 4,
|
||||||
PciCam::MmioCam => 8,
|
PciCam::MmioCam => 8,
|
||||||
PciCam::Ecam => 12,
|
PciCam::Ecam => 12,
|
||||||
} | register_offset as u32;
|
} | register_offset as u32;
|
||||||
@ -141,6 +149,7 @@ impl PciRoot {
|
|||||||
assert!(address & 0x3 == 0);
|
assert!(address & 0x3 == 0);
|
||||||
address
|
address
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # read_config - 通过bus_device_function和offset读取相应位置寄存器的值(32位)
|
/// # read_config - 通过bus_device_function和offset读取相应位置寄存器的值(32位)
|
||||||
///
|
///
|
||||||
/// 此函数用于通过指定的bus_device_function和register_offset读取PCI设备中相应位置的寄存器值。
|
/// 此函数用于通过指定的bus_device_function和register_offset读取PCI设备中相应位置的寄存器值。
|
||||||
@ -154,12 +163,16 @@ impl PciRoot {
|
|||||||
///
|
///
|
||||||
/// - `u32`: 寄存器读值结果
|
/// - `u32`: 寄存器读值结果
|
||||||
pub fn read_config(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 {
|
pub fn read_config(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 {
|
||||||
let address = self.cam_offset(bus_device_function, register_offset);
|
if self.ecam_root_info.is_some() {
|
||||||
unsafe {
|
let address = self.cam_offset(bus_device_function, register_offset);
|
||||||
// Right shift to convert from byte offset to word offset.
|
unsafe {
|
||||||
((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32)
|
// Right shift to convert from byte offset to word offset.
|
||||||
.add((address >> 2) as usize))
|
((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32)
|
||||||
.read_volatile()
|
.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,
|
register_offset: u16,
|
||||||
data: u32,
|
data: u32,
|
||||||
) {
|
) {
|
||||||
let address = self.cam_offset(bus_device_function, register_offset);
|
if self.ecam_root_info.is_some() {
|
||||||
// Safe because both the `mmio_base` and the address offset are properly aligned, and the
|
let address = self.cam_offset(bus_device_function, register_offset);
|
||||||
// resulting pointer is within the MMIO range of the CAM.
|
// Safe because both the `mmio_base` and the address offset are properly aligned, and the
|
||||||
unsafe {
|
// resulting pointer is within the MMIO range of the CAM.
|
||||||
// Right shift to convert from byte offset to word offset.
|
unsafe {
|
||||||
((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32)
|
// Right shift to convert from byte offset to word offset.
|
||||||
.add((address >> 2) as usize))
|
((self.mmio_guard.as_ref().unwrap().vaddr().data() as *mut u32)
|
||||||
.write_volatile(data)
|
.add((address >> 2) as usize))
|
||||||
|
.write_volatile(data)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PciArch::write_config(&bus_device_function, register_offset as u8, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 返回迭代器,遍历pcie设备的external_capabilities
|
/// 返回迭代器,遍历pcie设备的external_capabilities
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn external_capabilities(
|
pub fn external_capabilities(
|
||||||
@ -233,9 +251,14 @@ impl PciRootManager {
|
|||||||
/// - `pci_root`: Arc<PciRoot>,要添加的PciRoot的Arc指针
|
/// - `pci_root`: Arc<PciRoot>,要添加的PciRoot的Arc指针
|
||||||
pub fn add_pci_root(&self, pci_root: Arc<PciRoot>) {
|
pub fn add_pci_root(&self, pci_root: Arc<PciRoot>) {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
inner
|
|
||||||
.pci_root
|
if let Some(ecam_root_info) = pci_root.ecam_root_info {
|
||||||
.insert(pci_root.segment_group_number, pci_root);
|
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
|
/// # 检查是否存在PciRoot - 检查PciRootManager中是否存在指定segment_group_number的PciRoot
|
||||||
|
Loading…
x
Reference in New Issue
Block a user