深入分析Linux PCI驱动框架(三)

news2025/1/12 18:43:45

说明:

  1. Kernel版本:4.14
  2. ARM64处理器
  3. 使用工具:Source Insight 3.5, Visio

1. 概述

先回顾一下PCIe的架构图:

  • 本文将讲PCIe Host的驱动,对应为Root Complex部分,相当于PCI的Host Bridge部分;
  • 本文会选择Xilinx的nwl-pcie来进行分析;
  • 驱动的编写整体偏简单,往现有的框架上套就可以了,因此不会花太多笔墨,点到为止;

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

2. 流程分析

  • 但凡涉及到驱动的分析,都离不开驱动模型的介绍,驱动模型的实现让具体的驱动开发变得更容易;
  • 所以,还是回顾一下上篇文章提到的驱动模型:Linux内核建立了一个统一的设备模型,分别采用总线、设备、驱动三者进行抽象,其中设备与驱动都挂在总线上,当有新的设备注册或者新的驱动注册时,总线会去进行匹配操作(match函数),当发现驱动与设备能进行匹配时,就会执行probe函数的操作;

  • 深入分析Linux PCI驱动框架分析(二)中提到过PCI设备、PCI总线和PCI驱动的创建,PCI设备和PCI驱动挂接在PCI总线上,这个理解很直观。针对PCIe的控制器来说,同样遵循设备、总线、驱动的匹配模型,不过这里的总线是由虚拟总线platform总线来替代,相应的设备和驱动分别为platform_device和platform_driver;

那么问题来了,platform_device是在什么时候创建的呢?那就不得不提到Device Tree设备树了。

2.1 Device Tree

  • 设备树用于描述硬件的信息,包含节点各类属性,在dts文件中定义,最终会被编译成dtb文件加载到内存中;
  • 内核会在启动过程中去解析dtb文件,解析成device_node描述的Device Tree;
  • 根据device_node节点,创建platform_device结构,并最终注册进系统,这个也就是PCIe Host设备的创建过程;

我们看看PCIe Host的设备树内容:

pcie: pcie@fd0e0000 {
 compatible = "xlnx,nwl-pcie-2.11";
 status = "disabled";
 #address-cells = <3>;
 #size-cells = <2>;
 #interrupt-cells = <1>;
 msi-controller;
 device_type = "pci";
  
 interrupt-parent = <&gic>;
 interrupts = <0 118 4>,
              <0 117 4>,
              <0 116 4>,
              <0 115 4>, /* MSI_1 [63...32] */
              <0 114 4>; /* MSI_0 [31...0] */
 interrupt-names = "misc", "dummy", "intx", "msi1", "msi0";
 msi-parent = <&pcie>;
  
 reg = <0x0 0xfd0e0000 0x0 0x1000>,
       <0x0 0xfd480000 0x0 0x1000>,
       <0x80 0x00000000 0x0 0x1000000>;
 reg-names = "breg", "pcireg", "cfg";
 ranges = <0x02000000 0x00000000 0xe0000000 0x00000000 0xe0000000 0x00000000 0x10000000 /* non-prefetchable memory */
    0x43000000 0x00000006 0x00000000 0x00000006 0x00000000 0x00000002 0x00000000>;/* prefetchable memory */
 bus-range = <0x00 0xff>;
  
 interrupt-map-mask = <0x0 0x0 0x0 0x7>;
 interrupt-map =   <0x0 0x0 0x0 0x1 &pcie_intc 0x1>,
                   <0x0 0x0 0x0 0x2 &pcie_intc 0x2>,
                   <0x0 0x0 0x0 0x3 &pcie_intc 0x3>,
                   <0x0 0x0 0x0 0x4 &pcie_intc 0x4>;
  
 pcie_intc: legacy-interrupt-controller {
  interrupt-controller;
  #address-cells = <0>;
  #interrupt-cells = <1>;
 };
};

关键字段描述如下:

  • compatible:用于匹配PCIe Host驱动;
  • msi-controller:表示是一个MSI(Message Signaled Interrupt)控制器节点,这里需要注意的是,有的SoC中断控制器使用的是GICv2版本,而GICv2并不支持MSI,所以会导致该功能的缺失;
  • device-type:必须是"pci";
  • interrupts:包含NWL PCIe控制器的中断号;
  • interrupts-name:msi1, msi0用于MSI中断,intx用于旧式中断,与interrupts中的中断号对应;
  • reg:包含用于访问PCIe控制器操作的寄存器物理地址和大小;
  • reg-name:分别表示Bridge registers,PCIe Controller registers, Configuration space region,与reg中的值对应;
  • ranges:PCIe地址空间转换到CPU的地址空间中的范围;
  • bus-range:PCIe总线的起始范围;
  • interrupt-map-mask和interrupt-map:标准PCI属性,用于定义PCI接口到中断号的映射;
  • legacy-interrupt-controller:旧式的中断控制器;

 

