ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

UFS 3.1协议栈全解析:从UPIU到WriteBooster的工程实践

UFS 3.1协议栈全解析:从UPIU到WriteBooster的工程实践 第一次翻开JEDEC的UFS 3.1协议规范我是被工作逼着啃的。那会儿项目里手机连续写入速度上不去网上能搜到的中文资料又多是“读写快多少倍”式的产品宣传真正讲协议栈、UPIU、状态机的几乎没有。后来硬着头皮把JESD220E主规范读完又在团队内部做了四期分享也就是这套“UFS3.1协议中文学习讲解(1~4)”。这篇是第一期的内容也是我认为最该先看的一期先把协议全景立起来知道它分几层、每层干什么、3.1相比旧版强在哪、主机和设备从一次命令到数据回传的整体链路是怎样的。目标是让没接触过UFS的工程师也能流畅读懂Spec里的关键章节。如果你之前只接触过SPI、I2C、UART这类简单的板级总线那UFS的复杂度会高一个数量级如果你是从eMMC时代过来的嵌入式工程师那UFS其实就是一套带完整命令队列、分层协议栈和电源状态机的“小系统”。下面我从头讲。1. UFS3.1协议是什么从一条Multi-Lane串行总线说起1.1 一句话定义以及它和eMMC、NVMe的差别UFSUniversal Flash Storage是JEDEC组织定义的闪存存储标准UFS 3.1是其中的一个正式版本。它不仅仅是一个“接口规范”而是一整套从物理层到命令层的端到端协议族主机控制器怎么发命令、数据怎么打包、差分信号怎么在M-PHY lane上跑、闪存设备那边怎么解析并执行全部写在JEDEC文档里。对比几类常见协议更容易定位UFS的角色。eMMC本质上是并行总线存储协议同一时刻只能读或者写数据线共享架构简单但性能天花板很低。NVMe则是为PC和服务器设计的走PCIe通道性能上限高但功耗、封装面积和启动时序并不适合手机、手表这类设备。UFS刚好夹在两者之间采用串行差分lane支持独立的收发方向也就是全双工命令模型引用了一套精简的SCSI命令集既有GB/s级别的顺序读写能力又能把待机功耗压得很低。这些特性让它成了移动设备存储的主流方案。我最早也以为UFS就是个“快一点的eMMC”直到啃协议才发现UFS连命令都不自己定义而是直接复用SCSI那套CDBCommand Descriptor Block框架。这一点非常关键后面第4节会展开讲。理解了这个基础再看手机发布会上的“UFS 3.1读写速度提升”你就知道他们说的其实只是整个协议栈顶层的一小部分表现。1.2 为什么偏偏是UFS 3.1而不是1.0或2.1UFS 1.0和2.0解决的是“从无到有”的问题UFS 2.1靠M-PHY HS-Gear3 x2把理论带宽提到了约1.45GB/s已经比eMMC强很多。但进入5G时代连拍、大型游戏资源加载、车载多路摄像头录像、AI大模型本地缓存都对随机写和待机功耗提出了更高要求。UFS 3.0把物理层升级到HS-Gear4 x2理论带宽直接翻倍到约2.9GB/s而UFS 3.1在3.0的带宽基础上加入了针对随机写的WriteBooster、针对待机功耗的Deep Sleep以及改善随机读的HPB机制。你会发现3.1真正拉开差距的地方其实不是顺序读写跑分而是把“用户体验”相关的短板补上了。手机App安装、照片连拍、后台大量写入恰好都是随机写密集场景。换句话说UFS 3.1更像是一次面向实际场景的“工程优化版”而不只是堆带宽。1.3 一张表看懂UFS各代际的关键参数版本物理层配置理论带宽命令队列标志性新能力eMMC 5.18位并行半双工约400MB/s不支持架构简单、成本低UFS 2.1M-PHY HS-Gear3 x2约1.45GB/s最多32全双工、命令队列UFS 3.0M-PHY HS-Gear4 x2约2.9GB/s最多32带宽翻倍、高速写入UFS 3.1M-PHY HS-Gear4 x2约2.9GB/s最多32WriteBooster、Deep Sleep、HPB表格里没写进去的还有链路层可靠性机制、多LUN并发、设备描述符体系等这些差异后面再细说。至少现在你心里有了一个坐标UFS 3.1不是一次接口大改而是在已经很快的3.0基础上对实际用户体验做了精细优化。2. 四层协议栈UFS到底由哪些“层”组成2.1 每一层在哪里负责什么UFS协议栈从顶层往下分四层这是一切后续知识的地基Application Layer应用层定义命令集、任务管理、设备管理。这一层负责“要干什么”比如读LUN 2的第100个逻辑块。Transport Layer传输层UTP把应用层的命令、数据、状态打包成统一格式的UPIU负责“怎么把事说清楚”。Link Layer链路层UniPro负责可靠传输、流控、重传、多条lane的聚合负责“确保数据不丢、顺序不乱”。Physical Layer物理层M-PHY负责真正的电信号收发高速串行差分lane负责“用什么电压、多大速率在线上跑”。每层对应一个JEDEC规范族应用层和传输层主要看UFS主规范JESD220系列链路层看UniProJESD223系列物理层看M-PHYJESD221系列。再加上主机控制器接口规范UFSHCIJESD224系列整个协议闭环就齐了。很多初学者一上来就盯着M-PHY的Gear等级和输出眼图结果被信号完整性绕晕。我的建议恰恰相反先忽略物理层细节把应用层和传输层搞懂那才是理解协议交互的主干。物理层的问题通常由硬件团队把关做软件和系统集成的人更需要关心UPIU和命令时序。2.2 一次读操作怎么穿过四层拿主机发起一次读请求举例。应用层先构造一条SCSI READ命令传输层把它封装进一个COMMAND UPIU里加上LUN、任务标签、数据长度等信息链路层再把UPIU分成一个个UniPro数据帧加上序列号和控制信息交给M-PHYM-PHY按HS-Gear4的速率在两条lane上并行发送。设备侧收到信号后逐层反向拆包最后把命令交给闪存控制逻辑执行。这就像一个完整的快递流程应用层是“我要买一本书”传输层是“把订单装进信封、写清收件人和地址”链路层是“交通工具按路线运输、丢件自动重发”物理层是“公路和车辆本身”。每一层只关心自己该做的事不越界这是分层协议的核心思想也是UFS能同时被手机芯片厂商、存储厂商和操作系统广泛支持的原因。2.3 协议栈和实际产品的关系Host侧与Device侧互为镜像在真实产品里协议栈两端的实现一软一硬。Host侧SoC里的UFS主机控制器UFS Host Controller负责大部分协议逻辑软件驱动比如Linux内核里的ufshcd负责配置寄存器、下发命令Device侧UFS芯片内部的控制器负责UniPro、UTP和应用层再往下接的是闪存阵列。因此排查问题时必须同时看软件和硬件。命令超时可能是驱动配置寄存器不对可能是设备回了异常状态也可能是M-PHY链路发生了Gear降级。没有分层概念的时候你很容易乱猜有了分层的框架你至少能先判断问题发生在命令阶段、数据阶段还是链路阶段。3. UFS 3.1升级的重点WriteBooster、Deep Sleep与HPB3.1 WriteBooster用SLC缓存把随机写“熨平”WriteBooster是UFS 3.1最重要的存储特性没有之一。闪存本身分SLC和TLC等类型SLC写入快但容量成本高TLC容量大但写入慢。UFS设备里通常以TLC为主TLC存储的随机写性能经常不如预期。WriteBooster的思路是在设备里划出一块SLC缓冲区先把随机写数据整体收进来再在后台以顺序方式刷到TLC区。这有点类似处理零散桌面文件的方式先扔进一个收纳箱等箱子里攒够了再统一归档。实测下UFS 3.1设备的4KB随机写比UFS 2.1高出好几倍尤其是连续大量小文件写入场景比如连拍保存、游戏资源解压安装能明显感觉到卡顿变少。WriteBooster有两种缓存分配模式LU-based基于逻辑单元直接在用户分区里划保留块和Separate独立区域。前者实现简单后者灵活一点。提示这里有个工程坑SLC缓冲区一旦写满后续写入会直接落到TLC原速跑分就会出现“一开始飙高、后来掉回”的平台期。所以测试写性能前要么先把缓存状态的一次完整写入跑完要么每次测试前对设备做冷启重置否则数据不具备可比性。3.2 Deep Sleep为了极致待机功耗新增的状态UFS设备有自己的电源状态机Active、Idle、Sleep、Slumber、Deep Sleep、Powered Down。UFS 3.1新增或强化了Deep Sleep状态关键在于把设备内部大部分时钟和逻辑都关掉只保留唤醒必需的电路功耗比Slumber再低一个量级。这个状态对手机意义很大。息屏播放音频、手机放在兜里待机、IoT设备低功耗间歇唤醒存储设备如果还保持较高的待机功耗整机续航会被严重拖垮。Deep Sleep的代价是唤醒延迟更长所以电源管理策略必须权衡频繁唤醒的负载不能盲目进入Deep Sleep。我做功耗测试时习惯抓设备的电源状态切换trace确认设备真的进入了Deep Sleep而不是停在Slumber——只看整机电流数值会被骗因为存储只在总电流里占一小部分。3.3 HPB主机帮忙管映射表闪存写入时会不断移动数据所以设备内部维护着一张逻辑地址到物理地址的映射表FTL。每次读命令都要查映射表映射表太大时无法全部放进缓存就只能频繁读闪存里的表项随机读因此变慢。HPB的思路是把部分映射表缓存到主机内存里主机可以直接下发映射信息或使用HPB相关命令方式让设备少查几次表缩短读命令的地址解析开销。UFS 3.1扩展了HPB能力对随机读取有明显帮助尤其是数据库类、大量小文件读取场景。不过它需要Host驱动配合不是设备单方面就能生效。Android层面如果内核不支持或没使能HPB这个特性其实没有被用到。所以看存储规格时不能只看设备支持不支持还要看整机软件是否真的开了对应开关。3.4 性能调整通知与热管理还有一类容易被忽视的3.1特性性能调整通知。设备温度过高时闪存控制器需要降低处理速度来保护数据可靠性此时设备可以通过事件机制告诉主机“我在限速”。主机收到通知后可以主动把负载移走一部分避免设备继续升温。这个机制在手机上体验最明显长时间录像或大型游戏时机身发热如果存储热降级且没有通知整机表现就会莫名其妙变差。要判断是否为存储热降级除了看温度就是看设备是否抛出了性能调整相关的事件。这类事件日志用第5节讲到的协议分析仪或内核trace都能抓到。4. 一次命令的完整旅程UPIU、CDB和状态机4.1 UPIU协议层的最小“信封”UTP层定义的核心结构叫UPIUUFS Protocol Information Unit可以理解成协议的最小信封。UPIU由12字节Header加可选的Data Segment构成Header里带着事务类型、LUN、任务标签、数据长度、期望数据长度等信息Data Segment可以装SCSI CDB、用户数据或者查询请求。UPIU的类型大概可以分成几类命令类Command、数据类Data In/Data Out、响应类Response、任务管理类、查询管理类Query还有NOP这类链路保活用。主机和设备的一切交互本质都是互相交换UPIU。看协议分析仪输出的trace时如果能把每个UPIU类型认出来整个交互过程就清晰了。4.2 命令从哪里来SCSI命令集UFS应用层没有另起炉灶定义一堆新命令而是复用了SCSI体系里的部分命令比如READ(10)、WRITE(10)、UNMAP等等。这些命令以CDB的形式存在封装在Command UPIU的Data Segment里。好处很明显存储业界对SCSI命令的语义、错误处理、状态返回非常成熟UFS不用从头定义也让上层操作系统可以复用很多SCSI相关的驱动逻辑。坏处是不熟悉SCSI的人会觉得命令结构有点怪比如LBA多字节传输长度还带块计数。第一次调UFS时我花了不少时间在SCSI命令解析上。4.3 读和写的时序差异读操作典型链路是主机发Command UPIUCDB指向要读的LBA→ 设备返回Data In UPIU把数据送给主机→ 设备最后回一个Response UPIU状态Good。写操作则多一步主机发Command UPIU → 设备准备好接收后发RTT UPIUReady to Transfer→ 主机发Data Out UPIU把数据推给设备→ 设备回Response UPIU。注意一次命令不一定是单个UPIU一对一来回。设备可以把大数据拆成多个Data In片段多次送出每次都有独立序号。第一次看Trace容易慌以为重复发了命令其实只是分片传输。读和写的差异也是优化点读更依赖设备内部响应速度写还受RTT交互节奏影响。4.4 描述符、属性、标志设备报告“我是谁”UFS设备通过一套“描述符-属性-标志”的信息模型向主机报告自身能力和当前状态。描述符是一大块只读或半只读的结构比如设备描述符、几何参数描述符、单元描述符、电源参数描述符属性是可以查询和设置的运行参数比如当前电源模式、异常事件标志是布尔状态如写保护标志、设备初始化标志。主机用Query Request这类UPIU去读取和设置它们。新接触UFS的人经常分不清“描述符和属性有什么区别”我的记忆方式是描述符是“自我介绍书”属性是“仪表盘”标志是“开关”。调试时设备几何参数描述符里的区块数量、擦除块大小能帮你验证容量和性能配置是否正确。4.5 队列与LUN并发在哪里发生UFS支持最多8个可寻址LUN以及Report LUNs、Boot、RPMB这类特殊逻辑单元。每个LUN可以有自己的块配置和内容多LUN让系统可以划分系统分区、用户数据、RPMB安全存储等。同时UFS支持原生命令队列NCQ最多允许32个命令同时在队列中执行。这解决了eMMC时代“一个命令排到底”的效率问题I/O调度器可以把多个请求重排提升吞吐。队列、多LUN、分片传输再加上全双工lane这条链路的并发能力是很强的。因此排查性能问题时不能只看单一命令延迟要看队列深度和并发行为。很多“速度慢”的问题单条命令延迟正常但队列并发一上来就掉链子这种问题只有抓队列级trace才能定位。5. 从这篇到四讲完成阅读路线与调试避坑5.1 我建议的Spec阅读顺序很多人打开JEDEC的PDF就先翻M-PHY物理层然后被眼图和均衡器劝退。我的顺序是先读UFS主规范JESD220系列的前几章建立UPIU、描述符、命令交互的整体概念再回头细看Transport Layer里UPIU的每个字段然后把UniProJESD223的可靠传输和流控过一遍最后才需要面对M-PHYJESD221和UFSHCIJESD224寄存器。整套UFS 3.1相关文档加起来上千页不可能一次读完。四讲安排里这篇对应的是“建立地图”后续第二讲会把UPIU字段和命令时序逐条拆开第三讲专门讲WriteBooster、HPB、Deep Sleep的工程调优第四讲面向硬件调试与性能验证。跟着这个顺序走比反复跳读效率高得多。5.2 调试用到的工具与手段软件层面Linux内核的ufshcd驱动、Android平台抓取的storage trace加上厂商调试命令可以定位大多数命令超时、状态异常问题。硬啃内核日志时UPIU类型能看懂就能快速判断是命令阶段出了问题还是数据阶段出了问题。硬件层面UFS协议分析仪可以直接解码M-PHY信号并还原UPIU序列比看日志直观得多。没有分析仪时用示波器看差分lane的停顿时长也能判断是否有Gear降级但要定位到字段级别很难。有条件的话抓真实trace是理解协议最好的方式。5.3 最容易踩的三个坑第一个坑是字节序。UFS描述符和CDB里的多字节字段不同字段的布局可能并不符合x86/ARM的本地字节序习惯直接按native字节序memcpy解析轻则字段错乱重则把LBA认错。务必以Spec每个字段的Byte Offset和Size为准写解析工具时逐个字段硬解先拿设备实际dump验证。第二个坑是把命令交互想成同步串行。UFS明明是异步队列加全双工看时序却总想“一问一答”。抓trace时只要看到队列里多个Command交错、RTT和Data Out乱序就可能判断异常。事实上这是并发正常表现。第三个坑是测试写性能碰到WriteBooster缓存。很多测评数字好看是因为SLC缓冲还没耗尽一旦把它填满性能立刻回到TLC原速。做写性能对比时先跑一遍长时写入让缓存进入稳定态否则对比结果没有意义。这几个坑我在最初几个月全部踩过一遍后面几讲里会拿实际trace再展开。最后分享一个我自己看协议的习惯不要整本啃先把“UPIU的几种核心类型”“命令状态机里的几个迁移”背成图表贴在工作台上然后在协议分析仪里对照真实交互。等你能看着Trace说出“现在设备回的是Response UPIU状态是Good”的时候UFS 3.1协议的大局观才算真正建立起来了。
返回列表