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

PCIe基础知识之Linux内核中PCIe子系统的架构

5.1 先验知识

驱动模型:Linux建立了一个统一的设备模型,分别采用总线、设备、驱动三者进行抽象,其中设备和驱动均挂载在总线上面,当有新的设备注册或者新的驱动注册的时候,总线会进行匹配操作(match函数),当发现驱动和设备能进行匹配的时候,就会执行probe函数的操作

对于PCI:PCI设备,PCI总线和PC驱动的创建,PCI设备和PCI驱动挂接在PCI总线上面

对于PCIe的控制器,遵循设备,总线,驱动的匹配模型,这里的总线是由虚拟总线platform总线来替代,相应的设备和驱动分别为platform_device和platform_driver;

5.2 PCIe驱动程序的实现

5.2.1 Linux PCI的初始化过程

Linux PCI初始化的主要工作是遍历当前处理器系统中的所有PCI总线树,并且初始化PCI总线树上面的全部设备,包括PCI桥和PCI Agent设备。在Linux系统中,多次使用DFS算法对PCI总线树进行遍历查找,并分配相关的PCI总线号与PCI总线地址资源。

*参考博客:*【原创】Linux PCI驱动框架分析(三) - LoyenWang - 博客园

1.设备树

设备树用于描述硬件的信息,包含节点各类属性,在dts文件中定义,最终编译为dtb文件加载到内存中

内核会在启动过程中解析dtb文件,解析为device_node描述的Device Tree;

根据device_node节点,创建platform_device结构,并最终注册进系统,这个也就是PCIe设备的创建过程。

2.probe流程

系统会根据dtb文件创建对应的platform_device并进行注册;

当驱动与设备通过compatible字段匹配上后,会调用probe函数,也就是nwl_pcie_probe;

看一下nwl_pcie_probe函数:

通常probe函数都是进行一些初始化操作和注册操作:

  1. 初始化包括:数据结构的初始化以及设备的初始化等,设备的初始化则需要获取硬件的信息(比如寄存器基地址,长度,中断号等),这些信息都是从DTS获取

  2. 注册操作主要是包含中断处理函数的注册,以及通常的设备文件注册等。

针对PCI控制器的驱动,核心的流程是需要分配并且初始化一个*pci_host_bridge*结构,最终通过这个*bridge*去枚举PCI总线上的所有设备;

*devm_pci_alloc_host_bridge*:分配并且初始化一个基础的pci_host_bridge结构

*nwl_pcie_parse_dt*:获取DTS中的寄存器信息以及中断信息,并且通过*irq_set_chained_handler_and_data*设置intx中断号对应的中断处理函数,该处理函数用于中断的级联;

*nwl_pcie_bridge_init*:硬件的Controller一堆设置,这部分需要查阅Spec,了解硬件工作细节。此外,通过*devm_request_irq*注册misc中断号对应的中断处理函数,该处理函数,该处理函数用于控制器自身状态的处理;

*pci_parse_request_of_pci_ranges*:用于解析PCI总线的总线范围和总线上的地址范围,也就是CPU可以看到的地址区域

*nwl_pcie_init_irq_domain**mwl_pcie_enable_msi*与中断级联相关

pci_scan_root_bus_bridge:对总线上的设备进行*扫描枚举*,(枚举具体介绍:【原创】Linux PCI驱动框架分析(二) - LoyenWang - 博客园)bridge结构体中的pci_ops字段,用于指向PCI的读写操作函数集,当具体扫描到设备要读写的配置空间的时候,调用的就是这个函数,由具体的Controller驱动实现

3.中断处理

PCIe控制器,通过PCIe总线连接各种设备,因此它本身充当一个中断控制器,级联到上一层的中断控制器(比如GIC),如下图:

PCIe总线支持两种中断的处理方式:

  1. Legacy Interrupt:总线提供INTA#,INTB#,INTC#,INTD#四根中断信号,PCI设备借助这四根信号使用电平触发方式提交中断请求;

  2. MSI(Message Signaled Interrupt)Interrupt:基于消息机制的中断,也就是往一个指定地址写入特定消息,从而触发一个中断;