2.2 probe流程

  • 系统会根据dtb文件创建对应的platform_device并进行注册;
  • 当驱动与设备通过compatible字段匹配上后,会调用probe函数,也就是nwl_pcie_probe;

看一下nwl_pcie_probe函数:

  • 通常probe函数都是进行一些初始化操作和注册操作:
  • 初始化包括:数据结构的初始化以及设备的初始化等,设备的初始化则需要获取硬件的信息(比如寄存器基地址,长度,中断号等),这些信息都从DTS而来;
  • 注册操作主要是包含中断处理函数的注册,以及通常的设备文件注册等;
  • 针对PCI控制器的驱动,核心的流程是需要分配并初始化一个pci_host_bridge结构,最终通过这个bridge去枚举PCI总线上的所有设备;
  • devm_pci_alloc_host_bridge:分配并初始化一个基础的pci_hsot_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驱动框架分析(二)中分析过。brdige结构体中的pci_ops字段,用于指向PCI的读写操作函数集,当具体扫描到设备要读写配置空间时,调用的就是这个函数,由具体的Controller驱动实现;

2.3 中断处理

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

  • PCIe总线支持两种中断的处理方式:
  • Legacy Interrupt:总线提供INTA#, INTB#, INTC#, INTD#四根中断信号,PCI设备借助这四根信号使用电平触发方式提交中断请求;
  • 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控制器的中断时,调用它的中断处理函数,也就是上文中提到过的nwl_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退出中断级联的处理;

2.4 总结

  • PCIe控制器驱动,各家的IP实现不一样,驱动的差异可能会很大,单独分析一个驱动毕竟只是个例,应该去掌握背后的通用框架;
  • 各类驱动,大体都是硬件初始化配置,资源申请注册,核心是处理与硬件的交互(一般就是中断的处理),如果需要用户来交互的,则还需要注册设备文件,实现一堆file_operation操作函数集;

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/156625.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue 总结四 (ref, mixin, 插件, 插槽, VueX)

目录 ref 混入 mixin 插件 插槽 使用插槽的情景 使用方法 VueX 使用场景 使用 state 存放共享数据 actions 操作共享数据的API mutations 操作共享数据的API 生命周期图 ref 和id的区别 对于传统标签来说没有区别 都拿到的是 html内容 对于自定义的vue 的标签…

Spring事务源码分析

1. 前言 Spring支持两种事务管理的方式&#xff1a;声明式事务和编程式事务。编程式事务的优点是可以在代码里控制事务的粒度&#xff0c;实现细粒度的事务控制&#xff0c;缺点是对业务代码存在侵入性&#xff0c;代码复杂度较高&#xff0c;一般很少使用。声明式事务的优点是…

Linux下的动静态库

目录 认识动静态库 如何制作动静态库&#xff1f; 静态库 动态库 使用库 使用静态库 使用动态库 为什么动态链接是如此呢&#xff1f; 认识动静态库 我们在使用标准库的时候&#xff0c;需要有系统的头文件和系统的库文件&#xff0c;这个库文件是什么呢&#xff1f; …

Databend 借助对象存储帮你实现降本增效

本篇文章围绕着&#xff1a; 什么是对象存储当 Databend 遇到对象存储2022 年 Databend 利用对象存储降本的案例国内优秀的对象存储产品基于对象存储创业的产品 什么是对象存储 对象存储是一种可以非结构化存储和管理数据的技术。 可以简单理解为 NoSQL 接口方式存储和访问数…

linux系统中使用QT实现多媒体的功能方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何使用QT中的多媒体的功能。 目录 第一&#xff1a;多媒体基本简介 第二&#xff1a;应用实例实现 第三&#xff1a;程序运行效果 第一&#xff1a;多媒体基本简介 QT的多媒体模块提供了音频&#xff0c;视频&#xff…

分布式系统-CAP 理论

在前一篇分布式系统–拜占庭将军问题(The Byzantine Generals Problem) 我们理解了共识问题的背景&#xff0c;这一节主要讨论如何解决或者理解自己系统中的共识问题&#xff0c;通过什么来分辨自己的系统需要哪一种共识。 这个理论就是 CAP 理论&#xff0c;先想下面几个问题…

linux 线程详解

前言 程序运行在内存空间中叫进程&#xff0c;进程中包含有若干线程&#xff0c;线程是系统调度和执行的基本单位。线程才是程序运行的实体&#xff0c;通常程序里的main()函数就相当于主线程&#xff0c;把进程理解成一个容器&#xff0c;里面可以包含有若干线程和若干资源&am…

6)Mybatis启动流程

1. 首先Mybatis会加载配置文件mybatis-config.xml&#xff0c; 主要实现在Mybatis的builder模块&#xff0c;包路径org.apache.ibatis.builder&#xff0c;解析入口XMLConfigBuilder private void settingsElement(Properties props) {configuration.setAutoMappingBehavior(Au…

