PCIE详细介绍

原文链接:https://www.cnblogs.com/szhb-5251/p/11619294.html

【PCIE-1】—Pcie基本概念普及(扫盲篇–巨适合新手)

PCIE由早期得PCI扩展衍生而来并且对兼容PCI,两者得主要区别在于并行到串行得切换,且速率更快。目前主板上越来越多得设备都挂载到PCI总线下面,甚至部分硬盘也会挂载PCI总线下面,可见PCIE得应用越来越广。PCIE设计的知识面比较广,无论是在BIOS下还是系统下都显得尤为重要。本章主要介绍PCIE的基本概念及基本知识扫盲,初次学习的同学必看。

知识点扫盲:

  1. 通常会看到x1,x2,x4,x8,x16,x32,怎么理解?
      x1表示1个Lan,PCIE总线走差分信号,1个Lan4条线可接收也可发送。同理,x2表示2个Lan,以此类推, Lan数越多,数据传输的也越快。也可以将多个通道组合成x1,x2,x4,x12,x16,x32,以提高插槽的可用带宽
  2. 一般情况下:
      PCI-Express x1/x2/x4,由南桥提供支持
      PCI-Express x8/x16,由北桥提供支持

x1/x2主要是用来扩展声卡、网卡等低速设备,用于淘汰PCI插槽
  x4是用来扩展磁盘阵列卡等中速设备,用于淘汰PCI-X插槽
  x8/x16是用来扩展显卡等告诉设备,用于淘汰AGP插槽

  1. 关于南北桥
      北桥多挂载一些高速设备,如显卡,内存。 南桥多挂载一些低速设备,如LPC接口,网卡等
      由于北桥芯片多被集成在CPU内部,南桥一看自己隔空相望的兄弟不在了,也就不好再叫个南桥,加之Intel处理器各模块集成度越来越高,因此PCH诞生了。PCH的主要还是作为南桥的功能,包括ICHICH(I/O controller hub输入输出控制器中心)负责链接PCI总线,IDE设备,I/O设备等。

注: PCH也是有一颗单独的芯片上存在于主板上,该芯片于CPU之间通过DMI接口相连,因此多数位于南桥上的接口如LPC,部分PCIE等端口都会在PCH的芯片上暴露出来,而不会在CPU的处理器上暴漏。 目前部分Intel处理器将PCH亦集成在CPU的SOC上,集成度更高,所有的引脚都会在CPU的SOC上暴露。(以前楼主一直对PCH不太理解,参考手册别人说,这是PCH部分,那是CPU 部分,搞得有点头晕,这里建议大家就简单理解为两颗芯片即可)

  1. 关于PCIE通信

前面介绍PCIE是通过一组差分信号对也就是一个Lan为基本通信单位来传输数据。一条收一条发,为半双工通信模式,亦可设置为全双工通信模式!

【PCIE-2】—PCIE配置空间及访问方式简介

对新手来说,第一步了解PCIE的相关基本概念,第二步了解PCIE配置空间,第三步深入研究PCIE设备枚举方式。本章主要总结第二步的PCIE配置空间

按照国际惯例,先提问题:

  1. 什么是PCIE的配置空间?

  2. PCIE设备的配置空间有多大? PCI和PCIE的配置空间有何区别与联系?

  3. 如何访问PCIE设备的配置空间?

  4. 有几种类型,都包含什么内容?

带着上述问题,来进行该部分的总结:

什么是PCIE的配置空间?

每个PCIE设备都有自己的独立的一段配置空间,该部分空间是这个设备的(可能是一段e2prom),系统会给这个设备分配一段内存空间,CPU访问这段内存空间即访问对此设备的配置空间。设备在出厂时,配置空间是有默认初始值的。

PCIE设备的配置空间有多大? PCI和PCIE的配置空间有何区别联系?

早期的PCI时期,系统为每个PCI设备分配的内存大小仅有256个Bytes。到后来的PCIE时期,随着设备性能增强,PCIE设备的配置空间扩展至4K个Bytes。在这里需要注意:

PCIE一共支持256条Bus,32个Dev,8个Fun。因此在满负载的情况下,共需内存大小 = 4k * 256 328 = 256K Bytes = 256M,这个256M的内存空间是为PCIE设备准备的空间系统不可用,这也是你的内存条实际可用的总是会小于标称的主要原因之一。

PCIE设备发展向前兼容PCI,每个设备的配置空间的前256个Byte是PCI空间,后(4k-256)个Byte的空间是PCIE扩展空间,这是二者的主要区别,另外一个区别就要引出下面的一个问题:

