当前位置: 首页 > java >正文

Linux学习笔记:PCIe内核篇(1):初始化与枚举流程

根据system.map 查看内核中PCIe加载流程:

root@zh-vm:~# cat /boot/System.map-5.15.0-130-generic | grep pci | grep initcall
ffffffff8350ff68 d __initcall__kmod_pci__453_6907_pci_realloc_setup_params0
ffffffff83510098 d __initcall__kmod_probe__266_110_pcibus_class_init2
ffffffff8351009c d __initcall__kmod_pci_driver__419_1685_pci_driver_init2
ffffffff8351014c d __initcall__kmod_pci_acpi__284_1504_acpi_pci_init3
ffffffff83510158 d __initcall__kmod_pci__370_214_register_xen_pci_notifier3
ffffffff83510170 d __initcall__kmod_init__253_51_pci_arch_init3
ffffffff835102c0 d __initcall__kmod_slot__281_380_pci_slot_init4
ffffffff8351043c d __initcall__kmod_legacy__254_77_pci_subsys_init4
ffffffff83510444 d __initcall__kmod_pci_eisa__257_89_pci_eisa_init_early4s
ffffffff83510554 d __initcall__kmod_i386__269_373_pcibios_assign_resources5
ffffffff83510558 d __initcall__kmod_quirks__360_195_pci_apply_final_quirks5s
ffffffff83510564 d __initcall__kmod_pci_dma__265_136_pci_iommu_initrootfs
ffffffff83510758 d __initcall__kmod_pwm_lpss_pci__258_120_pwm_lpss_driver_pci_init6
ffffffff83510760 d __initcall__kmod_pcieportdrv__258_274_pcie_portdrv_init6
ffffffff83510764 d __initcall__kmod_proc__257_469_pci_proc_init6
ffffffff83510768 d __initcall__kmod_pci_hotplug__288_573_pci_hotplug_init6
ffffffff83510770 d __initcall__kmod_pci_ep_cfs__267_731_pci_ep_cfs_init6
ffffffff83510774 d __initcall__kmod_pci_epc_core__286_849_pci_epc_init6
ffffffff83510778 d __initcall__kmod_pci_epf_core__284_561_pci_epf_init6
ffffffff8351077c d __initcall__kmod_pcie_designware_plat__259_192_dw_plat_pcie_driver_init6
ffffffff835107f4 d __initcall__kmod_virtio_pci__289_638_virtio_pci_driver_init6
ffffffff83510810 d __initcall__kmod_platform_pci__364_193_platform_driver_init6
ffffffff83510830 d __initcall__kmod_8250_pci__275_6463_serial_pci_driver_init6
ffffffff83510834 d __initcall__kmod_8250_mid__263_402_mid8250_pci_driver_init6
ffffffff835108d4 d __initcall__kmod_pata_sis__333_909_sis_pci_driver_init6
ffffffff835108d8 d __initcall__kmod_ata_generic__318_250_ata_generic_pci_driver_init6
ffffffff83510900 d __initcall__kmod_vfio_pci_core__326_2248_vfio_pci_core_init6
ffffffff83510904 d __initcall__kmod_vfio_pci__271_264_vfio_pci_init6
ffffffff83510914 d __initcall__kmod_ehci_pci__268_432_ehci_pci_init6
ffffffff83510920 d __initcall__kmod_ohci_pci__274_321_ohci_pci_init6
ffffffff835109a0 d __initcall__kmod_intel_scu_pcidrv__253_55_intel_scu_pci_driver_init6
ffffffff83510ae0 d __initcall__kmod_pci__450_6732_pci_resource_alignment_sysfs_init7
ffffffff83510ae4 d __initcall__kmod_pci_sysfs__304_1424_pci_sysfs_init7
ffffffff83510b64 d __initcall__kmod_mmconfig_shared__282_718_pci_mmcfg_late_insert_resources7

同时:

root@zh-vm:/lib# cat /boot/System.map-5.15.0-130-generic | grep acpi_init | grep initcall
ffffffff835102cc d __initcall__kmod_acpi__408_1364_acpi_init4

因此,整体启动顺序如下:

--> pcibus_class_init()
--> pci_driver_init()
--> acpi_pci_init()
--> pci_arch_init()
--> pci_slot_init()
--> acpi_init()
--> pci_subsys_init()

整个过程主要分为两部分 扫描设备分配资源

(1)pcibus_class_init(): 注册pci_bus class,完成后创建了/sys/class/pci_bus目录。
(2)pci_driver_init(): 注册pci_bus_type, 完成后创建了/sys/bus/pci目录。
(3)acpi_pci_init(): 注册acpi_pci_bus, 并提供了一系列系统资源管理操作,包括:

  • ACPI寄存器
  • ACPI BIOS
  • ACPI Tables

(4)acpi_init(): apci启动所涉及到的初始化、枚举流程,PCIe基于acpi的启动流程从该接口进入。也是扫描设备的主要流程入口,主要包括以下几部分:

1)ACPI 子系统初始化
acpi_init()  # ACPI 子系统总入口(drivers/acpi/bus.c)|--> mmcfg_late_init()   # acpi扫描MCFG表,MCFG表中定义了ecam资源|--> acpi_bus_init()     # 初始化 ACPI 总线|--> acpi_scan_init()    # 初始化 ACPI 设备扫描框架|--> acpi_pci_root_init()  # 初始化 PCI Root Bridge 扫描(关键入口)|--> acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root");|--> .attach = acpi_pci_root_add|--> acpi_pci_link_init()|--> acpi_bus_scan()  # 扫描 ACPI 命名空间中的设备|--> acpi_walk_namespace() # 遍历全部device,为这些acpi device创建数据结构|--> acpi_bus_attach()  # 探测匹配的 ACPI 设备|--> handler->attach()  # 调用 PCI Root Bridge 的 attach 回调|--> acpi_pci_root_add()  # 创建并注册 PCI Root Bridge|--> pci_acpi_scan_root()  # 核心 PCIe 枚举入口(见下文)
2)PCIe 总线枚举与设备扫描
| pci_acpi_scan_root()  # 处理 ACPI PCI Root Bridge(drivers/acpi/pci_root.c)
|--> acpi_pci_root_create()  # 创建 PCI Host Bridge|--> pci_create_root_bus()  # 创建 PCI 根总线(drivers/pci/probe.c)|--> pci_alloc_host_bridge()  # 分配 Host Bridge 结构体|--> pci_register_host_bridge()  # 注册 Host Bridge|--> pci_scan_child_bus()  # 递归扫描子总线(核心扫描逻辑)|--> pci_scan_child_bus_extend(bus, 0)|--> for (devfn = 0; devfn < 256; devfn += 8)  # 遍历所有可能的设备/功能号|--> pci_scan_slot(bus, devfn)  # 检查指定插槽是否存在设备|--> pci_scan_single_device()|--> pci_scan_device(bus, devfn)  # 初始化设备|--> pci_bus_read_dev_vendor_id()  # 读取设备厂商ID|--> pci_alloc_dev()  # 分配设备结构体|--> pci_setup_device()  # 配置设备 BAR、Class 等|--> pci_device_add(dev, bus)  # 将设备添加到总线|--> pci_configure_device()  # 配置设备寄存器|--> pci_init_capabilities()  # 初始化 PCIe Capabilities|--> pcibios_add_device()  # 平台特定设备添加逻辑|--> for_each_pci_bridge(dev, bus) |--> pci_scan_bridge_extend()  # 扫描桥接器扩展总线|--> pci_add_new_bus()  # 添加新总线|--> pci_scan_child_bus_extend()  # 递归扫描新总线

总体流程便是:

ACPI 初始化 → MCFG 解析 → 发现根桥 → 创建根总线 → 递归扫描设备 → 资源分配 → 中断设置 → 驱动绑定

(1) BIOS预扫描与Kernel扫描启动

  • BIOS阶段会先进行初步扫描,但结果可能不完整或不可直接使用。
  • 内核启动后,通过acpi_init()初始化ACPI子系统,扫描MCFG表(mmcfglateinit())获取ECAM资源,为PCIe枚举做准备。

(2) 设备扫描阶段(深度优先)

  • 从主桥(Host Bridge)开始,调用pci_acpi_scan_root()进入核心枚举流程。
  • 通过pci_create_root_bus()创建根总线,并调用pci_scan_child_bus()扫描根总线下的设备。
  • 遍历所有设备槽位pci_scan_slot(),调用pci_scan_device()检查设备是否存在并初始化。
  • 若遇到桥接器for_each_pci_bridge(dev, bus),则扩展总线号(pci_scan_bridge_extend()),递归扫描子总线(pci_scan_child_bus_extend())。
  • 扫描过程中构建PCIe拓扑结构,并收集所有设备所需的资源信息(如内存、I/O、中断)。

(3) 资源分配阶段(深度优先)

  • 从主桥开始,按深度优先顺序分配资源。
  • 为每个设备分配地址空间(内存/I/O)和中断资源,确保x86域和PCI域地址不冲突。
  • 对于桥接器,根据其下设备分配的资源更新到设备的配置空间,供PCI总线路由使用。

http://www.xdnf.cn/news/14165.html

相关文章:

  • 第1章 C# 和 .NET 框架 笔记
  • MCP简介和应用
  • 第十七章 Linux之大数据定制篇——Shell编程
  • ES知识合集(四):高级篇
  • 20250614让NanoPi NEO core开发板在Ubuntu core16.04系统下使用耳机播音测试
  • 「Linux文件及目录管理」目录结构及显示类命令
  • Python虚拟环境的使用
  • SpringBoot源码解析(十一):条件注解@ConditionalOnClass的匹配逻辑
  • 如何调优Kafka
  • LeetCode 第71题 简化路径(繁琐)
  • thinkphp8提升之查询
  • Nature Machine Intelligence 北京通研院朱松纯团队开发视触觉传感仿人灵巧手,实现类人自适应抓取
  • 开心灿烂go开发面试题
  • 如何自动化测试 DependencyMatcher 规则效果(CI/CD 集成最佳实践)
  • 免费OCPP协议测试工具
  • FreeRTOS定时器
  • C++/OpenCV地砖识别系统结合 Libevent 实现网络化 AI 接入
  • 如何写出优秀的单元测试?
  • 17.vue.js响应式和dom更新
  • java33
  • Java重构实战:小步快跑的高效策略分析
  • 【嵌入式硬件实例】-555定时器实现烟雾和易燃气体泄露检测
  • JAVA-springboot 异常处理
  • 15故障排查
  • CAD中DWG到DXF文件解析(一)
  • ELK日志文件分析系统——E(Elasticsearch)
  • 【算法深练】二分答案:从「猜答案」到「精准求解」的解题思路
  • RT-Thread Studio SDK管理器安装资源包失败
  • 考研好?还是找工作好?
  • 灵界猫薄荷×贴贴诱发机制详解