阿呆在成为呆哥前,也有过青春年少,不仅有错过的大雨,还有错过的PCIe Reset。
PCIe是个博大精深的协议,跟Reset相关的术语就有好些:Cold Reset, Warm Reset, Hot Reset, Conventional Reset, Function Level Reset, Fundamental Reset, Non-Fundamental Reset
一开始面对这么多概念,阿呆心里其实是拒绝的。牛人都有特殊能力,蛋博士的能力是化神奇为腐朽,透过现象看本质。
阿呆的特点是提纲挈领,快速从一大堆概念中理出头绪:
第一步,呆哥先整理这些个Reset之间的关系:
这些Reset之间是从属关系, 总线规定了两个复位方式:Conventional Reset和FLR(Function Level Reset),而Conventional Reset由进一步分为两大类:Fundamental Reset和Non-Fundamental Reset。Fundamental Reset方式包括Cold和Warm Reset方式,可以将PCIe将设备中的绝大多数内部寄存器和内部状态都恢复成初始值;而Non-Fundamental Reset方式为Hot Reset方式。
看到下面这张表,有没有感觉好一点?
1.Conventional Reset |
1.1 Fundamental Reset |
1.1.1 Cold Reset |
1.1.2 Warm Reset |
||
1.2 Non-Fundamental Reset |
1.2.1 Hot Reset |
|
2. Function Level Reset |
第二步,呆哥要搞明白每种Reset具体干什么,实现方式以及对Device的影响;
Fundamental Reset:由硬件控制,会重启整个Device,包括:重新初始化所有的State Machine,所有的硬件逻辑,Port State和configuration register。
当然,也有Fundamental Reset搞不定的情况,就是那些某些Register里的某些属性为”Sticky”的Field,跟蛋博士一样坚强,除非完全断电,否则任你如何Reset这些Field的值一直不变。
这些Field在Debug的时候非常有用,特别是那些需要Reset Link的 情况,比如在link reset以后还能保存之前的错误状态,这个对那些对自己有要求的FW以及上层应用来说,是极好的。
Fundamental Reset一般发生在整个系统Reset的时候(比如你重启电脑),但是也可以只针对某个Device做Fundamental Reset。
Fundamental Reset有两种:
- Cold Reset: Power Off/On Device的Vcc (Vaux一直在)
- Warm Reset (Optional): 保持Vcc的情况下由系统触发,比如改变系统的电源管理状态可能会触发Device的warm reset,PCIe协议没有定义具体如何触发Warm Reset的,而是把决定权交给系统。
有两种方法对一块PCIe Device做Fundamental Reset:
-
系统这边发PERST# (PCIe Express Reset)信号给Device;
- 以下图为例
- 一个系统上电时,主电源稳定以后会有”Power Good”信号
- 这时ICH就会发PERST# 信号给下面挂的PCIe SSD
- 如果系统重启,Power Good信号的变化会触发PERST# 的Assert和De-Assert,就可以实现PCIe Device的Cold Reset
- 如果系统可以提供Power Good信号以外的方法触发PERST#,就可以实现Warm Reset
- PERST#信号会发送给所有PCIe Device,Device可以选择使用这个信号,也可以不理它
-
如果这块PCIe Device不支持PERST#信号,那上电时他会自动进行Fundamental Reset;
- 那些特例独行,选择不理睬PERST#信号的Device,必须能自己触发Fundamental Reset
- 比如,侦测到3.3V后就触发Reset (当Device发现供电超过其标准电压时,也必须触发Reset)
Hot Reset:通过Assert TS1的Symbol 5的Bit [0] 实现:
PCIe Device收到两个连续的带Hot Reset的TS1 后,经过2ms的timeout:
- LTSSM经过Recovery和Hot Reset State,最终停在Detect State (Link training的初始状态)
- Device所有的State Machine,所有的硬件逻辑,Port State和configuration register(Sticky bit 除外)全部回到初始值
当PCIe Device出现问题时,可以通过软件触发Hot Reset使其恢复,具体方法如下:
对 RC的Bridge Control Register Bit[6] – Secondary Bus Reset写’1’。
- RC会开始发带Hot Reset的TS1
- 2ms后Device会进入Hot Reset状态,此时LTSSM的状态变化是 L0 -> RCVRY -> HOTRESET
- 将RC的Bridge Control Register Bit[6] – Secondary Bus Reset清零, Device的LTSSM的状态变化HOTRESET -> DETECT
- 重新开始LTSSM进行Link Training
注:这个我觉得有点像SATA里面Host端通过Trigger OOB去修复Link上的一些问题
软件还可以通过设置Device的Link Control Register [2] – link disable bit 把Device disable掉。
当Device的Link Disable bit被置上以后,会进入LTSSM Recovery State,开始向RC发送带Disable bit的TS1(这个动作只能由EP发起,RC端这个bit是reserve的)。
RC端收到这样的TS1以后,其物理层会发送LinkUp=0的信号给链路层,之后所有的Lane都会进入Electrical Idle。2ms timeout以后,RC会进入LTSSM Detect mode,但是Device会一直停留在LTSSM的Disable状态,等待重出江湖的那一天。
FLR (Function Level Reset):PCIe Link就像一条大马路,上面可以跑各种各种的车,这些车就是不同的Function。如果某个Function出了问题,当然可以通过Reset整个Link的方式来解决,不过细腻的呆哥当然不会采取这种方法,他会使用Function Level Reset,哪里不舒服点哪里。并不是所有的Device都支持FLR,需要检查Device Capabilities Register[28]进行确认。
如果Device支持 FLR,那么软件就可以通过Device Control Register的[15]来进行Function Reset了
FLR会把对应Function的内部状态,寄存器重置,但是以下寄存器不会受到影响:
- Sticky bits – cold reset和warm reset都拿他们没辙
- HwIint类型的寄存器。在PCIe设备中,有效配置寄存器的属性为HwIint,这些寄存器的值由芯片的配置引脚决定,后者上电复位后从EEPROM中获取。Cold和Warm Reset可以复位这些寄存器,然后从EEPROM中从新获取数据,但是使用FLR方式不能复位这些寄存器。
- 一些特殊的配置寄存器,比如Captured Power, ASPM Control, Max_Payload_Size或者Virtual Channel
- FLR不会改变Device的LTSSM状态
FLR的时间:
协议规定一个Function的Reset需要在100ms内完成。但是软件在启动FLR前,要注意是否有还没完成的CplD,遇到这种情况,要么等这些CplD完成再开始FLR,要么启动FLR以后等100ms以后再重新初始化这个Function。这种情况如果不处理好,可能会导致data corruption: 前一批事物要求的数据因为FLR的影响被误传给了后一批事物。
要避免这种情况,阿呆建议这么做:
- 确保其他软件在FLR期间不会访问这个Function
- 把Command register清空,让Function一个人想静静
-
Polling Device Status Register [5] – Transactions Pending bit直到被Clear – 代表没有未完成的CplD,或者等待到Completion Timeout 的时间,如果Completion Timeout没有被Enable,等100ms
- 初始化FLR然后等100ms
- 重新配置Function并Enable
在FLR过程中:
- 这个Function对外不能被使用
- 不能保留之前的任何可以被读取的信息(比如内部的Memory需要被清零或者改写)
- 回复要求FLR的Cfg Request,并开始FLR
- 对于发进来的TLP可以回复UC (Unexpected Completion)或者直接丢掉
- FLR应该在100ms之内完成,但是其后的初始化还需要花一些时间,在初始化过程中如果收到Cfg Request,可以回复CRS (Configuration Retry Status)
快结束了,听阿呆总结一下Reset退出时的那些事:
- 从Reset状态退出后,必须在20ms内开始 Link Training;
- 软件需要给Link充分的时间完成Link Training和初始化,至少等上100ms才能开始发送Cfg Request ;
- 如果软件等了100ms开始发Cfg Request,但是Device还没初始化完成,Device会回复CRS;
- 这时RC可以选择重发Cfg Request或者上报CPU说Device还没准备好;
- Device最多可以有1s时间(从PCI那继承来的),之后必须能够正常工作,否则System/RC则可以认为Device挂了;