PCI/PCIE设备配置空间的访问方式----IO访问 & 内存访问

X86系统中,对PCIE设备配置空间的地址映射一般有两种方式:内存映射和IO映射。因此开发者也可以通过内存访问或者IO访问来访问其配置空间

PCIE设备的访问离不开其Bus,Dev,Fun的编号方式,如下图寄存器所示,Bit[23:16]用来存放Bus号,共8Bit,因此解释了上述表述为何一共有256条Bus,Bit[15:11]存放Dev,共5bit可存32个Dev,Bit[10:8]存放Bus,共3Bit可存8个Fun。这也就也是了为何上述PCIE设备数一共是256个Bus,32个Dev和8个Fun

无论是采用IO还是内存的方式来访问配置空间,都离不开上面的图,下面具体介绍:

  1. IO访问

IO应该是Intel X86架构的独有产物了,简单可理解为一段存储空间,用户通过IN/OUT指令来访问(内存的话,需要用MOVE指令来进行访问),部分设备可以映射到IO空间中,开发者通过IO端口访问这个设备,比如现在介绍的这个:通过CF8 / CFC端口。用户可通过这组端口来对PCIE的前256个Byte进行访问,一个指定地址,一个指定数据。代码如下:

1 /Access PCI Config Space in IO method/
2 Address = BIT31|((BUS & 0XFF)<< 16)|((DEV & 0x1F)<<11)|((Fun & 0x7) << 8);
3 IoWrite32(0xCF8, address); //将要读取的地址写入到CF8
4 Date32 = IoRead32(0xcfc); //从CFC端口读出address的数据
  注: IO访问仅能读取到前256个Byte,256Byte后的空间需要用内存访问

  1. 内存访问

这个其实与IO访问大同小异,配置空间全部映射到内存中,用户在确定设备地址后,即可通过内存读写的方式进行访问,如下代码:

1 /Write date/
2 MmioWrite32(PcieBaseAdd + Bus<<16 + Dev<<11 + Fun<<8 + offset, date); //PcieBaseAdd为PCIE在内存中的基地址
3
4 /Read date/
5 Value = MmioRead32(PcieBaseAdd + Bus<<16 + Dev<<11 + Fun<<8 + offset);
PCIE配置空间集中类型,都包含什么内容

配置空间主要有两种,开发者也是搞清楚这两种即可,一是Type0:设备空间 二是Type1: Bridge空间

桥设备空间如下图所示:下面介绍其中主要内容以及作用:(端点设备空间布局与Bridge空间类似,会简单一些,没有一堆Bus Num设备寄存器,CPU一般通过判断Header确定该设备是什么设备)

DID&VID: 设备及厂商ID,出场固定且每个设备都不应,枚举设备时通常判断此VID来判断设备是否存在。

Class Code: 该寄存器是只读的,通常用来表示该设备类型。用法如下:

ClassClde Register共3个byte,位于配置空间的[0A:08],分别表示BaseClass, Sub-Class, InterFace

举个简单的例子–使用RW工具查看笔者自己笔记本的Pcie Memory设备的Config空间,如下图:

可以看到该设备的ClassCode Register的值是0x058000,对照PCIE Spec查看,可以看到:

Add[0A] = 05

Add[09] = 80

Add[08] = 00

05表明该设备是一个Memory的Controller,具体内存子类是其他类型,不属于RAM&Flash,如下图:

而Add[08]表示该设备不同的接口,含有多种接口的才会表示出来,如下显示设备的会含有不同的Interface:

HeaderType: 标明Config空间的类型,同时也标明了Config空间的layout,共有三种:00H–普通端点设备,01H–Bridge设备,02H–CardBus bridges(此外,若该寄存器的Bit7为0.则表明该设备是一个单功能设备 )

BAR0 & BAR1: 设备空间的基地址

Subordinate Bus Number: 从属Bus号,即该Bus下最大的Bus号。

Secondary Bus Number: 该Bridge下接的Bus号

Primary Bus Number: 该Bridge上接的Bus号

Memory Limit: 此设备所分配的内存大小?

Memroy Base: 此设备在内从中分配的基地址?

【PCIE-3】—PCIE设备的枚举扫描(经典好文)

前面两个小节大致总结了下PCIE的基本知识,算是扫盲篇吧。本文主要总结PCIE设备的枚举扫描过程,此部分才是PCIE模块的重点,无论是在BIOS下还是系统驱动下都会用到。

按照国际惯例,先列问题:

1. 系统如何判断PCIE设备是否在位?

2. 设备中的配置空间的数据一开始就有嘛?谁写的?

