概述
PCI Express (peripheral component interconnect express) 简称PCIe,是一种高速、串行、全双工、计算机扩展总线标准,采用高速差分总线,并采用点到点的连接方式用于两个设备之间的通信。多个PCI Express设备通过使用Switch互连,因此可以在一个系统中将大量设备连接在一起。相对于PCI引入了一些新特性,如流量控制机制、服务质量管理(QoS)、热插拔支持、数据完整性和新型错误处理机制等。
PCIe链路
所谓全双工就是允许在同一时刻,同时进行发送和接收数据。将两个设备连接在一起的 PCI Express互连称为链路(Link)。 链路由每个方向上的x1、x2、x4、x8、x12、x16或x32信号对组成,这些信号称为通道(Lane)。链路内通道的数量称为链路宽度。一条x1的链路有一条通道,即每个方向都有一对差分信号,共4个信号。由于是串行总线,因此所有的数据(包括配置信息等)都是以数据包(Packet)为单位进行发送的。
PCIe总线使用端到端的连接方式,在一条PCIe链路的两端只能各连接一个设备,这两个设备互为数据发送端和数据接收端。由于PCIe是支持全双工通信的,所以发送端和接收端中都含有TX(发送逻辑)和RX(按收逻辑)。在PCIe总线的物理链路的一个数据通路(Lane)中,有两组差分信号,共4根信号线组成
PCIe分层结构
PCIe总线架构是一种分层协议架构,分为事务层(Transaction Layer)、数据链路层(Data Link Layer) 和物理层(Physical Layer)。这些层中的每一层都分为两部分:一部分处理出站 (要发送的) 信息,另一部分处理入站 (接收的) 信息。
在PCIe结构中使用数据包在设备之间传递信息,数据包在事务层和数据链路层中形成,以将信息从发送设备传送到接收设备
PCIe的事务类型
PCIe协议总共规定了Memory、I/O、Configuration和Message四种事务类型(TLP请求),其中前三种是从PCI继承过来的,消息是PCIE所扩展的。前三种分别用于访问内存空间、IO空间、配置空间,Message用于传输中断信息、错误信息等。这四种TLP请求,如果需要对方回应(对方返回一个Completion TLP),称之为Non-Posted TLP;不需要对方回应,称之为Posted TLP
pcie总线的拓扑结构
root complex
RC是PCIe体系结构中的一个重要的组成部件,它与PCI总线的中Host bridge有些类似,是CPU和PCIe总线直接的接口。它的主要功能是完成存储器域到PCIe总线域的地址转换,随着虚拟化技术的引入,RC的功能也越来越复杂。RC把来自CPU的request转化成PCIe的4种不同的requests(configuration, Memory, I/O, Message)并发送给接在它下面的设备。从软件的角度来看,RC像是一组虚拟的PCI-PCI桥
PCIe Switch & Bridge
Switch提供了分散或者是聚合的功能,它允许更多的设备接入到 一个PCIe Port。它扮演了数据包路由的功能。Bridge提供了一个转换接口用来连接其他的总线,如PCI/PCI-X。这样可以允许在PCIe的系统中接入一张旧的PCI设备。
PCIe Endpoint
它只有一个上游端口,位于PCIe拓扑结构的树的末端。它作为请求的发起者或者完成者。分为Legacy Endpoint和Native Endpoint,Legacy使用PCI总线的操作用于支持向后兼容
BDF(Bus、Device、Function)
每一个Pcie设备可以只有一个功能(Function),即Fun0。也可以拥有最多8个功能,即多功能设备(Multi-Fun)。不管这个设备拥有多少个功能,其每一个功能都有唯一的配置空间与之对应。和PCI总线一样,PCIe总线的每一个功能(Function)都有唯一的标识符与之对应。这个标识符就是BDF(Bus、Device、Function),PCIe的配置软件(即root 的应用层)应该有能力识别整个PCIe总线的拓扑逻辑,以及其中的每一条总线(Bus),每一个设备(Device)和每一项功能(Function)。在BDF中,Bus Num占用8位,Device Num占用5位,Function Num占用3位。显然PCIe总线最多支持256条Bus、每条Bus支持32个Device,每个Device支持8个Function
配置空间
PCIe的配置空间(Configuration Space)是一种用于存储和管理PCIe设备相关信息的特殊地址空间。它包含了设备的配置寄存器和扩展配置寄存器,这些寄存器用于描述设备的功能、性能、资源分配等信息,设备在出厂时,配置空间是有一些默认值的
早期的PCI时期,系统为每个PCI设备分配的内存大小仅有256个Bytes,其中前64字节是标准配置空间header,后面的192字节是Capability结构, 展示pci能提供的能力。到后来的PCIE时期,PCIe设备性能增强,PCIe设备的配置空间扩展至4KBytes。但为了兼容PCI,PCIe的配置空间前256字节与PCI保持一致,256~4096字节是pcie 扩展配置空间。
我们知道PCIe一共支持256条Bus,每条bus支持32个Dev,每个dev支持8个Func。因此在满负载的情况下,共需内存大小4k * 256 * 32 *8 = 256MB,这个256M的内存空间是为PCIE设备准备的空间,系统不可用,但是对于很多嵌入式cpu,预留的配置空间并不大,可能只包含几个配置空间
配置空间的前64Bytes位标准的头部空间,之后192字节为Capabilities结构,256~4096Bytes则是PCIe的扩展配置空间
type0
type0为Endpoint设备
type1
type1为PCI Bridge和Switch设备
公共的寄存器
Device ID: 设备ID, 表示该PCI设备的设备号,只读。
Vendor ID: 厂商ID, 表示生产该设备的厂商的编号,只读。
Status: pci设备状态寄存器,用于保存pci设备的状态,如中断状态或运行产生错误时的状态。
Command: PCI设备命令寄存器,主要是负责使能或关闭pci设备的I/O 访问,memory访问和INTx中断等。
Class Code: 设备分类信息,表示pci设备属于哪一种类别,如网卡,存储卡,显卡等。
Revision ID: 设备版本ID, 表示PCI设备的版本号。该寄存器可以被认为是Device ID寄存器的扩展。 只读。
BIST: 可选,用于内部自检。
Header type: PCI设备头类型寄存器,表示该设备是PCI EP设备还是PCI 桥设备。PCI配置空间是type0还是type1就是由该寄存器确定。
Lantency Timer: 在PCI总线中,多个设备共享同一条总线带宽,该寄存器用来控制PCI设备占用PCI总线的时间。PCIe设备不需要使用该寄存器,该寄存器的值必须为0。因为PCIe总线的仲裁方法与PCI总线不同,使用的连接方法也与PCI总线不同。
Cache line size: cache缓存大小。对于PCIe设备,该寄存器的值无意义。
Expansion Rom Base Address: 扩展ROM映射基地址寄存器。分配给ROM使用,用于PCI设备在处理器还没有运行操作系统之前,完成基本的初始化设置。
Base Address register: BAR地址寄存器负责PCI设备内部空间的映射,bit 0标识IO空间还是MEM空间,bits 2:1 用来标识address为32bit还是64bit,bit 3标识能否预取。type0有6个32bit的BAR寄存器,type1与2个32bit的BAR寄存器。每一个BAR地址对应一个地址空间
Capbility Pointer: 第一个PCI capbility的地址偏移, capbility用于表示pci设备支持的能力。该寄存器存放Capabilities 结构链表的头指针。在一个PCIe 设备中,可能含有多个Capability 结构,这些寄存器组成一个链表,Next Capability Pointer存放下一个PCI capbility的地址偏移。
Interrupt Pin: PCI设备中断引脚,支持INTX A/B/C/D四个中断引脚。
Interrupt line: 表示当前PCI设备使用的中断号。
type0 独有的寄存器
CardBus CISpointer: 只读,可选,用于表明访问CIS(card info structure)的地址空间, 通常不会涉及。
Subsystem ID/ subsystem Vendor ID: 子系统和子厂商ID,可以结合Device ID和Vendor ID来组成完成的PCI设备标识。
Max_lat: 设备期望的最大延时,只读。
Min_Gbt: 设备期望的最小延时,只读。
type1 独有的寄存器
Primary Bus Number: 表示PCI设备挂在的PCI总线号。
Subordinate Bus Number: PCI桥可以管理其下的PCI总线子树。其中Subordinate Bus Number寄存器存放当前PCI子树中,编号最大的PCI总线号。
Secondary Bus Number: 存放当前PCI桥Secondary Bus使用的总线号,这个PCI总线号也是该PCI桥管理的PCI子树中编号最小的PCI总线号
Secondary Latency Timer: PCI桥下游的延时寄存器,和Latency Timer寄存器的含义相近
I/O base: 表示IO寻址的基地址, 低4bit只读,所以PCI设备默认IO寻址4K对齐,高4bit可写。
I/O limit: IO寻址的上限,高4bit可写,低4bit为全F,所以IO寻址上限是I/O limit地址 + 4K.
Secondary status: 保存PCI下游总线和设备的状态。
Memory Base: 表示memory寻址的基地址。
Memory Limit: 表示memroy寻址的上限,和IO limit类似。
Prefetchable Memory Base: 可预期内存的基地址
Prefetchable Memory Limit: 可预期内存寻址的上限。
Bridge Control Register:管理PCI桥的Secondary Bus, 可以控制 Secondary Bus的 Reset。
配置空间寄存器如何读写?
配置空间的访问分为两种方式,一种是IO访问,一种是内存映射访问。
IO访问
IO访问应该是Intel X86架构的独有产物了,简单可理解为一段存储空间,用户通过IN/OUT指令来访问。
比如这个:通过CF8 / CFC端口,用户可通过这组端口来对PCIE的前256个Byte进行访问,一个指定地址,一个指定数据。代码如下
/Access PCI Config Space in IO method/
Address = BIT31|((BUS & 0XFF)<< 16)|((DEV & 0x1F)<<11)|((Fun & 0x7) << 8);
IoWrite32(0xCF8, address); //将要读取的地址写入到CF8
Date32 = IoRead32(0xcfc); //从CFC端口读出address的数据
内存访问
PCIe配置空间的寄存器可以通过将其映射到系统内存地址空间的方式进行访问。通过内存映射,可以使用读写内存的指令来读取和写入配置空间的寄存器。
Enhanced Configuration Access Mechanism (ECAM)是访问PCIe配置空间的一种机制。是将PCIe的配置空间映射到MEM空间,使用MEM访问其配置空间的一种实现。
在内存方式中,需要根据设备的总线号、设备号和功能号计算出相应的内存地址。内存地址的计算公式为 Config Base Address + (Bus Number << 20) + (Device Number << 15) + (Function Number << 12) + offset,得到内存地址之后就可以直接读取到配置空间的寄存器值了
PCI capbility结构
PCIE Capability可以分为PCI兼容的capability 和PCIE extended capability两类,64字节到256字节是pci\pcie设备的capability结构,256到4096则为pcie的扩展空间,定义位于内核的include/uapi/linux/pci_regs.h文件