PCI总线配置核心实现与架构解析

pciconf.c 函数调用流程、执行流程与架构梳理

一、文件整体定位

该文件是通用PCI总线配置核心实现,主要完成PCI/PCIe设备的扫描、配置空间读写、中断路由、地址空间(IO/MEM)分配、PCIe参数(MPS/MRRS)配置、桥设备管理等核心功能,适配龙芯(LOONGSON)2K/3C6000/LS7A等平台,遵循BSD许可协议。

核心目标

  1. 枚举系统中所有PCI/PCIe设备并构建设备树;
  2. 为设备分配IO/Memory地址空间,配置BAR(Base Address Register);
  3. 处理PCI桥设备的总线编号、地址窗口映射;
  4. 配置PCIe关键参数(最大有效载荷MPS、最大读请求MRRS);
  5. 处理中断路由、IOMMU设备管理等平台相关逻辑。

二、核心数据结构(隐式梳理)

从代码中提炼关键数据结构,理解架构基础:

结构名 核心作用
pci_device 描述PCI设备实例,包含总线/设备/功能号(BDF)、配置空间标签、类码、父设备、桥信息、BAR窗口等
pci_bus 描述PCI总线,包含总线号、带宽、延迟参数、地址空间范围、设备列表等
pci_win 描述PCI地址窗口(BAR/桥窗口),包含地址、大小、对齐、所属设备、寄存器偏移等
pci_intline_routing 中断路由信息,关联设备与中断线

三、函数调用流程(核心链路)

1. 顶层入口:PCI总线扫描初始化(隐含入口)

代码中未直接展示main入口,但核心触发点是_pci_scan_dev(扫描单条总线上的设备),而_pci_scan_dev_pci_query_dev(桥设备处理时)调用,整体扫描流程的顶层触发逻辑为:

复制代码
_setup_pcibuses() ------[初始化总线]→ _pci_scan_dev() ------[扫描设备]→ _pci_query_dev() ------[查询设备]→ _pci_query_dev_func()

2. 核心函数调用链路(按执行顺序)

阶段1:设备扫描与枚举

无效
有效


_pci_scan_dev(父设备, 总线号, 设备号, 初始化标志)
_pci_query_dev(父设备, 总线号, 设备号, 初始化标志)
_pci_make_tag(生成PCI配置空间标签)
_pci_conf_read(读取设备ID寄存器)
设备是否有效(ID≠0/0xFFFF)
返回
读取设备头类型(BHLC_REG)
是否多功能设备?
遍历0-7功能号
处理单功能设备
_pci_query_dev_func(父设备, PCI标签, 初始化标志)

阶段2:设备属性解析与初始化(_pci_query_dev_func)





_pci_query_dev_func
读取设备类码/ID,打印设备信息(VERBOSE模式)
分配pci_device结构体,填充BDF/标签/类码等基础信息
_pci_setupIntRouting(配置中断路由)
关闭设备命令寄存器(禁止IO/MEM/主模式,初始化阶段)
更新总线属性(66MHz/快速背靠背/设备响应时间)
是否是PCI桥设备?
处理桥设备:分配总线号、初始化子总线pci_bus结构体
_pci_bus_insert(插入总线链表)
_pci_scan_dev(递归扫描桥的次级总线)
计算桥的IO/MEM窗口大小,插入父设备窗口链表
是否是SR-IOV设备?(非2K平台)
处理VF设备,计算VF的BDF,更新子总线号
处理普通设备:配置BAR寄存器
遍历BAR寄存器(0-5/ROM)
_pci_conf_write(写入全1测试大小)
_pci_conf_read(读取BAR掩码,计算地址空间大小)
_insertsort_window(插入地址窗链表,按对齐排序)

阶段3:PCIe参数配置(龙芯2K/LS7A平台)

pcie_write_mps(配置最大有效载荷)
pcie_get_branch_min_mps(获取分支最小MPS)
pcie_get_mpss(读取设备支持的最大MPS)
pcie_set_mps(设置设备MPS为分支最小值)
pcie_write_mrrs(配置最大读请求)
pcie_get_readrq(读取桥的MRRS)
pcie_set_readrq(设置设备/桥的MRRS)

