pcie&usb对比学习笔记第五章:系统配置空间及系统初始化至运行

您所在的位置:网站首页 ram读写周期 pcie&usb对比学习笔记第五章:系统配置空间及系统初始化至运行

pcie&usb对比学习笔记第五章:系统配置空间及系统初始化至运行

2023-04-15 02:44| 来源: 网络整理| 查看: 265

背景:

试想一下,公司让你在2023年1月1日开始负责A镇的物流运输。于是你修建了马路,购买了运输车辆,1月1日早晨8点,雇佣的快递员都上班了,此时,作为RC,你需要开始指挥整个运输事业了。

本系列和PCIE协议及相关文档的一个很大的不同点是,我想用最快速通俗的方式让您理解PCIE到底在干什么。按照普通的PCIE介绍文档的排序,第五章要介绍物理层PHY在干什么,或者链路层的状态机LTSSM,但是我们先假定这些功能都是完好的,即port和port之间可以正常通信了,我们本章关注更高层,更全局性的问题。

先看看我们现在有了什么:

一整套的物理拓扑结构,把主机,桥,和设备连接起来。一套数据包格式,让主机和设备能用统一格式互相发送数据及各种信息。路由方式,使得数据包能从主机发送到任意桥或者设备。

OK,对于拥有了这些组件的人,你迫切希望开始运输事业。那么,还缺少什么??我认为是更高的抽象层级的架构:

需要一套配置信息,让主机知道,目前接入了多少设备,设备是什么(电脑上有没有显卡,网卡等),各个设备需要什么(比如供电功率,占用几个中断),从而方便供电,分配中断,以及执行对应的驱动程序。这套信息也要是标准化的,不能不同的设备有不同的格式,那么主机读起来就太乱了。需要一套初始化流程,即上电之后,主机何时及如何知道某个PORT插了东西?主机知道了后如何知道具体什么设备插入了?如何分配地址空间(空间大小要让设备满足)?如何不断扩大树形结构(主机自己要知道,同时也要让SWITCH和device知道自己在结构中所处的位置)?如何满足设备的功耗等一系列配置,最终让这个设备正常运转起来?

好,我们慢慢来,先重温下概念:

device(endpoint)和function

之前我们说过,PCIE中一个device(EP)中有一个或多个function,如下图,连在bus3上的 device0就有2个function。

5.1 PCIE configuration space

重点:每个function,都有独立的一套PCIE configuration space。

这里的配置空间的意义,就是每个function的身份证+简历,其中部分项是device的function天生自带的,比如生日,籍贯;而部分项让是RC后天赋予的,比如现居地,职称。

每个function的配置空间,大小是4KB,分为2个部分,256byte(64DW)的PCI-Compatible space和3840KB(960DW) PCIE高级功能区。可以说前一个部分是基本功能,后一部分是PCIE加入的一些高级功能。下图中16DW+48DW为PCI-Compatible space,下面960DW为PCIE ehhanced space。

注意PCI Header的格式是统一的,但是下面的PCI capability reg sets和Express extended config space每个function可以不一样。这里我的记忆点就是,每个function就像一个独立的个人,有自己的简历,简历有统一的格式,前面一部分PCI Header是个人基本信息,后面一部分是项目经历,项目经历部分不同人不一样,有的人有1段,有的人有5段。

如果你设计了一个device芯片,这个芯片有N个function,那么芯片内部必然需要有N*4KB个寄存器(或者同等sram),用来实现配置空间。

我们之前介绍过,RC通过config TLP来读写配置空间,在这里补充下,只有RC才能这样,反过来,EP不能config RC或者其他EP。

我们之前还介绍过,config TLP的路由方式是ID路由,并且该TLP在从RC出来时时TYPE1的,一直到对应的Device才变成Type0的,下图很直观,这个TYPE1/TYPE0转换的存在意义,就理解因为老式PCI结构的原因吧,其实对于PCIE结构来说,已经没什么意义。

我们来看下,下图就是config read tlp的格式。可以看到最下方Bus numb/device numb/Function numb就是为了路由用的,而register number是为了配置具体的项,单位是byte,比如register number[7:0] = 16, 那么配置的项是第16byte(4DW),Base address0。

OK,知道了这个配置空间是什么,以及如何被RC配置的,我们下面深入下细节。因为很很多时候,如果你的工作是软件驱动相关,你面对的一个完成的EP,那么就需要通过读这个配置空间来了解他的相关信息。

