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

news/2024/11/15 1:44:30/

说明:

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

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桥去扩展总线;

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

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

3. 流程分析

3.1 设备驱动模型

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

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

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函数的调用,实际会去比对vendor和device等信息,这个都是厂家固化的,在驱动中设置成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的流程可以看出,主要有两大块:
  • PCI设备扫描,从循环也能看出来,每条总线支持32个设备,每个设备支持8个功能,扫描完设备后将设备注册进系统,pci_scan_device的过程中会去读取PCI设备的配置空间,获取到BAR的相关信息,细节不表了;
  • PCI桥设备扫描,PCI桥是用于连接上一级PCI总线和下一级PCI总线的,当发现有下一级总线时,创建子结构,并再次调用pci_scan_child_bus_extend的函数来扫描下一级的总线,从这个过程看,就是一个递归过程。
  • 从设备的扫描过程看,这是一个典型的DFS(Depth First Search)过程,熟悉数据结构与算法的同学应该清楚,这就类似典型的走迷宫的过程;

如果你对上述的流程还不清楚,再来一张图:

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

 


http://www.ppmy.cn/news/274654.html

相关文章

Linux驱动学习--初识PCI驱动(一)

PCI是什么 PCI—Peripheral Component Interconnect,外围设备互联总线。是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总…

Linux驱动学习--PCI设备驱动

目录 一、引言 二、PCI总线介绍 三、PCI设备驱动组成 四、查看本机上的PCI设备 一、引言 PCI总线在linux中应用的十分广泛,本文就来简单介绍一下 二、PCI总线描述 1、PCI总线结构 PCI是CPU和外围设备通信的高速传输总线。普通PCI总线带宽一般为132MB/s(在3…

PCI驱动

一、PCI总线 1、PCI桥 Host/PCI桥:用于连接CPU与PCI根总线,即“北桥芯片组” PCI/ISA桥:用于连接PCI与旧的ISA总线,即“南桥芯片组” PCI-to-PCI桥:用于连接PCI主总线与次总线 2、pci_bus结构体(PCI总线结构…

pci驱动框架

PCI 总线架构主要被分成三部分: 1.PCI 设备。符合 PCI 总线标准的设备就被称为 PCI 设备,PCI 总线架构中可以包含多个 PCI 设备。图中的 Audio 、LAN 都是一个 PCI 设备。PCI 设备同时也分为主设备和目标设备两种,主设备是一次访问操作的发…

pci设备驱动

原文地址:https://www.cnblogs.com/xiaoya901109/archive/2012/12/14/2818057.html 一,初始化设备模块 当Linux内核启动并完成对所有PCI设备进行扫描、登录和分配资源等初始化操作的同时,会建立起系统中所有PCI设备的拓扑结构,此后…

PCI驱动开发学习笔记(一)

PCIE简介 PCIe作为串行总线的一种,它的发展必然和另一种总线架构密不可分:并行总线。 像PCIe接口的显卡、声卡、网卡,都属于功能设备,在PCIe规范中,我们统称为Endpoint(简称EP)。还有其他两类设…

Linux PCI总线驱动-1

Linux PCI总线驱动-1 一、PCI总线介绍1. PCI介绍2. PCI接口3. PCI-X介绍4. PCI-E介绍4.1 下图从上到下依次是PCIEX16,X1,X44.2 PCI-E各版本的传输速度4.3 PCI-E不同传输通道数设备的金手指数和长度4.4 三种接口的传输速度比较 二、pci设备基础知识2.1 内…

PCI驱动程序实现

1、数据结构: PCI设备上有三种地址空间:PCI的I/O空间、PCI的存储空间和PCI的配置空间。CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用。内核在…