阶段4:地址空间分配(_pci_setup_windows)

失败
成功
_pci_setup_windows(分配IO/MEM地址)
遍历设备MEM窗口链表
_pci_allocate_mem(分配内存地址)
分配是否成功?
使用PCI_BIGMEM_ADDRESS分配大内存地址
写入设备BAR寄存器/桥窗口寄存器
遍历IO窗口链表
_pci_allocate_io(分配IO地址)
写入设备BAR寄存器/桥窗口寄存器
处理VGA设备ROM地址(特殊逻辑)

3. 辅助函数调用链路

函数名 被调用位置 核心作用
_pci_roundup 桥窗口计算 地址/大小向上取整到指定粒度(如IO窗口取整到0x1000,MEM到0x100000)
_pci_device_insert _pci_query_dev_func 将设备插入父设备的子设备链表(维护设备树)
_pci_bus_insert 桥设备处理 将新总线插入全局总线链表
_insertsort_window BAR/桥窗口处理 按对齐大小插入排序窗口链表(大对齐优先,保证地址分配连续)
is_power_of_2/ffs/fls PCIe参数配置/地址计算 辅助判断2的幂、计算位位置(MPS/MRRS配置)、地址对齐
set_pcie_port_type 桥设备处理 识别PCIe设备类型,填充pci_device的pcie_type/pcie_cap字段

四、文件内执行流程(按代码块逻辑)

1. 预处理与全局变量初始化

  • 定义编译宏(PCIVERBOSE/LOONGSON_2K/LS7A等),控制不同平台逻辑;
  • 初始化全局变量:have_vga(VGA设备标签)、monarch_mode(总线主模式)、pci_roots(根总线数)、_pci_head(设备链表头)、_pci_bushead(总线链表头)等;
  • 定义工具宏(MIN/MAX/PRINTF)、内联函数(ffs/fls,位操作)。

2. PCIe参数配置函数(独立模块)

  • pcie_get_mpss:读取设备支持的最大有效载荷(MPS);
  • pcie_get_mps:读取当前配置的MPS;
  • pcie_set_mps:设置MPS(校验合法性:128~4096,2的幂);
  • pcie_get_readrq/pcie_set_readrq:读取/设置最大读请求(MRRS);
  • pcie_get_branch_min_mps:获取设备分支(父桥链)的最小MPS;
  • pcie_write_mps/pcie_write_mrrs:龙芯平台核心逻辑,将设备/桥的MPS/MRRS配置为链路最小值(保证PCIe链路兼容)。

3. 设备扫描核心逻辑(_pci_scan_dev/_pci_query_dev/_pci_query_dev_func)

  • 生成PCI配置空间标签(_pci_make_tag);
  • 读取设备ID,过滤无效设备;
  • 处理多功能设备,遍历所有功能号;
  • 分配并初始化pci_device结构体,维护设备树;
  • 处理桥设备:分配次级总线号,递归扫描子总线,计算地址窗口;
  • 处理普通设备:解析BAR寄存器,计算地址空间大小,插入窗口链表;
  • 平台相关逻辑:SR-IOV(VF设备)、IOMMU设备收集(龙芯3C6000)。

4. 地址空间分配(_pci_setup_windows)

  • 遍历设备的MEM/IO窗口链表;
  • 调用_pci_allocate_mem/_pci_allocate_io分配地址(支持向上/向下分配);
  • 分配失败时使用PCI_BIGMEM_ADDRESS作为备用地址;
  • 写入设备BAR寄存器或桥的窗口寄存器(MEMBASE/IOBASE);
  • 特殊处理VGA设备的ROM地址(兼容传统BIOS)。

5. 辅助工具函数

  • 中断路由:_pci_setupIntRouting/_pci_getIntRouting(代码中未展示实现,但调用链路存在);
  • 内存分配:pmalloc/pfree(封装的内存分配函数);
  • 打印函数:_pci_bdfprintf/_pci_tagprintf(VERBOSE模式下打印设备BDF信息)。

四、架构设计梳理

1. 分层架构

