背 景

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

说明:

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

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的函数来扫描下一级的总线,从这个过程看,就是一个递归过程。
  • 从设备的扫描过程看,这是一个典型的DFS(Depth First Search)过程,熟悉数据结构与算法的同学应该清楚,这就类似典型的走迷宫的过程;

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

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

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

欢迎关注个人公众号,不定期分享Linux内核相关技术文章:

【原创】Linux PCI驱动框架分析(二)的更多相关文章

  1. 【原创】Linux PCI驱动框架分析(三)

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

  2. 【原创】Linux PCI驱动框架分析(一)

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  3. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

  4. Linux USB驱动框架分析【转】

    转自:http://blog.csdn.net/jeffade/article/details/7701431 Linux USB驱动框架分析(一) 初次接触和OS相关的设备驱动编写,感觉还挺有意思的 ...

  5. linux驱动基础系列--linux spi驱动框架分析

    前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...

  6. linux驱动基础系列--linux spi驱动框架分析(续)

    前言 这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容. spi设备树相关信息 如之前的文章里所述,控制器的device和s ...

  7. Linux USB驱动框架分析(2)【转】

    转自:http://blog.chinaunix.net/uid-23046336-id-3243543.html   看了http://blog.chinaunix.net/uid-11848011 ...

  8. Linux Framebuffer驱动框架之二软件架构(未完待续)【转】

    本文转载自:http://blog.csdn.net/gqb_driver/article/details/12918547 /************************************ ...

  9. Linux Framebuffer 驱动框架之一概念介绍及LCD硬件原理【转】

    本文转载自:http://blog.csdn.net/liuxd3000/article/details/17464779 一.基本概念 帧缓冲(Framebuffer)是Linux系统为显示设备提供 ...

随机推荐

  1. MockWebServer使用指南(转载)

    转载自(http://blog.csdn.net/shensky711/article/details/52771797 ) MockWebServer介绍 MockWebServer是square出 ...

  2. 【NOIP2015模拟11.2晚】JZOJ8月4日提高组T2 我的天

    [NOIP2015模拟11.2晚]JZOJ8月4日提高组T2 我的天 题目 很久很以前,有一个古老的村庄--xiba村,村子里生活着n+1个村民,但由于历届村长恐怖而且黑暗的魔法统治下,村民们各自过着 ...

  3. 异步任务-----django-celery

    异步任务 ---- django-celery   大家的知道celery的使用,网上也有很多的教程.因为最近在使用django来完成项目,无意间发现发现有个东西叫django-celery,比cel ...

  4. String、StringBUffer和StringBuilder的区别与使用

    一.区别 String是一个不可变的类,即创建String对象后,该对象中的字符串是不可变的,平时我们改变String对象中的字符串实际上是通过StringBuffer实现的,所以StringBuff ...

  5. PyQt(Python+Qt)学习随笔:QScrollBar以及QAbstractSlider滚动条部件功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 在Designer输入部件中Horizo ...

  6. Python妙用re.sub分析正则表达式匹配过程

    声明:本文所使用方法为老猿自行研究并编码,相关代码版权为老猿所有,禁止转载文章,代码禁止用于商业用途! 在<第11.23节 Python 中re模块的搜索替换功能:sub及subn函数>介 ...

  7. PyQt(Python+Qt)学习随笔:Qt Designer中toolBar的floatable属性

    floatable属性用于保存工具栏是否可以作为独立小窗口拖放,其类型为bool类型,默认值为True,表示工具栏可以漂作为独立窗口拖放. 下图是漂浮在窗口上的工具栏案例: 可以通过isFloatab ...

  8. ARL资产导出对接Xray扫描

    使用ARL资产灯塔系统对目标进行资产整理的时候,能够对获取的结果进行导出: 导出之后为excel文件 想要将site中的URL导出为txt文件,再使用Xray高级版进行批量化扫描: https://w ...

  9. Srcum冲刺_Day05

    一.团队展示: 1.项目:light_note备忘录 2.队名:删库跑路队 3.团队成员 队员(不分先后) 项目角色 黄敦鸿 后端工程师.测试 黄华 后端工程师.测试 黄骏鹏 后端工程师.测试 黄源钦 ...

  10. SPFA算法优化

    前言 \(SPFA\) 通常在稀疏图中运行效率高于 \(Dijkstra\) ,但是也容易被卡. 普通的 \(SPFA\) 时间复杂度为 \(O(km)\) ,其中 \(k\) 是一条边松弛其端点点的 ...