2. UFS协议栈层次与各层功能简介
各位做UFS的兄弟,我们先不急着调均衡参数。你得先把UFS协议栈的层次结构摸清楚。这就像修车,发动机、变速箱、悬挂各干各的,你总得知道哪层出了毛病。
UFS协议栈,说白了就是四层结构:应用层、传输层、链路层、物理层。每一层都把自己封装得严严实实,上层只管往下丢数据,下层只管把信号送出去。为什么要这么分层?方便迭代。物理层换了,上层代码都不用改。
2.1 应用层(Application Layer)——发号施令者
应用层是UFS的大脑。Host上的操作系统发一个“读数据”指令,这指令就在应用层被封装成标准的SCSI命令。UFS继承了SCSI的基因,Command Descriptor Block就是它的灵魂。
应用层还负责设备管理和电源管理。比如说,你要让UFS设备进入睡眠模式,这个命令也是在应用层组装的。
- 命令封装与解析(SCSI命令集)
- 任务管理(Task Manager Functions)
- 设备配置与查询(Query Request)
- 电源模式切换(Active、Idle、Sleep、Power Down)
我个人习惯,第一件事就是抓应用层的命令交互。调试工具里看看UFS Command Queue,Host发了什么命令,Device回了什么状态。我遇到过几次,明明物理层信号没问题,读性能死活上不去,结果发现是应用层发命令的顺序不对——没有Well-Known Logical Unit的支持,导致命令重叠度太低。
2.2 传输层(Transport Layer)——快递分拣中心
传输层干的事,就是给应用层的“包裹”打上地址和序列号,然后交给下层。UFS的传输层基于一种叫做UTP(UFS Transport Protocol)的机制。
UTP定义了一套事务模型。一个事务(Transaction)包含一个请求和一个响应。请求到了设备那边,设备处理完,再传回一个响应。传输层负责确保这个请求-响应对是匹配的,不丢包,不乱序。
你想想看,如果传输层出了乱子,应用层那边可能收到一个莫名其妙的响应。我排查过一个问题,设备偶尔返回错误状态码,用LA抓了半天,最后发现是传输层的事务ID(Transaction ID)因为中断冲突被覆盖了。
// UTP事务的典型帧结构(UFS Protocol Information Unit)
struct upiu {
uint32_t header; // 事务类型 + 标志位
uint32_t transaction; // 事务ID + 任务标签
uint8_t cdb[16]; // 命令描述符块
uint8_t data[……]; // 数据载荷
};
传输层的帧格式是调试的必考点。你得看得懂UPIU的Type字段,知道这是Command、Response还是Data In。我建议大家在调试的时候,把这个帧头解析出来打印到日志里,很多时候问题一眼就能看出来。
2.3 链路层(Link Layer)——高速公路监管员
链路层,嗯,这里要注意。它负责建立和维护两个UFS设备之间的数据通道。UFS的链路层基于MIPI UniPro(Unified Protocol)标准。UniPro定义了如何去管理链路的启停、如何进行流量控制、如何进行错误重传。
UniPro有两个子层:数据链路层(Data Link Layer)和网络层(Network Layer)。数据链路层负责成帧、校验、流控;网络层负责寻址和路由。UFS里一般只用单端口,网络层比较轻,重点在数据链路层。
在我们的UFS自动协商中,链路层起什么作用?它负责协商数据传输单元(MTU)的大小、链路重传超时参数。如果链路层协商失败,物理层就算信号再完美,设备也上不了Full Speed。
我曾经遇到一个案例,设备在高温下链路频繁断开。排查下来不是物理层掉信号,而是链路层的CRC错误计数超阈值,触发了链路层自动断开重连。我调整了UniPro的重传超时参数后,问题就消失了。所以你看,链路层的参数调优,往往被忽视,但非常关键。
| 参数名称 | 默认值 | 影响 |
|---|---|---|
| PA_MaxRxLanes | 1/2 | 最大接收链路数 |
| PA_MaxTxLanes | 1/2 | 最大发送链路数 |
| PA_CRCThreshold | 3 | CRC错误触发重传阈值 |
| PA_LocalTxDataLanes | 1/2/4 | 本端发送数据通道数 |
2.4 物理层(Physical Layer)——铜线信号工
物理层,说白了,就是MIPI M-PHY。M-PHY定义了差分信号、波特率、预加重、均衡等一堆物理参数。UFS 2.1用HS-Gear1/Gear2/Gear3,UFS 3.1以上用HS-Gear4/Gear5。Gear越高,速率越快,对信号质量的要求也越苛刻。
物理层也是我们自动协商和链路均衡调试的主战场。Host和Device上电后,物理层先来一轮握手:看看双方支持什么Gear,支持什么Rate(A/B),能不能High Speed。协商不成功,就退到最低的Gear。
物理层的参数包括:
- TX/RX Differential Amplitude:信号摆幅。摆幅太低,容易误码;太高,功耗大且可能有EMI问题。
- TX Pre-emphasis:预加重。高速信号在高频衰减严重,预加重能抬高高频成分。
- RX Equalizer:接收均衡器。常见有CTLE和DFE两种。我倾向先用CTLE压住低频噪声,再调DFE消除符号间干扰。
- Gear/Rate设定:确定最终工作的速率等级。
2.5 各层之间的协作关系
我现在带着项目,教新人第一课就是:别跳层。有些兄弟遇到通讯失败,上来直接怀疑均衡参数,改一遍不管用又去换晶体。这不行。
按我的经验,正确的排查路径是:
- 先看物理层:信号幅值够不够?眼图张开度如何?
- 再看链路层:UniPro有没有成功建立?CRC错误计数多少?
- 然后看传输层:UPIU帧的序列号有没有乱序?事务是否超时?
- 最后才看应用层:命令是否正确被处理?响应内容是否合理?
你想想看,如果物理层信号都不过关,上面各层再调也是白搭。反过来,物理层完美没问题,但传输层帧格式错了,一样跑不动。
这就是我为什么要把协议栈层次讲这么细。没有这个层次概念,自动协商和链路均衡参数调试就是瞎调。