5.1.1 详细介绍

下图是TYPE0的config space具体项,黑色部分是EP自己出厂时自带的。

我们一项项看。

先看Vendor ID,Device ID,Revision ID,Class Code,SubSystem Vendor ID,SubSystem ID。这六项合在一起,代表了这个EP及function到底是什么。

Vendor ID是厂商编号;

Device ID是function的标号;

Revision ID是版本号;

Class Code是功能分类,比如IDE mass storage controller;

SubSystem Vendor ID,进一步细分,不重要;

SubSystem ID,进一步细分,不重要;

再看header type:bit7代表device是单function还是多function,bit[6:0]代表是EP还是switch。

再看BIST register:代表build-in-self-test,这个function有没有自检模式,有的话,RC通过配置bit6开始自检,自检结果在[3:0]显示。

status register:顾名思义,代表了EP想要告诉RC的一些状态,比如bit4代表有pcie cap list扩展。

command register:代表了该EP的某些功能有没有被使能,比如IO使能代表可以接收IO TLP, BUS master使能代表EP能自己成为master,发出memory/IO request。

cache line size register:老的功能,现已不用

latency timer register:老的功能,现已不用

interrupt line register:将来讲中断会讲到,PCI的中断有4条线INTA/B/C/D#

interrupt pin register:将来讲中断会讲到,这是中断编号,和line register合起来,可以实现function发出中断后,RC能通过寄存器找到具体是哪个function发出的中断。

base address registers:上章提到,代表EP function被分配的pcie域空间

Min_Gnt、Max_Lat Register:老的功能,现已不用

Expansion Rom Base Address register:扩展驱动地址。这里大概介绍下,有的pcie设备需要在计算机boot阶段使用,而此时计算机的操作系统还没开始工作,所以无法加载设备的驱动等内容。怎么办呢? EP自带expansion rom,把驱动写在EP的rom里,RC读这个rom,就能获得驱动了。这个驱动的地址,就放在Expansion Rom Base Address register里,RC读这个地址不是全FFFF,代表有效,则可以通过BAR0+ERBAR,正式访问ROM。

capabilities point register:重要,capability功能的指针。之前说了,PCI header共64DW,目前我们先研究了前16DW,而后48DW是cap空间,再往后4KB是extended cap空间。48DW的cap空间干什么用的呢?比如power management的配置,又比如MSI中断的配置,空间使用如下图:

总之,RC读capabilities point register,就能找到上图的结构,分析上图的结构,能通过cap ID知道这个功能是什么,pointer to next cap知道下个功能的指针。RC读这些通过指针串成一串的链表,就能知道这个PCIE设备一些具体功能的信息。

CardBus CIS Point register:CardBus device的信息,什么样的pcie设备是CardBus我也不知道,用时再查。

5.2 PCIE系统初始化

好,现在我们看看整个PCIE系统初始化的进程,下图左是初始状态,而下图右是完成状态,系统已经完全了解所有的device和连接情况,并编号:

1.主机开机后,自然对PCIE的结构一无所知,它只知道自己RC的结构(如上图左,RC框里的内容主机是知道的,即有BUS0,和下面两个P2P桥,所以有两个downport)。

2.自然的,现在需要discover下面的结构,首先就是RC左边的downstream port,有没有连接东西,以及连接的是什么。那么怎么发现呢?通过RC发送给BUS1(咱们知道,如果RC左port上连了一个device,这个link的编号自然是BUS1)一个read config TLP,读该设备pci config space里的venderID+DeviceID这两项。

为什么读这两项呢?因为这是所有的EP生产商约定好的,比如上图是一个A公司的switch,这两项就为32’h3EA,那么RC读到后,就从操作系统库里查到,3EA代表一个A公司的switch,那么说明系统该处接了一个switch。如果该处什么也没接,比如上图BUS8,那么读到的是FFFF,这代表什么都没有。

3.OK,目前读到了BUS1上挂了个SWITCH,RC就会接着读该SWITCH的左port,因为枚举采用深度优先算法,所以暂不管右边的port,而是走左边的一条道走到底。故给BUS3发送read config TLP,就能读到BUS3上的Device0(右图坐下BUS4貌似是笔误,因该为BUS3)。

由于是device而非switch,故此路到此为止。

4.接下来继续访问BUS1 SWITCH的右边port,发现BUS4 Device0,由于是device而非switch,故此路到此为止。此时整个RC左边port下的port都被遍历完毕了,接着该走SWITCH的右port,即BUS5了。

