Linux PCI驱动框架分析(万字长文)

一口Linux 2021-02-28 00:00

背景

  • Read the fucking source code!  --By 鲁迅
  • A picture is worth a thousand words. --By 高尔基

说明:

  1. Kernel版本:4.14
  2. ARM64处理器


Linux PCI驱动框架分析(一)

1. 概述

从本文开始,将会针对PCIe专题来展开,涉及的内容包括:

  1. PCI/PCIe总线硬件;
  2. Linux PCI驱动核心框架;
  3. Linux PCI Host控制器驱动;

不排除会包含PCIe外设驱动模块,一切随缘。

作为专题的第一篇,当然会先从硬件总线入手。进入主题前,先讲点背景知识。在PC时代,随着处理器的发展,经历了几代I/O总线的发展,解决的问题都是CPU主频提升与外部设备访问速度的问题:

  1. 第一代总线包含 ISAEISAVESAMicro Channel等;
  2. 第二代总线包含 PCIAGPPCI-X等;
  3. 第三代总线包含 PCIemPCIem.2等;

PCIe(PCI Express)是目前PC和嵌入式系统中最常用的高速总线,PCIe在PCI的基础上发展而来,在软件上PCIe与PCI是后向兼容的,PCI的系统软件可以用在PCIe系统中。

  本文会分两部分展开,先介绍PCI总线,然后再介绍PCIe总线,方便在理解上的过渡,开始旅程吧。

2. PCI Local Bus

2.1 PCI总线组成

  • PCI总线(Peripheral Component Interconnect,外部设备互联),由Intel公司提出,其主要功能是连接外部设备;
  • PCI Local Bus,PCI局部总线,局部总线技术是PC体系结构发展的一次变革,是在 ISA总线CPU总线之间增加的一级总线或管理层,可将一些高速外设,如图形卡、硬盘控制器等从 ISA总线上卸下,而通过局部总线直接挂接在CPU总线上,使之与高速 CPU总线相匹配。PCI总线,指的就是 PCI Local Bus

先来看一下PCI Local Bus的系统架构图:


从图中看,与PCI总线相关的模块包括:

  1. Host Bridge,比如PC中常见的North Bridge(北桥)。图中处理器、Cache、内存子系统通过Host Bridge连接到PCI上,Host Bridge管理PCI总线域,是联系处理器和PCI设备的桥梁,完成处理器与PCI设备间的数据交换。其中数据交换,包含处理器访问PCI设备的地址空间PCI设备使用DMA机制访问主存储器,在PCI设备用DMA访问存储器时,会存在Cache一致性问题,这个也是Host Bridge设计时需要考虑的;此外,Host Bridge还可选的支持仲裁机制,热插拔等;

  2. PCI Local Bus;PCI总线,由Host Bridge或者PCI-to-PCI Bridge管理,用来连接各类设备,比如声卡、网卡、IDE接口等。可以通过PCI-to-PCI Bridge来扩展PCI总线,并构成多级总线的总线树,比如图中的PCI Local Bus #0PCI Local Bus #1两条PCI总线就构成一颗总线树,同属一个总线域;

  3. PCI-To-PCI BridgePCI桥,用于扩展PCI总线,使采用PCI总线进行大规模系统互联成为可能,管理下游总线,并转发上下游总线之间的事务;

  4. PCI Device;PCI总线中有三类设备:PCI从设备,PCI主设备,桥设备。PCI从设备:被动接收来自Host Bridge或者其他PCI设备的读写请求;PCI主设备:可以通过总线仲裁获得PCI总线的使用权,主动向其他PCI设备或主存储器发起读写请求;桥设备:管理下游的PCI总线,并转发上下游总线之间的总线事务,包括PCI桥PCI-to-ISA桥PCI-to-Cardbus桥等。

2.2 PCI总线信号定义