3. Bus号,Dev号,和Fun号与硬件有关系嘛?P

4. Bridge和Device的区别?

5. Device和Function的区别?

6. 枚举的流程是怎么样的?

系统如何判断PCIE设备是否在位

BIOS代码在枚举设备的时候,会去读每个设备的VID,如果读到的是不是FFFF,则表示此位置有设备存在,若为FFFF,则表示设备不存在。DID&VID是出厂时就固定在PCIE设备配置空间中的数据,表示每个不同的设备,同理,我们在BIOS中也可通过判断这个ID值来寻找指定的PCIE设备。

设备中的配置空间的数据一开始就有嘛?谁写的?

每个设备在出厂时,其配置空间中的值都有一些default值,枚举该设备时为每个设备分配BDS号和内存资源时,会再写入部分值。

Bus号,Dev号,和Fun号与硬件有关系嘛?硬件链接与BDS号的分配是否有关?

这个问题很关键,我想应该大部分的同学都会弄得不是很清楚,笔者一直以为BDS号是在枚举过程中全部由软件分配的,但实际应该不是这样的。与多个同事讨论后,基本断定:Dev和Fun号应该是和硬件设计有关系,也就是硬件就已经固定,软件的枚举过程是更多的是在分配Bus号。为什么这么说呢?这里要着重讲解下:

PCI是总线结构,而PCIE已经是点对点机构,这个点对点结构很重要,待会重点讲到。首先先来看下一个典型的Pcie系统框图如下:

从CPU出来,有一个Root Compex(RC),从PCIE设备断端来看的,我更倾向于简单的把这个RC理解为一个HostBridge,这样可能大家都会理解的更加清楚。OK,从RC出来,最典型也是最简单的结构就是一个Root Port和一个Endpoint设备直接组成一个点对点设备,重点来了哈,这里面我们仅仅挂载了一个端点设备,但当一个root port仅和一个EndPoint设备相连时,该EndPoint设备就需要一条Bus,我和同事讨论了下,大致原因是从CPU出来的每个port都是一个Bridge,有一个Bridge就要对应一条Bus,即使该Bus下仅有一个Dev,也需要给他单独分配一个Bus号。

上面介绍了一个Root Port和一个EndPont设备相连时的情况,这是最典型的PCIE点对点结构,现在讨论一个Port下挂载多个设备时要怎么做? 这种情况下一般就需要Switch了,Switch物理上一般是一个芯片,我更倾向于把他理解为一个分线器,RootPort对应一条Bus,该Bus由于Switch的存在可以挂载多个dev,也就是对应多个Dev的情况。

那么问题中所说的每个设备的Dev和Fun是由硬件固定的是怎么回事呢?那加入这两个固定,对于到软件枚举又如何对应呢?情况大致是这样:

a. Dev和Fun硬件固定,这个是由硬件决定,为何这样定,后续我做实验后贴数据上来,现在我们就这样认为;

b. 上面已经介绍了PCIE点对点结构,从一个Port出来即使仅有一个设备,也需要给该设备重新分配一条Bus。那么假设我插入了两个设备,在没有挂接到switch上时,这两个设备正如上面所说,组成了root port - endpoint dev的两个设备对,每个设备在枚举时,都会被重新分配一条Bus号,这种情况不会冲突。

c. 假如这两个设备接在了同一个Switch上,原本应该是Switch属于某个Bus下一个分线器,分别挂接来不同的设备,亦有不同的Dev和Fun。那么在这种情况下,如果Dev和Fun一致,枚举软件自动会把这Switch的两个port再次当成一个与Root Port类似的port。每个Port也可当作一个Bridge来使用,由于两个设备Dev和Fun一样,所以会再给这两个设备分配 两个新的Bus号,以表示区别,其他的设备则按原计划枚举扫描。大概是这样的过程。

这个说法不知道会不会颠覆部分人的认识,后续我会找个实际的PCIE设备插入不同设备来进行验证,但就目前查阅的资料来看,应该是此过程!

Bridge和Device的区别?

PCIE设备树的实现,离不开Bridge,我个人更倾向于简单一点去看带着Bridge和Device,或许可以这样说:Bridge是一条Bus的管理者,当你看到一个Bridge的时候,也会对应的有一条Bus。那Device就简单的多了,简单的一个终端设备。不过目前在我看来Bridge某种意义上也可以算的上一种Device

因为在枚举扫描的时候,接下来扫到的这个是什么?你假设它为Bus1,Dev0,Fun0,然后发现有设备,去读了配置空间的Header和ClassCode后才知道这是一个Bridge还是device,但实际上你已经假设它为一个Device了,不是嘛?哈哈