5.上述过程重复,就能把BUS7,8,9也发现了。

6.RC自己会总结,BUS1 BUS5上挂2个switch;BUS0,BUS2,BUS6是RC和SWITCH内部的bus;BUS3,BUS4,BUS7,BUS8,BUS9是挂的device。在枚举过程中,会把各个bus的pri,sec,sub(这三项在PCI配置空间中)填好。比如BUS5的三项为5/6/9,代表自己上游是BUS5,下游是BUS6,以及下游最末端是BUS9,有了这三项就可以进行ID路由了。

7.自此,初始化完成,操作系统完全了解PCIE树的拓扑结构,以及每个节点的device具体类型,后续会通过config rd,config wr继续配置每一个节点,使整个系统正常工作。

5.2.1热插拔(选读)

既然讲了初始化,我们顺便讲下热插拔,即初始化完成后,RC已经知道了树形结构,此时我又插了一块PCIE网卡,RC识别,这里的机制是什么样的?

PCIE热插拔,特别是拔出被设计成no surprises模式,即你的卡拔出时,不能毫无征兆,上位机措手不及,系统混乱。如何实现呢?PCIE卡的PRSNT1# PRSNT2#触点在两端,且比较高,这样拔卡时,software就先知道拔卡,可以复位,断电等操作,而后才建立或者失去信号连接,下图两端你一看就懂:

PCI和PCIE的热插拔系统有2点不一样:1.因为PCIbus是一起连在pci bus线上的,所以需要每个slot 一套iso逻辑来隔离(和芯片低功耗的isolation一样的作用),PCIE不用;2.PCI的hot-plug controller是系统board上的一个整体,而PCIE的是每个port各有一个自己的controller。

插入PCIe设备的步骤:

两个插槽上的指示灯初始状态是:Attention Indicator(Yellow灯)-Off,Power Indicator(Green灯)-Off

1.用户安装PCIe设备,并且压下Attention按钮或者在软件界面告知系统安装PCIe设备的信息。主要通过发送中断的形式告知系统热插拔信息;

2.热插拔软件通过状态寄存器来验证热插拔的请求;

3.软件命令Power指示灯开始闪烁;

4.软件命令Hot-Plug Controller将Slot打开,让Slot处于ON状态;

5.上电后,Power指示灯处于ON状态;

6.系统为PCIe设备寻找对应的驱动,并将驱动放入内存;

7.系统调用驱动完成对PCIe设备的初始化。

移除PCIe设备的步骤是:

初始状态是:Attention Indicator(Yellow灯)-Off,Power Indicator(Green灯)-On

1.用户通过压下Attention按钮或者在软件界面告知系统移除PCIe设备的消息。当按下Attention按钮之后,Hot-Plug Controller检查到这个讯息之后,会发送中断给Root Complex。之后,Hot-Plug Service会调用Hot-Plug System Driver去读取slot的状态信息并且侦测到Attention按钮的状态;

2.Hot-Plug Service调用Hot-Plug System Driver让Power指示灯开始闪烁5s并通过状态寄存器来验证热插拔的请求;

3.Hot-Plug Service命令Device Driver停用PCIe设备;

4.软件通过Link Control Register关闭PCIe链路;

5.软件命令Hot-Plug Controller关闭slot;

6.断电后,Power指示灯处于OFF状态;

7.系统为PCIe设备寻找对应的驱动,并将驱动放入内存;

8.系统取消对Slot的配置资源。

好,我们接下来分析下USB的配置空间及系统的初始化

5.3 USB device的配置内容结构:descriptors

USB里如何对一个DEVICE进行描述呢?

我们知道,PCIE通过每个function对应一个PCIE CONFIG space,来描述这个function到底是什么。而USB里,通过descriptors(描述符)来描述deivice的特征和行为。如下图:

注意,这个树形结构仅仅是一个device包含的descriptors,不是整个USB树形结构所有的device和hub的结构。

如上图,这种结构的意思就是,device desc里保存了这个device的相关信息;而6个EP desc代表这个device包含6个EP,每个EP的信息。

当然,上面这个树形结构里部分desc是optional的,有的device存在,有的没有。

那么,Host如何获得这些desc呢?通过control transfer中的一种GetDescriptor即可,如下:

不同的desc有不同的编号:

我们以想获得device descriptor举例,按上表Host应该发送type=1的GetDescriptor request:

而device回复这个control transfer,其data部分如下,包括了device desc的相关信息:

可以看到device desc里的很多信息比如vendorID productID等,正好也是PCIE协议里配置空间里的项,他们的作用是相似的。

OK,关于desc我不想把树形图里的十几种都一一详细解析,上面讲了device desc,剩余的我们大致看一下:

BOS desc:binary object store,包含了也是一些device级别的信息,比如device协议支持的速度和低功耗部分信息。

Configuration desc:接口数量(numb of interfaces),及host配置值(config value)。什么意思能?一个device,有N个EP,会被分成几个interface。比如说,一个摄像头,有N个EP,其中p个组合在一起为音频接口,而另外q个组合在一起称为视频接口,所以这个device的config desc的接口数量这项的值为2;而host可以配置config value,如果=1,device就知道host希望自己是全功能模式,如果=2,就是host希望自己是仅音频模式,这个值是驱动程序和device的设计者约定的。

interface desc:对应某个interface的的信息,它包含几个EP,interface的类型ID等等,Host通过取interface desc能够知道这个device是否需要鼠标驱动等信息。

EP desc:每一个EP的信息,包括type,maxpacketsize等。

string desc:以unicode characters的形式来显示字符信息,比如之前提到的device desc里就有项目指向这个desc,作为附加说明,这里的信息是给人来看的。

OK,这一块其实系统驱动和device驱动的人对细节比较在意,具体描述符的组织其实我也不太了解,下面举例一个键盘Keyboard的完整描述符信息,大家看看就行:

5.4 USB系统的初始化

在这里我们探讨一下,USB device如何被host发现并配置的。

分为下面的步骤:

Device Detection and Reporting

2.给device分配地址

3.发现device的属性(通过读取device desc)

4.发现给使用者的信息(通过读取string desc)

5.配置device (通过 SetConfiguration Request)

6.启动对应的软件驱动

7.驱动初始化device

我们展开来讲:

5.4.1 Device Detection and Reporting

我们假设现在系统是一台电脑,电脑上插了个hub。此时插入一个U盘到这个hub上,那么U盘是如何被发现的以及初始化的呢?

首先hub是给要插入U盘的这个port供电的,即VBUS电压有效(如无效这个port是disabled状态,插了U盘也没用)。

此时这个port处于inactive状态,在这个状态下,以12ms为周期检测port的电容充放电时间。为什么呢?因为一旦U盘插入了,由于接了负载,所以充放电变慢了,以此可以推断port插入了device。

OK,此时hub知道了有东西插入了(但不知道是U盘),hub会通过中断告诉host,要处理这个事情。host通过GetPortStatus这个control xfer,来读hub这个port此时的状态,至此,第一步device检测完成。

5.4.2 地址分配

我们前一章路由讲过,usb device也有地址,当然比pcie的bar分配要简单,这相当于给个门牌号,host通过SetAddress配置下即可,当然host自己是清楚系统中有几个device,各自的地址是多少。这步不起眼,但是是必须的。

5.4.3 发现device属性

5.3节已经介绍过了device通过大量的descriptors来表示这个device的属性信息。所以host通过GetDescriptor来获得所有的这些desc,从而判断是什么device,该调用什么驱动。

5.4.4 发现给使用者信息

其实就是读string desc,string desc是给人读的信息,这步optional不太重要。

5.4.5 配置device

5.4.3+5.4.4表示host知道了插入的是什么,以及一些有用的相关信息,那么host根据自己的情况(比如带宽,供电),开始配置device进入什么状态,比如摄像头功能打开还是关闭的。这步是通过SetConfiguration来完成。

5.4.6 启动软件驱动,软件驱动进一步初始化device

这里和USB协议已经无关了,操作系统的底层驱动开始做一些事情。

到这里你可能会发现,5.4介绍USB的初始化,但是并没有PCIE初始化那些enumerate整个树状结构的过程,而是仅仅类似对一个device的读取和配置。这是因为,虽然同样是树状结构,但是pcie的每个节点有mem map 范围和路由ID,所以需要一套流程,连着switch也要配置对应的mem map和路由信息;

而USB每个树状结构,只需要简单的在route string里表示自己的位置就行了,并且USB系统初始化后,可以认为只有host,别的没有,然后插上一个hub,就记录下位置,再插下级hub,再记录位置,再插device,就记录device的位置,总之是比较简单的,不用那么复杂。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3