指针进阶篇(2)

进阶指针 &#x1f914;前言&#x1f914; 一、&#x1f60a;函数指针&#x1f60a; 二、&#x1f61c;函数指针数组&#x1f61c; 三 、&#x1f61d;指向函数指针数组的指针&#x1f61d; 四、&#x1f31d;回调函数&#x1f31d; &#x1f340;小结&#x1f340; &…

摩丝-题解

看到题目&#xff0c;怀疑是莫尔斯电码&#xff0c;打开发现果然是莫尔斯电码的点和划.. .-.. --- ...- . -.-- --- ..-简单说一下电报的原理最简单的电报模型就是一个电源&#xff0c;一个开关和一个电磁铁当需要长距离使用时候&#xff0c;需要用到继电器按下开关&#xff0c…

【BP靶场portswigger-服务端10】XML外部实体注入(XXE注入)-9个实验(全)

前言&#xff1a; 介绍&#xff1a; 博主&#xff1a;网络安全领域狂热爱好者&#xff08;承诺在CSDN永久无偿分享文章&#xff09;。 殊荣&#xff1a;CSDN网络安全领域优质创作者&#xff0c;2022年双十一业务安全保卫战-某厂第一名&#xff0c;某厂特邀数字业务安全研究员&…

C#【必备技能篇】使用NPOI实现对excel的读取和写入

文章目录1、Winform界面布局2、引用NPOI的dll3、源码4、运行效果5、NPOI的dll下载地址6、补充【以上步骤只能打开.xls文件&#xff08;97-2003版本&#xff09;&#xff0c;打不开.xlsx文件&#xff08;2007版本&#xff09;】1、Winform界面布局 2、引用NPOI的dll 3、源码 us…

(十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置

前言 本节内容我们主要介绍一下在jenkins中如何集成sonar qube代码质量检查工具&#xff0c;sonar qube可以在流水化项目集成部署前对我们的代码质量检查。开始本节内容前我们需要先搭建好sonar qube服务&#xff0c;关于sonar qube服务的搭建可参考作者往期博客内容&#xff…

P4391 [BOI2009]Radio Transmission 无线传输

题目描述 给你一个字符串 s_1s1​&#xff0c;它是由某个字符串 s_2s2​ 不断自我连接形成的。但是字符串 s_2s2​ 是不确定的&#xff0c;现在只想知道它的最短长度是多少。 输入格式 第一行一个整数 LL&#xff0c;表示给出字符串的长度。 第二行给出字符串 s_1s1​ 的一个子…

【linux入门】基础知识学习笔记

文章目录【第一章-宏观知识】1.硬件和软件的关系2.操作系统 是什么、作用是什么3.常见的操作系统4.Linux的诞生5.Linux内核 是什么6.Linux发行版 是什么7.WSL是什么8.虚拟机快照9.FinalShell&#xff08;Xshell替代品&#xff09;【第二章-Linux基础命令】1.Linux目录结构2.什么…

Linux---权限

目录 1.文件访问者的分类&#xff08;人/用户&#xff09; 2.文件类型和访问权限&#xff08;事物属性&#xff09; 3.文件权限值的表示方法 a)字符表示方法 b)8进制数值表示方法 4.文件访问权限的相关设置方法 4.1 改属性 4.2 改人&#xff08;改拥有者/所属组&#xff09;…

数组常用方法总结 (3) :map / forEach / every / some

map 遍历数组的每一项。如果是简单数组&#xff0c;不改变原始数组&#xff08;值类型&#xff09;。如果是对象数组&#xff0c;原始数组可以被改变&#xff08;引用类型&#xff09;。遍历原始数组&#xff0c;返回值为原始数组的每一项&#xff0c;最终可组合成新数组。 简…

LeetCode 78 子集 | 解题思路分享

原题链接&#xff1a;78. 子集 - 力扣&#xff08;LeetCode&#xff09; 题目难度&#xff1a;中等 题目描述 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任…

忆享聚焦|5G投资、网络安全市场、云计算、Web3技术……近期热点资讯一览

“忆享聚焦”栏目第11期来啦&#xff01;本栏目汇集近期互联网最新资讯&#xff0c;聚焦前沿科技&#xff0c;关注行业发展动态&#xff0c;筛选高质量讯息&#xff0c;拓宽用户视野&#xff0c;让您以最低的时间成本获取最有价值的行业资讯。目录行业资讯1. SA&#xff1a;全球…

ubuntu虚拟机VmWare与主机共享文件夹

一、说明&#xff1a; 宿主操作系统&#xff1a;Windows 11 64位。 客户操作系统&#xff1a;Ubuntu 18.04.1 64位。 虚拟机软件&#xff1a;VMware Workstation 17 pro 二、步骤&#xff1a; 1、参考教程链接1&#xff0c;在主机设置共享文件夹。 注意&#xff1a;教程链接…