这里对桥和设备的判断是通过HeaderType和ClassCode来判断的,如下:

待添加:

Device和Function的区别?

这个问题困扰了笔者很久的时间,其实真正弄懂了以后发现,可以不用钻的太深,最大的疑惑是: Dev到底对应的是不是一个设备,Fun是不是这个设备的具体的一个功能?请教了好多人,每个人给的回复都不一样。其实笔者后来总结部分情况下是这样的,对于你插入的某个设备,其Function号对应的就是它不同的功能。

枚举的流程是怎么样的?

又是一长串的知识扫盲,以上问题都是困扰了笔者许久的问题,因此单独列出来,作下说明,希望能解答和我有同样疑惑的你们。接下来就要进入正式的枚举过程了,如下图是枚举之后的两个图,希望各位同学对着这两个图,来看这个过程,你就会知道枚举到底是怎么回事了?

1. 对CPU来说,最开始仅仅知道Bus0的存在,Bus0下面都有什么设备,PCIE树是怎么样的一概不知。因此首先从Bus0,Dev0(桥A)开始,先去读Dev0中Fun0的DID&VID(一定是从Fun0开始),看其是否返回0,如果不为0则表示设备存在,继续下一步。若返回FFFF,则Dev0中没有Fun0(任何设备的第一种功能一定是0),因此该设备不存在,继续探查Bus0,Dev1,Fun0

2. Bus0,Dev0,Fun0存在,读其Header寄存器的值为“1”,则表示这是一个PCI To PCI Bridge(桥B),每一个bridge对应一个Bus,那么接下来就开始填写这个Dev0,Fun0的配置空间,将其总线号寄存器设置如下:

Primary Bus Number = 0; 以下简称为PBN

Secondary Bus Nymber = 1; 以下简称为SBN

Subordinate Bus Number = 1; 以下简称为SuBN

至此,桥B知道了他管理的下游的一条Bus,编号为1,下游最远(也就是Bus号最大的那个Bus是1)

3. 更新HostBridge的SuBN = 1

4. PCIE设备扫描遵循深度优先法则,因此在进行Bus0其他Dev扫描之前,必须首先扫面Bus1

5. 软件读取Bus1,Dev0,Fun0的DID&VID,若返回不为FFFF,则该设备存在。在此查看Header寄存器值为1,表名Bus1,Dev0,Fun0依旧是一个PCI to PCI Bridge,。且Bit7是0.说明桥C是单功能设备

6. 至此开始设置桥C的总线号寄存器

Primary Bus Number = 1;

Secondary Bus Nymber = 2;

Subordinate Bus Number = 2;

然后再更新桥A,桥B的 SuBN = 2

7. 继续延续深度优先法则,开始扫描桥C下管理的Bus2总线,首先读取Dev0,Fun0的DID&VID,会发现结果与之前一直,Bus2,Dev0,Fun0设备存在,其Header寄存器值为1,表明又是一个PCI to PCI Bridge(桥D),bit7为0,说明桥D也是单功能设备。

8. 设置桥D的总线号寄存器

Primary Bus Number = 2;

Secondary Bus Nymber = 3;

Subordinate Bus Number = 3;

然后再更新桥A,桥B,桥C的 SuBN = 3

9. 继续深度优先法则,扫描桥D下的Dev0,Fun0, 发现DID&VID存在,则表示Bus3,Dev0,Fun0存在,查看其Header寄存器的值为0,表名是一台端点设备,不是在是Bridge,且Bit7是一台多功能,这就对应到某个具体设备的多个功能了,Bridge的话就仅有一个功能–桥接。

10. 然后接着扫描Bus3, Dev0, Fun1-7,会发现仅有Fun1存在。

至此基于深度扫描法则的一条支路扫描完毕,其实到这个地方大家应该就能发现,深度扫描的意思大概是什么了,简而言之就是只要有Bridge就往下一直走,走到最后不是Bridge的那个点,PCIE设备树的结构也是在这样的基础上完成的。

11. Bus3扫面完毕后,枚举软件返回到上层Bus,也就是Bus2上的其他设备。之前已经扫描国Bus2 Dev0,Fun0,并且属于这个分支的都已经扫描完毕,接下来要扫描Bus2,Dev1,Fun0. 同样DID&VID存在,且Heade寄存器表明该设备是一个Bridge设备(桥E)。

12. 设置桥E的总线号寄存器

Primary Bus Number = 2;

Secondary Bus Nymber = 4;

Subordinate Bus Number = 4;