PCI总线是一条共享总线,可以挂接多个PCI设备,PCI设备通过一系列信号与PCI总线相连,包括:地址/数据信号、接口控制信号、仲裁信号、中断信号等。如下图:


  • 左侧红色框里表示的是PCI总线必需的信号,而右侧蓝色框里表示的是可选的信号;
  • AD[31:00]:地址与数据信号复用,在传送时第一个时钟周期传送地址,下一个时钟周期传送数据;
  • C/BE[3:0]#:PCI总线命令与字节使能信号复用,在地址周期中表示的是PCI总线命令,在数据周期中用于字节选择,可以进行单字节、字、双字访问;
  • PAR:奇偶校验信号,确保 AD[31:00]C/BE[3:0]#传递的正确性;
  • Interface Control:接口控制信号,主要作用是保证数据的正常传递,并根据PCI主从设备的状态,暂停、终止或者正常完成总线事务:
    • FRAME#:表示PCI总线事务的开始与结束;
    • IRDY#:信号由PCI主设备驱动,信号有效时表示PCI主设备数据已经ready;
    • TRDY#:信号由目标设备驱动,信号有效时表示目标设备数据已经ready;
    • STOP#:目标设备请求主设备停止当前总线事务;
    • DEVSEL#:PCI总线的目标设备已经准备好;
    • IDSEL:PCI总线在配置读写总线事务时,使用该信号选择PCI目标设备;
  • Arbitration:仲裁信号,由 REQ#GNT#组成,与PCI总线的仲裁器直接相连,只有PCI主设备需要使用该组信号,每条PCI总线上都有一个总线仲裁器;
  • Error Reporting:错误信号,包括 PERR#奇偶校验错误和 SERR系统错误;
  • System:系统信号,包括时钟信号和复位信号;

看一下C/BE[3:0]都有哪些命令吧:


2.3 PCI事务模型

PCI使用三种模型用于数据的传输:


  1. Programmed I/O:通过IO读写访问PCI设备空间;
  2. DMA:PIO的方式比较低效,DMA的方式可以直接去访问主存储器而无需CPU干预,效率更高;
  3. Peer-to-peer:两台PCI设备之间直接传送数据;

2.4 PCI总线地址空间映射

