一、故事前传
前面的文章针对PCIe的一部分内容已经做了解析。
较为详细解释请见之前的文章:
1. PCIe技术概述;
2.0~2.8 PCIe事务层详细解析;
3.0~3.2 PCIe数据链路层详细解析;
4.0~4.1 PCIe物理层解析;
二、电源管理
PCIe总线的电源管理包括两方面的内容:
注: ASPM= Active State Power Management.
在本文中,我们就针对这两种电源管理机制展开介绍。
1. PCI-PM电源管理
PCI-PM电源管理机制是系统软件通过修改寄存器中的电源管理字段,使PCIe设备进入D状态。D状态总共有四种:D0,D1,D2,D3.
D0: 这个状态属于"全马力"工作状态,不考虑任何电源节省的因素。D0又有两个子状态: D0-Uninitialized和D0 Active.
a, D0-Unintialized: 这时PCIe还没有被激活,只能接受Configure Write/Read TLP请求,仍不能正常工作。比如设备刚被Reset后进入D0-Unintialized。
b, D0 Active: PCIe设备已经被成功激活,可以正常工作。
D1: PCIe设备进入"浅睡眠"状态;
D2: PCIe设备进入"深度睡眠"状态;
D3: 这个状态是电源管理中最低功耗的状态。有两个子状态: D3-hot和D3-cold。
a, D3-hot: 此时与D1/D2的功能类似,但是D3-hot只能返回到D0-Unitialized。
b, D3-cold: 当PCIe设备的VCC电源被移除时,PCIe设备进入此状态。
值得注意的是,PCIe设备必须支持D0和D3,但是D1/D2是选择性的。所以在目前市面的SSD PCIe主控,一般都只是支持D0/D3,并不支持D1/D2。当PCIe设备处于D0状态时,ASPM可以改变PCIe链路的电源状态。
介绍ASPM之前,我们先认识一下PCIe定义的有关PCIe链路的电源状态:
L0: 这个状态属于PCIe设备的工作状态,与D0对应;
L0s: PCIe设备进入Standby状态;
L1: PCIe设备进入比L0s更低功耗的Standby状态;L1状态有两个子状态L1.1和L1.2;
L2/L3 Ready: 这两个状态是PCIe设备准备进入L2/L3前的预备状态;
L2: 比L1功耗更低的深度省电状态;
L3: 此时PCIe链路出于关闭状态,PCIe设备的VCC电源也被移除;
LDn: 这个状态不具有实际意义,只是L2/L3返回L0状态时所需要用的中间过渡状态;
PCIe设备的D状态与PCIe链路电源状态相辅相成,不是单独存在的。亲密关系如下表:
了解了PCIe设备D状态与PCIe链路的电源状态,我们接下来看看"一号主人公"ASPM.
2. ASPM电源管理
ASPM是基于硬件自主控制的链路电源管理机制,只有在PCIe设备处于D0状态是才可以应用ASPM机制。与ASPM有关的链路状态只有L0s和L1。
在L0s和L1状态下,PCIe链路均进入Electrical Idle. 此时,链路中差分信号D+和D-没有压差,也就代表没有信号传输。Electical Idle状态的进入和退出会用到数据流的Ordered sets(TS1/TS2, EIOS, FTS, EIEOS等),有关数据流的相关内容请见前面的文章"物理层数据流解析", 在这里不再展开介绍。
我们这里主要介绍一下L0s和L1的状态转换。
从上面ASPM链路状态装换图(蓝色部分)中,我们可以看到:
L0s状态的进入:
L0s状态的进入是根据设备所处空闲时间的长短决定的。PCIe Sec规定,如果PCIe设备在7us之内,没有TLPs或者DLLPs要传输,那么PCIe设备发送端就可以决定是否要进入L0s状态。
不过,这个不是强制性的,如果你任性的坚持即使超过7us没有TLPs/DLLPs传输也不进入L0s,也是可以接受的~但这样的话就失去了ASPM的意义咯~
当PCIe设备发送端决定进入L0s时,发送端会停止数据输出,并给接收端发送Ordered set "EIOS",之后,发送端就进入Electrical Idle状态。接收端接收到EIOS序列之后,在经过一段延时(最短20ns)后,也进入Electrical Idle状态。此时,发送端和接收端均进入L0s状态。
另外,需要提一点:发送端与接收端有可能出于不同的链路状态。比如,进行DMA操作时,发送端一直处于工作状态L0,而接收端在长时间内无事可做,将自主进入L0s状态,此时不需要发送端同步进入L0s。
L0s状态的退出:
当PCIe设备的发送端检测到空闲状态的条件(7us之内没有TLPs或者DLLPs要传输)不再满足时,就会从L0s退回L0状态。此时,发送端会向接收端发送N_FTS(Link Training时设定)个FTS和1个SOS,之后进入L0状态。接收端收到满足要求的FTS后,再接收1个SOS序列,然后也进入L0状态。
与L0s相比,L1的功耗更低。同时L1状态的进入与退出都比L0s要复杂。
L1状态的进入:
L1要求PCIe链路两端的设备均进入L1状态。重要的是,只有下游设备(EP活着Switch上游端口,如下图红色框)可以主动要求进入L1状态。上游设备在接收到下游设备的请求之后,根据自身状态决定是否接收上游设备的请求。
其实,下游设备也不是很任性的随时可以请求进入L1状态,也需要满足几个条件:
那么,我们就详细解读下游设备是如何启动请求进入L1状态的。
1. 当下游设备准备启动进入L1状态时,会先暂停安排新的TLP;
2. 在发送进入L1状态请求之前,必须接收到暂停TLP传输前的最后一个TLP的Ack回报,确保其已被正确接收;
3. 另外,还要确保Flow Control积分单元可以满足最大TLP传输的需要。这个主要是为了设备退出L1状态之后可以立刻开始TLP传输工作;
4. 在前面的准备工作完成之后,此时就可以放心的给上游设备发送进入L1状态的请求咯。在这个过程中,下游设备会一直发送PM_Active_State_Request L1 DLLP,知道收到对方的"接收函"PM_Request_ACK DLLP。
5. 上游设备接收到进入L1状态的请求。
6-8. 上游设备在接收到L1请求之后会重复类似上游设备的准备工作(Step 1-3)。
9. 上游设备的准备工作完成后,会给下游设备下发"接收函"PM_Request_ACK DLLP,同意下游设备的请求。
10. 下游设备接收到上游的接收函之后,停止TLP和DLLP的传输。
11. 下游设备发送端发送EIOS序列,然后进入Electrical Idle状态。
12. 上游设备收到下游设备的EIOS序列后,知道下游设备已进入L1状态。此时,上游设备也停止TLP和DLLP的传输。
13. 接着上游设备的发送端也进入Electrical Idle状态,代表了上游设备也进入L1状态。
其实,上述的过程是一种比较理想的状态,就是假设在下游设备发送进入L1请求的时候,双方均已完成事务传输,并且没有新的事务传输需求。
生活不可能总是一帆风顺。下游设备的进入L1请求也有可能被上游设备拒绝:
1. 当下游设备准备启动进入L1状态时,会先暂停安排新的TLP;
2. 在发送进入L1状态请求之前,必须接收到暂停TLP传输前的最后一个TLP的Ack回报,确保其已被正确接收;
3. 另外,还要确保Flow Control积分单元可以满足最大TLP传输的需要。这个主要是为了设备退出L1状态之后可以立刻开始TLP传输工作;
4. 在前面的准备工作完成之后,此时就可以放心的给上游设备发送进入L1状态的请求咯。在这个过程中,下游设备会一直发送PM_Active_State_Request L1 DLLP,知道收到对方的"接收函"PM_Request_ACK DLLP。
5. 上游设备接收到进入L1状态的请求。
6. 上游设备在接收到L1请求之后,发现自身情况并不能满足L1的要求,并回复 PM_Active_State_Nak TLP,告知下游设备目前无法进入L1状态。
7. 下游设备接收到上游的拒绝信。
8. 因为无法进入L1状态,下游设备会退而求其次,在满足L0s时先进入L0s状态。
L1状态的退出:
与L1状态的进入步骤相比,L1状态的退出相对简单很多了。L1状态的退出请求可以有任何一方提出。不像L1状态的进入,只有下游设备才能请求进入L1状态。
L1状态的退出是通过重新Link Training实现的。因为发送TS1序列之后,设备退出Electrical Idle状态,也即退出L1,进入Recovery状态,进而回到L0状态。
上面介绍了ASPM相关的链路状态,是不是觉得ASPM挺好玩的呢?
如果我们要在SSD中应用ASPM功能,其实还有两项工作:
在Link Control Register中,将ASPM的功能打开:
在Link Capabilities Register中,对ASPM进行具体的设定.
此外,除了上述通过软件修改Link Control Register的方式打开ASPM功能外,现在很多主板BIOS中可以修改ASPM的设定。