本部分主要目的是host在识别枚举PCIe设备之前,设备与主机在PCIe链路上都发生了什么事情,,主要流程为上电后两侧根据PCIe总线协议进入LTSSM流程,主要分为以下几个方面去介绍:
PCIe总线的的接收端链路上没有时钟,因此获取时钟的办法是通过接收到发送端发过来的报文信息(带有时钟信息)来获取时钟信息,将此过程称之为bit lock,同理symbol lock表示PCIe链路上获取开始训练的标记符COM字符的过程。
PCIe总线在硬件训练的过程中主要使用这几个序列:TS1、TS2,这两个序列主要作用是在LTSSM状态机之间来回跳转。FTS序列协助PCIe的链路获取bit lock和symbol lock。SKIP序列负责处理各个lane上面的skew,使其保持一致,具体技术细节可参考elastic buffer技术。整个训练过程pcie链路使用默认gen1速率进行传输,LTSSM状态机精简流程如下:
detect <------->polling------config------L0状态(主机可以枚举到device侧设备)
![LTSSM流程图](https://img-blog.csdnimg.cn/20201025140128398.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI0NzIyODkz,size_16,color_FFFFFF,t_70#pic_center)
此部分主要的作用是用来确认PCIe链路上可以正常工作的lane资源
detect.quiet<----->detect.active------>polling
首先上电后PCIe两端设备同时进入detect.quiet状态,首先host先将linkup 以及upconfig capblity 置0,同时PCIe链路处于静默状态,当其中一个或多个lane退出静默状态,或者经过12ms后,进入detect active状态。此时host向对端“未经过配置的lane”发送receive Detect 序列(通过DC共模电压来识别对方是否存在,对应的lane是否正常工作)。若没有一个存在则退回Detect.quiet状态重新进行detect流程。否则经过12ms后再次发送receive Detect序列来确认与上次正常工作的lane数目是否一致。若不一致则退回Detect.quiet状态重新进行detect流程。若一致则进入下一个状态polling状态
该状态主要功能为获取bit/symbol lock 以及同步链路两端使其进入下一个config状态。 有基本有一下三个子状态机组成,其实还有一个polling.compliance状态机负责对pcie链路进行检测是否存在故障
polling.active----->polling.config------>exit to config状态
进入polling.active 状态后首先PCIe两端的TX会向对端发送1024个TS1序列,用于获取bit/symbol lock,由于pcie两端设备进入polling.active状态的时机可能不同步因此只要满足一下几种情况就能进入polling.config状态
1,同时RX会接收8个TS1序列(对端通过loopback传过来),或者TS2序列(对端先进入polling.config状态,从而生成TS2序列),
2,如果没有接收到则经过20ms判断RX是否接收8个TS1序列,或者从进入polling.active状态时有至少一个lane是可以正常工作的。
满足以上条件则进入polling.config状态。否则进入polling.compliance状态对链路进行修复,修复成功重新进入polling.active,修复不成功退回detect状态。
进入polling.active状态后,首先设置link control 2寄存器的transmit margin为0, 其次向对端发送8个TS2序列表示已经成功进入polling.config状态。最后要收到8个TS2序列(一共需要收到16个TS2序列),若在48ms之内完成以上操作则进入config状态,否则退回到detect状态重新训练。
该功能是pcie link 训练中最重要的状态,主要的作用为完成pcie链路的主要配置工作主要包括,link number 和 lane number,以及对各个lane通过设置FTS来进行deskew。然后进入L0状态使PCIe链路正常工作 主要有以下几个子状态组成分别为:
cfg.linkwidth.start-----> cfg.linkwidth.accept-----> cfg.linknum.start <----->cfg.linknum.accept---->cfg.complete---->cfg.idle----->L0
**1、**cfg.linkwidth.start和cfg.linkwidth.accept 主要的作用是确定linknum(通过互相发送TS1来确定PCIe下游端口的linknum拓扑结构)。
**2、**cfg.linknum.start和cfg.linknum.accept 主要的作用是确定lanenum 方法同上。
**3,**cfg.complete 状态主要是确定完link/lane num后,再通过互发TS2序列来同步pcie链路两端使其同步进入cfg.idle状态 另一个作用是通过TS2序列来确定设置多少个FTS,来消除lane之间的skew。
**4,**cfg.idle 该状态主要为pcie两端会向对端发送16个idle序列,同时接受端收到16个idle序列后,将自己的link_up寄存器设置为1,同时pcie链路的状态有DL-inactive转变为DL_init,进入L0状态,PCIe链路可以正常工作。
该状态为PCIe链路正常工作的状态,host可以访问device的配置空间以及与之进行数据交互。
只有出现以下几个情况,L0才会进入recovery状态:
1、PCIe需要更改链路速率
pcie设备中存在两个状态位,dircted_speed_change == 1表示pcie设备希望更改传输速率,changed_speed_recovery1,表示pcie链路更改速率完成。软件可以将dircted_speed_change == 1同时 changed_speed_recovery0 触发设备进入recovery状态,注意pcie 链路两边需要同时进行该操作。
2、PCIe需要更改链路宽度
3、已经配置完成的lane又重新受到TS1或者TS2序列
4,、发现对端进入idle状态(只有当对端进入idle是没有发送EIO序列,认为pcie链路出了故障)
该状态比较复杂,主要是L0,可以进入该状态, L0s, L1等低功耗状态也通过此状态恢复到L0状态(L0s可以直接回到L0状态,只有在切回L0状态时不能重新获取bit/symbol lock时才进过recovery状态), 该状态一共分为以下几个子状态:recovery.rcvlock、recovery.speed、recovery.rcvcfg、recovery.idle
1,recovery.rcvlock:该状态重新获取bit/symbol lock 并处理lane之间的skew。
比如,switch 与 EP两端都处于L0 状态,EP想改变速率,
**1)**则软件将dircted_speed_change 置1,同时将changed_speed_recovery 置0,进入recovery.rcvlock状态,同时向switch发送TS1 序列(该序列中的speed change 位为1),
**2)**当switch接收到TS1时直接进入recovery.rcvlock状态并向对端发送若干TS1序列(此时还没有检查接收TS1的speed change状态位,所以发送的TS1序列,speed change 仍然为0),当switch收到8个连续的TS1(speed change 位为1),将改变switch本地的dircted_speed_change 置1,此时再向EP发送若干TS1序列(speed change 为1)。
**3)**当EP设备收到8个 TS1序列中speed change 状态和EP本地dircted_speed_change状态一样,则进入recovery.rcvcfg状态。并向switch发送TS2序列(其speed change 也为1).
**4)**当switch 接收到8个TS2序列中speed change 状态和switch本地dircted_speed_change状态一样。则进入recovery.rcvcfg状态。同时向EP发送TS2 序列。
2,recovery.rcvcfg switch和ep 根据TS2序列中的speed change 状态位来决定进入下个状态机:
**1)**当TS2序列中speed change状态位1 跳转到recovery.rcvspeed状态,同时向对端发送32个TS2序列
**2)**当TS2序列中speed change状态位0 跳转到recovery.rcvidle状态,同时向对端发送16个TS2序列
3,recovery.rcvspeed 状态,进入该状态后根据TS2序列中的速率,向对方发出不同的EIO序列,同时两端进入electrical idle状态(TX和RX都进入idle状态)。 pcie两端都进入electrical idle 状态后,需要判断pcie链路两端是否成功完成速率协商,等待800ns ~ 1ms 后判端 successful_speed_negotiation是否为1,然后将本地dircted_speed_change 置位0,跳转到recovery.rcvlock用新的速率重新获取bit/symbol lock 并处理lane之间的skew。若不能获得symbol/bit lock 还得退回recovery.rcvspeed 进行降速,再次进入recovery.rcvlock状态获取bit/symbol lock 并处理lane之间的skew。
4,recovery.rcvsidle 链路两端设备TX向对端发送16个idle序列,并且RX端接受到8个idle序列,则该设备进入L0状态。
L0s 、L1、L2、disabled、hot reset、loopback状态,