PCI体系架构支持三种地址空间:


  1. memory空间:针对32bit寻址,支持4G的地址空间,针对64bit寻址,支持16EB的地址空间;

  2. I/O空间PCI最大支持4G的IO空间,但受限于x86处理器的IO空间(16bits带宽),很多平台将PCI的IO地址空间限定在64KB;

  3. 配置空间x86 CPU可以直接访问memory空间I/O空间,而配置空间则不能直接访问;每个PCI功能最多可以有256字节的配置空间;PCI总线在进行配置的时候,采用ID译码方式,使用设备的ID号,包括Bus NumberDevice NumberFunction NumberRegister Number,每个系统支持256条总线,每条总线支持32个设备,每个设备支持8个功能,由于每个功能最多有256字节的配置空间,因此总的配置空间大小为:256B * 8 * 32 * 256 = 16M;

    有必要再进一步介绍一下配置空间:x86 CPU无法直接访问配置空间,通过IO映射的数据端口和地址端口间接访问PCI的配置空间,其中地址端口映射到0CF8h - 0CFBh,数据端口映射到0CFCh - 0CFFh

    • 图为配置地址寄存器构成,PCI的配置过程分为两步:
    1. CPU写CF8h端口,其中写的内容如图所示,BUS,Device,Function能标识出特定的设备功能,Doubleword来指定配置空间的具体某个寄存器;
    2. CPU可以IO读写CFCh端口,用于读取步骤1中的指定寄存器内容,或者写入指定寄存器内容。这个过程有点类似于通过I2C去配置外接芯片;

    那具体的配置空间寄存器都是什么样的呢?每个功能256Byte,前边64Byte是Header,剩余的192Byte支持可选功能。有种类型的PCI功能:Bridge和Device,两者的Header都不一样。

    • Bridge

    • Device

    1. 配置空间中有个寄存器字段需要说明一下:

    2. Base Address Register ,也就是 BAR空间 ,当PCI设备的配置空间被初始化后,该设备在PCI总线上就会拥有一个独立的PCI总线地址空间,这个空间就是 BAR空间 BAR空间 可以存放IO地址空间,也可以存放存储器地址空间。

    • PCI总线取得了很大的成功,但随着CPU的主频不断提高,PCI总线的带宽也捉襟见肘。此外,它本身存在一些架构上的缺陷,面临一系列挑战,包括带宽、流量控制、数据传送质量等;
    • PCIe应运而生,能有效解决这些问题,所以PCIe才是我们的主角;

    3. PCI Express

    3.1 PCIe体系结构

    先看一下PCIe架构的组成图:

    • Root Complex:CPU和PCIe总线之间的接口可能会包含几个模块(处理器接口、DRAM接口等),甚至可能还会包含芯片,这个集合就称为 Root Complex,它作为PCIe架构的根,代表CPU与系统其它部分进行交互。广义来说, Root Complex可以认为是CPU和PCIe拓扑之间的接口, Root Complex会将CPU的request转换成PCIe的4种不同的请求(Configuration、Memory、I/O、Message);
    • Switch:从图中可以看出, Swtich提供扇出能力,让更多的PCIe设备连接在PCIe端口上;
    • Bridge:桥接设备,用于去连接其他的总线,比如PCI总线或PCI-X总线,甚至另外的PCIe总线;
    • PCIe Endpoint:PCIe设备;
    • 图中白色的小方块代表 Downstream端口,灰色的小方块代表 Upstream端口;

    前文提到过,PCIe在软件上保持了后向兼容性,那么在PCIe的设计上,需要考虑在PCI总线上的软件视角,比如Root Complex的实现可能就如下图所示,从而看起来与PCI总线相差无异:


    • Root Complex通常会实现一个内部总线结构和多个桥,从而扇出到多个端口上;
    • Root Complex的内部实现不需要遵循标准,因此都是厂家specific的;

    Switch的实现可能如下图所示:


    • Switch就是一个扩展设备,所以看起来像是各种桥的连接路由;

    3.2 PCIe数据传输


    • 与PCI总线不同(PCI设备共享总线),PCIe总线使用端到端的连接方式,互为接收端和发送端,全双工,基于数据包的传输;
    • 物理底层采用差分信号(PCI链路采用并行总线,而PCIe链路采用串行总线),一条Lane中有两组差分信号,共四根信号线,而PCIe Link可以由多条Lane组成,可以支持1、2、4、8、12、16、32条;

    PCIe规范定义了分层的架构设计,包含三层:


    1. Transaction层

    • 负责TLP包( Transaction Layer Packet)的封装与解封装,此外还负责QoS,流控、排序等功能;
  1. Data Link层

    • 负责DLLP包( Data Link Layer Packet)的封装与解封装,此外还负责链接错误检测和校正,使用Ack/Nak协议来确保传输可靠;
  2. Physical层

    • 负责 Ordered-Set包的封装与解封装,物理层处理TLPs、DLLPs、Ordered-Set三种类型的包传输;

    数据包的封装与解封装,与网络包的创建与解析很类似,如下图:


    • 封装的时候,在Payload数据前添加各种包头,解析时是一个逆向的过程;

    来一个更详细的PCIe分层图:


    3.3 PCIe设备的配置空间

    为了兼容PCI软件,PCIe保留了256Byte的配置空间,如下图:


    此外,在这个基础上将配置空间扩展到了4KB,还进行了功能的扩展,比如Capability、Power Management、MSI中断等:


    • 扩展后的区域将使用MMIO的方式进行访问;

    草草收场吧,对PCI和PCIe有一些轮廓上的认知了,可以开始Source Code的软件分析了,欲知详情、下回分解!


    Linux PCI驱动框架分析(二)

    1. 概述

    • 本文将分析Linux PCI子系统的框架,主要围绕Linux PCI子系统的初始化以及枚举过程分析;
    • 如果对具体的硬件缺乏了解,建议先阅读上篇文章 《Linux PCI驱动框架分析(一)》

    话不多说,直接开始。

    2. 数据结构

    • PCI体系结构的拓扑关系如图所示,而图中的不同数据结构就是用于来描述对应的模块;
    • Host Bridge连接CPU和PCI系统,由 struct pci_host_bridge描述;
    • struct pci_dev描述PCI设备,以及PCI-to-PCI桥设备;
    • struct pci_bus用于描述PCI总线, struct pci_slot用于描述总线上的物理插槽;

    来一张更详细的结构体组织图:

    • 总体来看,数据结构对硬件模块进行了抽象,数据结构之间也能很便捷的构建一个类似PCI子系统物理拓扑的关系图;
    • 顶层的结构为 pci_host_bridge,这个结构一般由Host驱动负责来初始化创建;
    • pci_host_bridge指向root bus,也就是编号为0的总线,在该总线下,可以挂接各种外设或物理slot,也可以通过PCI桥去扩展总线;

    3. 流程分析

    3.1 设备驱动模型

    Linux PCI驱动框架,基于Linux设备驱动模型,因此有必要先简要介绍一下,实际上Linux设备驱动模型也是一个大的topic,先挖个坑,有空再来填。来张图吧:

    • 简单来说,Linux内核建立了一个统一的设备模型,分别采用总线、设备、驱动三者进行抽象,其中设备与驱动都挂在总线上,当有新的设备注册或者新的驱动注册时,总线会去进行匹配操作( match函数),当发现驱动与设备能进行匹配时,就会执行probe函数的操作;
    • 从数据结构中可以看出, bus_type会维护两个链表,分别用于挂接向其注册的设备和驱动,而 match函数就负责匹配检测;
    • 各类驱动框架也都是基于图中的机制来实现,在这之上进行封装,比如I2C总线框架等;
    • 设备驱动模型中,包含了很多 kset/kobject等内容,建议去看看之前的文章 《linux设备模型之kset/kobj/ktype分析》
    • 好了,点到为止,感觉要跑题了,强行拉回来。

    3.2 初始化

    既然说到了设备驱动模型,那么首先我们要做的事情,就是先在内核里边创建一个PCI总线,用于挂接PCI设备和PCI驱动,我们的实现来到了pci_driver_init()函数:

    • 内核在PCI框架初始化时会调用 pci_driver_init()来创建一个PCI总线结构(全局变量 pci_bus_type),这里描述的PCI总线结构,是指驱动匹配模型中的概念,PCI的设备和驱动都会挂在该PCI总线上;
    • pci_bus_type的函数操作接口也能看出来, pci_bus_match用来检查设备与驱动是否匹配,一旦匹配了就会调用 pci_device_probe函数,下边针对这两个函数稍加介绍;

    3.2.1 pci_bus_match

    • 设备或者驱动注册后,触发 pci_bus_match函数的调用,实际会去比对 vendordevice等信息,这个都是厂家固化的,在驱动中设置成 PCI_ANY_ID就能支持所有设备;
    • 一旦匹配成功后,就会去触发 pci_device_probe的执行;

    3.2.2 pci_device_probe

    • 实际的过程也是比较简单,无非就是进行匹配,一旦匹配上了,直接调用驱动程序的probe函数,写过驱动的同学应该就比较清楚后边的流程了;

    3.3 枚举

    • 我们还是顺着设备驱动匹配的思路继续开展;
    • 3.2节描述的是总线的创建,那么本节中的枚举,显然就是设备的创建了;
    • 所谓设备的创建,就是在Linux内核中维护一些数据结构来对硬件设备进行描述,而硬件的描述又跟上文中的数据结构能对应上;

    枚举的入口函数:pci_host_probe

    • 设备的扫描从 pci_scan_root_bus_bridge开始,首先需要先向系统注册一个 host bridge,在注册的过程中需要创建一个 root bus,也就是 bus 0,在 pci_register_host_bridge函数中,主要是一系列的初始化和注册工作,此外还为总线分配资源,包括地址空间等;
    • pci_scan_child_bus开始,从 bus 0向下扫描并添加设备,这个过程由 pci_scan_child_bus_extend来完成;
    • pci_scan_child_bus_extend的流程可以看出,主要有两大块:
    1. PCI设备扫描,从循环也能看出来,每条总线支持32个设备,每个设备支持8个功能,扫描完设备后将设备注册进系统,pci_scan_device的过程中会去读取PCI设备的配置空间,获取到BAR的相关信息,细节不表了;
    2. PCI桥设备扫描,PCI桥是用于连接上一级PCI总线和下一级PCI总线的,当发现有下一级总线时,创建子结构,并再次调用 pci_scan_child_bus_extend的函数来扫描下一级的总线,从这个过程看,就是一个递归过程。
  3. 从设备的扫描过程看,这是一个典型的DFS( Depth First Search)过程,熟悉数据结构与算法的同学应该清楚,这就类似典型的走迷宫的过程;
  4. 如果你对上述的流程还不清楚,再来一张图:

    • 图中的数字代表的就是扫描的过程,当遍历到PCI桥设备的时候,会一直穷究到底,然后再返回来;
    • 当枚举过程结束后,系统中就已经维护了PCI设备的各类信息了,在设备驱动匹配模型中,总线和设备都已经具备了,剩下的就是写个驱动了;

    暂且写这么多,细节方面不再赘述了,把握大体的框架即可,无法扼住PCI的咽喉,那就扼住它的骨架吧。


    Linux PCI驱动框架分析(三)

    1. 概述

    先回顾一下PCIe的架构图:

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

    2. 流程分析

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

    • 《Linux PCI驱动框架分析(二)》中提到过PCI设备、PCI总线和PCI驱动的创建,PCI设备和PCI驱动挂接在PCI总线上,这个理解很直观。针对PCIe的控制器来说,同样遵循设备、总线、驱动的匹配模型,不过这里的总线是由虚拟总线 platform总线来替代,相应的设备和驱动分别为 platform_deviceplatform_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-namemsi1, msi0用于MSI中断, intx用于旧式中断,与 interrupts中的中断号对应;
    • reg:包含用于访问PCIe控制器操作的寄存器物理地址和大小;
    • reg-name:分别表示 Bridge registersPCIe Controller registers,  Configuration space region,与 reg中的值对应;
    • ranges:PCIe地址空间转换到CPU的地址空间中的范围;
    • bus-range:PCIe总线的起始范围;
    • interrupt-map-maskinterrupt-map:标准PCI属性,用于定义PCI接口到中断号的映射;
    • legacy-interrupt-controller:旧式的中断控制器;

    2.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_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_domainmwl_pcie_enable_msi与中断级联相关,下个小节介绍;
    • pci_scan_root_bus_bridge:对总线上的设备进行扫描枚举,这个流程在 Linux PCI驱动框架分析(二)中分析过。 brdige结构体中的 pci_ops字段,用于指向PCI的读写操作函数集,当具体扫描到设备要读写配置空间时,调用的就是这个函数,由具体的Controller驱动实现;

    2.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控制器的中断时,调用它的中断处理函数,也就是上文中提到过的 nwl_pcie_leg_handlernwl_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操作函数集;
    • 好吧,我个人不太喜欢分析某个驱动,草草收场了;

    参考

    《PCI Express Technology 3.0》

    《pci local bus specification revision 3.0》

    《PCIe体系结构导读》

    《PCI Express系统体系结构标准教材》


     

    ------------ END ------------


    推荐阅读


    【1】C语言实现MD5加密,竟如此简单!必读
    【2】【粉丝问答11】如何在内网搭建TCP服务器并能被外网直接访问 必读
    【3】手把手教Linux驱动10-platform总线详解必读
    【4】基于Linux的tty架构及UART驱动详解必读
    【5】1万字30张图说清TCP协议 必读
    【6】 一键获取linux内存、cpu、磁盘IO等信息脚本编写,及其原理详解 必读
    【7】 自己DIY一个mp3播放器
    【8】 从Linux源码看Socket(TCP)的bind
    【9】 【粉丝问答12】如何计算函数的执行时间? 必读
    【10】 【粉丝问答13】11道嵌入式笔试题,看下你会几道? 必读
    【11】 作为一个江苏人,我眼中的苏宁

     


     

    进群,请加一口君个人微信,带你嵌入式入门进阶。


    在公众号内回复「1024」,即可免费获取学习资料,期待你的关注~

    一口Linux 写点代码,写点人生!
    评论
    • 在2024年的科技征程中,具身智能的发展已成为全球关注的焦点。从实验室到现实应用,这一领域正以前所未有的速度推进,改写着人类与机器的互动边界。这一年,我们见证了具身智能技术的突破与变革,它不仅落地各行各业,带来新的机遇,更在深刻影响着我们的生活方式和思维方式。随着相关技术的飞速发展,具身智能不再仅仅是一个技术概念,更像是一把神奇的钥匙。身后的众多行业,无论愿意与否,都像是被卷入一场伟大变革浪潮中的船只,注定要被这股汹涌的力量重塑航向。01为什么是具身智能?为什么在中国?最近,中国具身智能行业的进
      艾迈斯欧司朗 2025-02-28 15:45 286浏览
    • 一、VSM的基本原理震动样品磁强计(Vibrating Sample Magnetometer,简称VSM)是一种灵敏且高效的磁性测量仪器。其基本工作原理是利用震动样品在探测线圈中引起的变化磁场来产生感应电压,这个感应电压与样品的磁矩成正比。因此,通过测量这个感应电压,我们就能够精确地确定样品的磁矩。在VSM中,被测量的样品通常被固定在一个震动头上,并以一定的频率和振幅震动。这种震动在探测线圈中引起了变化的磁通量,从而产生了一个交流电信号。这个信号的幅度和样品的磁矩有着直接的关系。因此,通过仔细
      锦正茂科技 2025-02-28 13:30 128浏览
    • 在物联网领域中,无线射频技术作为设备间通信的核心手段,已深度渗透工业自动化、智慧城市及智能家居等多元场景。然而,随着物联网设备接入规模的不断扩大,如何降低运维成本,提升通信数据的传输速度和响应时间,实现更广泛、更稳定的覆盖已成为当前亟待解决的系统性难题。SoC无线收发模块-RFM25A12在此背景下,华普微创新推出了一款高性能、远距离与高性价比的Sub-GHz无线SoC收发模块RFM25A12,旨在提升射频性能以满足行业中日益增长与复杂的设备互联需求。值得一提的是,RFM25A12还支持Wi-S
      华普微HOPERF 2025-02-28 09:06 200浏览
    • RGB灯光无法同步?细致的动态光效设定反而成为产品客诉来源!随着科技的进步和消费者需求变化,电脑接口设备单一功能性已无法满足市场需求,因此在产品上增加「动态光效」的形式便应运而生,藉此吸引消费者目光。这种RGB灯光效果,不仅能增强电脑周边产品的视觉吸引力,还能为用户提供个性化的体验,展现独特自我风格。如今,笔记本电脑、键盘、鼠标、鼠标垫、耳机、显示器等多种电脑接口设备多数已配备动态光效。这些设备的灯光效果会随着音乐节奏、游戏情节或使用者的设置而变化。想象一个画面,当一名游戏玩家,按下电源开关,整
      百佳泰测试实验室 2025-02-27 14:15 152浏览
    • 1,微软下载免费Visual Studio Code2,安装C/C++插件,如果无法直接点击下载, 可以选择手动install from VSIX:ms-vscode.cpptools-1.23.6@win32-x64.vsix3,安装C/C++编译器MniGW (MinGW在 Windows 环境下提供类似于 Unix/Linux 环境下的开发工具,使开发者能够轻松地在 Windows 上编写和编译 C、C++ 等程序.)4,C/C++插件扩展设置中添加Include Path 5,
      黎查 2025-02-28 14:39 174浏览
    • 振动样品磁强计是一种用于测量材料磁性的精密仪器,广泛应用于科研、工业检测等领域。然而,其测量准确度会受到多种因素的影响,下面我们将逐一分析这些因素。一、温度因素温度是影响振动样品磁强计测量准确度的重要因素之一。随着温度的变化,材料的磁性也会发生变化,从而影响测量结果的准确性。因此,在进行磁性测量时,应确保恒温环境,以减少温度波动对测量结果的影响。二、样品制备样品的制备过程同样会影响振动样品磁强计的测量准确度。样品的形状、尺寸和表面处理等因素都会对测量结果产生影响。为了确保测量准确度,应严格按照规
      锦正茂科技 2025-02-28 14:05 174浏览
    • 更多生命体征指标风靡的背后都只有一个原因:更多人将健康排在人生第一顺位!“AGEs,也就是晚期糖基化终末产物,英文名Advanced Glycation End-products,是存在于我们体内的一种代谢产物” 艾迈斯欧司朗亚太区健康监测高级市场经理王亚琴说道,“相信业内的朋友都会有关注,最近该指标的热度很高,它可以用来评估人的生活方式是否健康。”据悉,AGEs是可穿戴健康监测领域的一个“萌新”指标,近来备受关注。如果站在学术角度来理解它,那么AGEs是在非酶促条件下,蛋白质、氨基酸
      艾迈斯欧司朗 2025-02-27 14:50 452浏览
    • 2020年,世界经济论坛发布了《将来工作报告》,预言了人工智能 (AI)、机器人和自动化将在五年内对劳动力市场带来反天性的变化。最震撼人心的预测是:85亿个工位将消失,97亿个新工位将被创造。这个信息给我们提出了一些骂烈的疑问:AI究竟会消灭哪些工作?管理者的规划依然重要吗?AI会代替我们的管理之路吗?AI不会替代管理者,会进一步增强他们随着AI在机器学习、自然语言处理和预测分析方面的进步,许多人对AI接管事务表示担心。但研究显示,大多数情况下,AI将作为工具与管理者协同完成任务,而不是替换他们
      优思学院 2025-03-01 12:22 49浏览
    • 压力传感器是指能感受压力信号,并能按照一定的规律将压力信号转换成可用的电信号的器件或装置。压力传感器通常由压力敏感元件和信号处理单元组成,按不同测压方法,压力传感器可分为表压传感器、差压传感器和绝压传感器;按不同测压原理,压力传感器又可分为常见的压阻式压力传感器、电容式压力传感器、扩散硅压力传感器、蓝宝石压力传感器与陶瓷压力传感器等。作为工业自动化与智能化的关键器件,压力传感器在各类工业设备中扮演着不可或缺的角色,其通过精确感知和转换物理压力信号,为工业物联网(IIoT)构建起了高效精确的“压力
      华普微HOPERF 2025-03-03 10:19 74浏览
    • 应用趋势与客户需求,AI PC的未来展望随着人工智能(AI)技术的日益成熟,AI PC(人工智能个人电脑)逐渐成为消费者和企业工作中的重要工具。这类产品集成了最新的AI处理器,如NPU、CPU和GPU,并具备许多智能化功能,为用户带来更高效且直观的操作体验。AI PC的目标是提升工作和日常生活的效率,通过深度学习与自然语言处理等技术,实现更流畅的多任务处理、实时翻译、语音助手、图像生成等功能,满足现代用户对生产力和娱乐的双重需求。随着各行各业对数字转型需求的增长,AI PC也开始在各个领域中显示
      百佳泰测试实验室 2025-02-27 14:08 283浏览
    • DeepSeek的风还吹到了TV圈。去年,人工智能领域迎来了重大突破,然而对大多数人而言,它依旧是个颇为模糊的概念。即便是如ChatGPT这样的产品,给人最直接的感受也仅仅是一个相较于Siri更为智能的语音交互工具。直至今年,DeepSeek的惊艳亮相,人们真正感受到了生成式人工智能在实际应用中的价值。在这股浪潮的推动下,电视厂商们也纷纷跟上了脚步。2月11日,海信电视宣布正式接入DeepSeek,并支持满血R1和V3版本自由切换,成为行业首个搭载深度思考智能体的电视品牌。长虹电视紧随其后,宣布
      刘旷 2025-03-03 09:55 68浏览
    • 美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?美国加州CEC能效跟DOE能效有什么区别?CEC/DOE是什么关系?‌美国加州CEC能效认证与美国DOE能效认证在多个方面存在显著差异‌。认证范围和适用地区‌CEC能效认证‌:仅适用于在加利福尼亚州销售的电器产品。CEC认证的范围包括制冷设备、房间空调、中央空调、便携式空调、加热器、热水器、游泳池加热器、卫浴配件、光源、应急灯具、交通信号模块、灯具、洗碗机、洗衣机、干衣机、烹饪器具、电机和压缩机、变压器、外置电源、消费类电子设备
      张工nx808593 2025-02-27 18:04 140浏览
    •           近日受某专业机构邀请,参加了官方举办的《广东省科技创新条例》宣讲会。在与会之前,作为一名技术工作者一直认为技术的法例都是保密和侵权方面的,而潜意识中感觉法律有束缚创新工作的进行可能。通过一个上午学习新法,对广东省的科技创新有了新的认识。广东是改革的前沿阵地,是科技创新的沃土,企业是创新的主要个体。《广东省科技创新条例》是广东省为促进科技创新、推动高质量发展而制定的地方性法规,主要内容包括: 总则:明确立法目
      广州铁金刚 2025-02-28 10:14 127浏览
    •         近日,广电计量在聚焦离子束(FIB)领域编写的专业著作《聚焦离子束:失效分析》正式出版,填补了国内聚焦离子束领域实践性专业书籍的空白,为该领域的技术发展与知识传播提供了重要助力。         随着芯片技术不断发展,芯片的集成度越来越高,结构也日益复杂。这使得传统的失效分析方法面临巨大挑战。FIB技术的出现,为芯片失效分析带来了新的解决方案。它能够在纳米尺度上对芯片进行精确加工和分析。当芯
      广电计量 2025-02-28 09:15 167浏览
    我要评论
    0
    点击右上角,分享到朋友圈 我知道啦
    请使用浏览器分享功能 我知道啦