层级 核心功能 核心函数
配置空间层 读写PCI配置空间寄存器(底层硬件交互) _pci_conf_read/_pci_conf_write
设备枚举层 扫描总线/设备/功能,构建设备树 _pci_scan_dev/_pci_query_dev
设备属性层 解析设备类码、中断、BAR、桥参数,维护总线属性 _pci_query_dev_func
地址分配层 为设备/BAR/桥窗口分配IO/MEM地址,写入硬件寄存器 _pci_allocate_mem/_pci_setup_windows
PCIe适配层 配置PCIe链路参数(MPS/MRRS),保证链路兼容性 pcie_write_mps/pcie_write_mrrs
平台适配层 龙芯2K/3C6000/LS7A平台特殊逻辑(IOMMU、VGA、SR-IOV) is_ls3c6000_pcie/set_pcie_port_type

2. 链表管理设计

  • 设备链表_pci_head为根,通过pci_device.parent/next/bridge.child维护父子/兄弟关系,形成PCI设备树;
  • 总线链表_pci_bushead为根,_pci_bus_insert插入新总线,管理所有PCI总线;
  • 地址窗口链表 :每个设备/桥维护iospace/memspace链表,_insertsort_window按对齐大小排序,保证地址分配高效。

3. 平台适配设计

  • 宏控区分平台:LOONGSON_2K/LOONGSON_3C6000/LS7A,隔离不同平台的特殊逻辑;
  • 弱符号函数:pci_alloc_fixmemio/pci_get_busno,允许平台重定义;
  • IOMMU管理:3C6000平台收集IOMMU设备范围,2K平台跳过;
  • VGA适配:区分BMC VGA(AST2050)、AMD VGA、龙芯7A VGA,处理ROM地址。

4. 初始化策略

  • 初始化阶段关闭设备的IO/MEM/主模式(避免干扰扫描),配置完成后再启用;
  • 桥设备递归扫描:扫描完桥的次级总线后,再计算桥的地址窗口大小;
  • 地址分配粒度:桥窗口按0x1000(IO)/0x100000(MEM)取整,保证硬件兼容性;
  • VERBOSE分级:通过PCIVERBOSE宏控制打印粒度,便于调试。

五、关键设计亮点

  1. 兼容性优先:PCIe MPS/MRRS配置为链路最小值,保证不同设备间的PCIe链路兼容;
  2. 资源高效分配:地址窗口按对齐大小排序,向上/向下分配地址,最大化利用地址空间;
  3. 平台解耦:通过宏控和弱符号实现平台差异化,核心逻辑通用;
  4. 设备树构建:基于链表的设备/总线树结构,清晰维护PCI拓扑关系;
  5. 鲁棒性处理:地址分配失败时使用备用大内存地址,设备ID读取前加延迟(避免硬件未就绪)。

六、总结

该文件是典型的PCI总线配置框架实现,核心逻辑遵循PCI/PCIe规范,同时深度适配龙芯平台特性。整体执行流程围绕"总线扫描→设备枚举→属性解析→地址分配→硬件配置"展开,通过分层设计、链表管理、平台宏控实现了通用性与平台适配的平衡。核心链路清晰,从顶层的总线扫描到底层的配置空间读写,形成了完整的PCI设备初始化闭环。

相关推荐
这是谁的博客?3 小时前
[模型解析] DeepSeek: 技术创新与架构解析
ai·架构·大模型·moe·开源模型·deepseek·国产ai
ting94520003 小时前
Codex 适配国产信创环境完整部署指南(深度技术篇)
人工智能·架构
難釋懷3 小时前
Nginx应用场景
运维·nginx
曾阿伦4 小时前
Linux 系统资源查看命令大全
linux·运维·服务器
这是谁的博客?4 小时前
[模型解析] Gemini: 多模态技术架构深度解析
ai·google·架构·大模型·多模态·视频生成·gemini
全栈游侠4 小时前
DRM驱动分析01 - 初始化
linux
qq_401700414 小时前
TCP 多客户端与服务器通信程序
运维·服务器
宠..4 小时前
VS Code SSH 远程连接 Ubuntu 并实现快速运行(C/C++示例)
java·运维·c语言·开发语言·c++·ubuntu·ssh
量子罐头4 小时前
国产鲲鹏服务器适配:光润通 100GbE 网卡性能实测报告
运维·服务器