针对两种处理方式,NWL PCIe驱动中,实现了两个irq_chip,也就是两种方式的中断控制器:

irq_domain对应一个中断控制器(irq_chip),*irq_domain负责将硬件中断号映射到虚拟中断号上面*

再来看一下nwl_pcie_enable_msi函数:

在该函数中主要完成的工作就是设置级联的中断处理函数,级联的中断处理函数中最终回去调用具体设备的中断处理函数;

总结,作为两种不同的中断处理方式,套路都是一样的,均为创建irq_chip中断控制器,为该中断控制器添加irq_domain,具体设备的中断响应流程如下:

1)设备连接在PCI总线上面,触发中断的时候,通过PCIe控制器充当的中断控制器路由到上一级控制器,最终路由到CPU;

2)CPU在处理PCIe控制器的中断时,调用它的中断处理函数,也就是上文中提到过的new_pcie_leg_handler,nwl_pcie_msi_handler_high,和nwl_pcie_leg_handler_low;

3)在级联的中断处理函数中,调用chained_irq_enter进入中断级联处理;

4)调用irq_find_mapping找到具体的PCIe设备的中断号;

5)调用generic_handle_irq触发具体的PCIe设备的中断处理函数执行;

6)调用chained_irq_exit退出中断级联的处理

4.总结

各类的驱动,大体都是硬件初始化配置,资源申请注册,核心时处理和硬件的交互(一般就是中断的处理),如果需要用户来进行交互,则还需要注册设备文件,实现一堆file_operation操作函数集。

PCI驱动程序实现关键数据结构

PCI设备有三种地址空间:

PCI的I/O空间

PCI的存储空间

PCI的配置空间。

CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用。内核在启动时负责对所有的PCI设备进行初始化,配置好所有的PCI设备,包括中断号以及I/O基址,并在文件 /proc/pci中列出所有找到的PCI设备,以及这些设备的参数和属性

http://www.dtcms.com/a/270779.html

相关文章:

  • youtube图论
  • 深度解析:将SymPy符号表达式转化为高效NumPy计算函数的通用解决方案
  • 底盘机械臂仿真fetch_gazebo实践
  • 从0开始学习R语言--Day42--LM检验
  • Flume日志采集工具
  • 深入理解图像二值化:从静态图像到视频流实时处理
  • 迁移Oracle SH 示例 schema 到 PostgreSQL
  • qml加载html以及交互
  • python安装pandas模块报错问题
  • Opencv探索之旅:从像素变化到世界轮廓的奥秘
  • Adobe Illustrator 2025 安装图文教程 | 快速上手平面设计
  • 让AI绘图更可控!ComfyUI-Cosmos-Predict2基础使用指南
  • 分治算法---快排
  • ts学习1
  • 宏集案例 | 基于CODESYS的自动化控制系统,开放架构 × 高度集成 × 远程运维
  • 打破传统,开启 AR 智慧课堂​
  • react16-react19都更新哪些内容?
  • 【LeetCode 热题 100】136. 只出现一次的数字——异或
  • Deepoc具身智能大模型:送餐机器人如何学会“读心术”
  • Java结构型模式---装饰者模式
  • Vue3 Element plus table有fixed列时错行
  • Embarcadero Delphi 12.3 Crack
  • C++ 中最短路算法的详细介绍
  • B站排名优化:从算法密码到流量密钥的全方位解析
  • vue快速上手
  • 前端开发自动化设计详解
  • 【牛客刷题】游游的字母串
  • 2023年IEEE TITS SCI2区TOP,增强回溯搜索算法EBSA+多无人机辅助商业包裹递送系统飞行规划,深度解析+性能实测
  • NLP:初识RNN模型(概念、分类、作用)
  • HarmonyOS应用开发者高级试题2025年7月部分单选题