type
Post
status
Published
date
Jul 28, 2025
slug
2025/07/28/Analysis-of-Linux-PCI-driver-framework-(1)
summary
tags
Linux
category
Linux
created days
new update day
icon
password
Created_time
Jul 28, 2025 06:59 AM
Last edited time
Jul 29, 2025 02:13 AM
Read the fucking source code!
--By 鲁迅
A picture is worth a thousand words.
--By 高尔基
说明:
- Kernel版本:4.14
- ARM64处理器
- 使用工具:Source Insight 3.5, Visio
1. 概述
从本文开始,将会针对PCIe专题来展开,涉及的内容包括:
- PCI/PCIe总线硬件;
- Linux PCI驱动核心框架;
- Linux PCI Host控制器驱动;
不排除会包含PCIe外设驱动模块,一切随缘。
作为专题的第一篇,当然会先从硬件总线入手。进入主题前,先讲点背景知识。在PC时代,随着处理器的发展,经历了几代I/O总线的发展,解决的问题都是CPU主频提升与外部设备访问速度的问题:
- 第一代总线包含
ISA
、EISA
、VESA
和Micro Channel
等;
- 第二代总线包含
PCI
、AGP
、PCI-X
等;
- 第三代总线包含
PCIe
、mPCIe
、m.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总线相关的模块包括:
Host Bridge
,比如PC中常见的North Bridge(北桥)。
- 图中处理器、Cache、内存子系统通过
Host Bridge
连接到PCI上,Host Bridge
管理PCI总线域,是联系处理器和PCI设备的桥梁,完成处理器与PCI设备间的数据交换。其中数据交换,包含处理器访问PCI设备的地址空间
和PCI设备使用DMA机制访问主存储器
,在PCI设备用DMA访问存储器时,会存在 Cache 一致性问题,这个也是 Host Bridge 设计时需要考虑的;此外,Host Bridge
还可选的支持仲裁机制,热插拔等;
PCI Local Bus;
PCI总线,由Host Bridge
或者PCI-to-PCI Bridge
管理,用来连接各类设备,比如声卡、网卡、IDE接口等。- 可以通过
PCI-to-PCI Bridge
来扩展PCI总线,并构成多级总线的总线树,比如图中的PCI Local Bus #0
和PCI Local Bus #1
两条PCI总线就构成一颗总线树,同属一个总线域;
PCI-To-PCI Bridge
;PCI桥
,用于扩展PCI总线,使采用PCI总线进行大规模系统互联成为可能,管理下游总线,并转发上下游总线之间的事务;
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使用三种模型用于数据的传输:

Programmed I/O
:通过IO读写访问PCI设备空间;
DMA
:PIO 的方式比较低效,DMA 的方式可以直接去访问主存储器而无需CPU干预,效率更高;
Peer-to-peer
:两台 PCI 设备之间直接传送数据;
2.4 PCI总线地址空间映射
PCI体系架构支持三种地址空间:

memory空间
:- 针对 32bit 寻址,支持
4G
的地址空间,针对 64bit 寻址,支持16EB
的地址空间;
I/O空间
:- PCI最大支持
4G 的 IO 空间
,但受限于 x86 处理器的 IO 空间(16bits
带宽),很多平台将 PCI 的 IO 地址空间限定在64KB
;
配置空间
:- x86 CPU可以直接访问
memory空间
和I/O空间
,而配置空间则不能直接访问; - 每个 PCI 功能最多可以有 256 字节的配置空间;PCI总线在进行配置的时候,采用 ID 译码方式,使用设备的 ID 号,包括
Bus Number
,Device Number
,Function Number
和Register Number
, - 每个系统支持 256 条总线,每条总线支持 32 个设备,每个设备支持 8 个功能,由于每个功能最多有 256 字节的配置空间,因此总的配置空间大小为:
256B * 8 * 32 * 256 = 16M
;
有必要再进一步介绍一下配置空间:x86 CPU无法直接访问配置空间,只能通过IO映射的数据端口和地址端口间接访问 PCI 的配置空间,其中地址端口映射到
0CF8h - 0CFBh
,数据端口映射到 0CFCh - 0CFFh
;图为配置地址寄存器构成,PCI的配置过程分为两步:
- CPU 写
CF8h
端口,其中写的内容如图所示,BUS
,Device
,Function
能标识出特定的设备功能,Doubleword
来指定配置空间的具体某个寄存器;
- CPU 可以 IO读写
CFCh
端口,用于读取步骤 1 中的指定寄存器内容,或者写入指定寄存器内容。这个过程有点类似于通过 I2C 去配置外接芯片;

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

- Device

配置空间中有个寄存器字段需要说明一下:
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规范定义了分层的架构设计,包含三层:
Transaction
层- 负责
TLP
包(Transaction Layer Packet
)的封装与解封装,此外还负责QoS,流控、排序等功能;
Data Link
层- 负责
DLLP
包(Data Link Layer Packet
)的封装与解封装,此外还负责链接错误检测和校正,使用Ack/Nak
协议来确保传输可靠;
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的软件分析了,欲知详情、下回分解!
《PCI Express Technology 3.0》
《pci local bus specification revision 3.0》
《PCIe体系结构导读》
《PCI Express系统体系结构标准教材》


参考文献
作者:LoyenWang
公众号:LoyenWang
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
欢迎加入“喵星计算机技术研究院”,原创技术文章第一时间推送。

- 作者:tangcuyu
- 链接:https://expoli.tech/articles/2025/07/28/Analysis-of-Linux-PCI-driver-framework-(1)
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章