然后再更新桥A,桥B SuBN = 4

这个地方要注意了,桥E是挂载Bus2下载设备,因此PBN = 2没有问题,但是这个SBN = 4,SuBN = 4相比大家应该也不会有任何问题吧,截止到桥E(一个桥代表有一个Bus,编号分到Bus4),该分支下最远的Bus应该就是到Bus4,所以这样设置,但是再更新上游桥的SuBN就已经没有桥C的了,这是为什么呢? — 因为桥C和E是不同的支路。而每次更新SuBN,我们仅仅更新同一条支路上的所有Bridge上的SuBN的值。

13. Bus4(桥E)也分配好了,接下来扫描Bus4下的设备,首先就是Dev0,Fun0,其Header寄存器值为0表示是一台端点设备,bit7为0表示一台单功能设备,OK,已经到头,且此Dev0没有更多Fun,此条支路到此结束。

其他的支路扫描与上述过程类似,在此不再赘述。截至此,基本描述完PCIE设备的枚举过程,过程还是比较简单的,就是要结合很多硬件设计的知识,以及其这样设计的初衷和原理,对此的了解会更加深刻一些!

【PCIE-4】—PCIE中部分概念或问题总结(很基础很重要)

前面三小节,介绍了PCIE的基本知识和概念,以及扫描流程。在不求甚解的情况下,我想各位小伙伴应该对PCIE有了个宏观的认识,OK,那么本章我们在之前的基础上,再单独把一些概念和更深层次的问题摘出来具体讨论。

首先依旧是国际惯例,先列问题:

1. PCIE的各个模块中,经常提到Bridge/Host Bridge,Root Complex, Root port以及一些其他常用的部件概念要怎么理解?

2. PCI总线模型和PCIE是点对点模型,要怎么理解?

3. EndPint是否可以直接访问另外一个EndPoint

  1. Bridge/Host Bridge,Root Complex, Root port这些要怎么理解(以下解释来源于PCIE Spec)

Host bridge的概念:Root Complex中用来链接一个主CPU或多个CPU和一个层次结构的一个部分。英文原意如下:

Port 的概念:

1.逻辑上: 位于部件和一个PCIE链路之间的接口。 2. 物理上: 位于同一个芯片上用来定义一个链路的一组发射器和接收器。 原意如下:

Add Receiver&Reveiver Port

Root Port的概念:一个位于Root Complex上通过相关联的虚拟PCI-PCI Bridge映射一个层次结构整体部分的的PCIE Port,

Root Complex的概念: 一个的系统元素,包含一个Host Bridge, 0个或多个集成EndPoints的Root Complex, 0个或多个Root Complex时间收集器,0个或多个Root Ports

Add Root complex Componen

Switch的概念:一个定义好的用来连接两个或多个Ports且允许数据包在不同Ports之间被路由转发的一个系统元素。通过配置软件,一个switch也被配置为一组虚拟PCI-to-PCI Bridges的集合

Link的概念:两个Ports和他们之间所连接Lanes的集合。一个Link是一个双工通信通道在两个部件之间。

Lane的概念:一组不同的信号对,一对用来传送,一堆用来接收。由于PCIE使用差分信号传输,一条lane四条线,两条线组成一对,供发送。另外两条接收!

  1. PCI总线模型和PCIE是点对点模型,要怎么理解?

PCI总线模型: 在传统的PCI总线模型中,一个设备通过在Bus上判断DEVSEL(设备选择)来认领一个请求。如果在一段时钟周期后没有设备认领一个请求,这个请求就被放弃。

PCIE点对点模型:PCI是一种点对点的传输模型,不像PCI总线那样,在总线上有平等认领请求的机制。所有的传送总是由一个Device发给Link上的另外一个Device。所以,对于所有接收方来说,接收方将会直接判断这个请请求是否要被认领。

  1. EndPint是否可以直接访问另外一个EndPoint

在PCIE这种点对点的模型中,设备之间之间的互联访问是可以的。

情况一:不需要CPU参与

最典型的应用就是在一个带有DMA功能的Switch下,挂载两个EP,CPU需要首先配置DMA控制器,包括设置一些源地址,目标地址,传输数据以及数据量。然后每个设备发起DMA传输的时候,会直接透过Switch中的DMA控制器,发数据到另外一个设备,这个过程不需要CPU干预

情况二:CPU参与

这个过程就相对来说简单了,CPU从一个PCIE设备中读取出要发送的数据,然后直接发送给指定的目的PCIE设备节点即可。

你可能感兴趣的:(Linux,BMC,PCIE)