UFS特性介紹


UFS發展史

在手機飛速發展的近 10 年,巨大的市場需求催生出移動存儲的快速發展,人們需要越來越來越多的空間和越來越快的存儲速度。下圖是一個俗稱存儲 8+256G 的手機模塊連接示意圖。

 

圖 1 手機存儲連接

 

JEDEC在2011推出了UFS1.0協議標准,從2015開始手機廠家開始陸續商用UFS2.0的存儲器件,Samsung,Toshiba,Hynix等傳統存儲器件率先推出自己的UFS存儲器件。現在,UFS器件已經被各大手機廠商廣泛采用,那么UFS具備哪些優勢,有哪些特性,具體工作流程是什么,本文將逐一描述。

 

和傳統eMMC相比,UFS采用了MPHY協議,這個是UFS底層物理信號傳輸協議,MPHY是一個MIPI Alliance推出的PHY協議的一種。這個MPHY的傳輸特點就是兩個字,“快”和“穩”,MPHY通過串行+差分的形式保證了這一點,串行保證了“快”,串行信號能做到高頻傳輸,因為沒有並行信號的相互干擾,而“穩”則由差分保證,差分傳輸可以相互抵消共模信號干擾。

 

MPHY

如下圖所示,信號具有單向,差分的特點,TXDP和TXDN分別表示發送端TX的差分管腳的positive和negative。目前UFS采用的是2lane(但是如果因為焊點等物理斷開,只剩下一個lane,lane0,UFS也可以正常工作),類似於雙向4車道,但是不能變道,也不能逆行,lane之間是相互獨立工作的。下圖屬於1.5lane。需要注意的是這里一個通道就標注為1個lane,而UFS里面通常叫法是1個lane包含兩個方向的數據方向,即TX->RX, RX->TX。

 

圖 2 MPHY的底層鏈路傳輸示意圖

 

通過驅動控制TX兩個差分點TXDP/TXDN的電壓,以及對端RX接收機RXDP/RXDN的阻抗,形成如下的4種差分線狀態:

圖 3 差分線組成的四種狀態

 

同過控制上圖4種line state的保持時間,可以實現TX和RX的狀態機切換,以實現功耗和性能的平衡。從下面的狀態機可以看到,可以將MPHY的功耗分為4個層次:POWERED,HIBERN8,STALL/SLEEP,BURST。手機在進行大量數據傳輸時,將處於HS-BURST狀態,如果LINE被驅動成DIF-N,並且持續20UI(HS)的時間,那么就會進入STALL模式。這里的UI是Unit Interval,即在傳輸模式下的20個單位間隔。

圖 4 UFS采用的TypeII M-TX狀態機切換

 

在HS-BURST模式下,又分為1~4擋,和汽車的擋位一樣,每個擋位對應不同的速度,MPHY對應的不同擋位的傳輸速率如下圖所示。從UFS3.0增加了HS-G4,之前最高速擋只有到HS-G3。這里的傳輸是指1個lane的傳輸速率,實際上UFS有2個lane,帶寬是應該是double一下的,目前各廠家基本采用rateB,那么理論上帶寬11660.8Mbps * 2 = 2915.2MB/s,這里有個細節需要注意一下,為了避免連續的高電平或低電平出現,MPHY上面傳輸的數字都是經過特殊處理的,目前UFS采用的是8b/10b編碼的方式,所以這里的有效理論帶寬需要打8折,即2915.2MB/s * 0.8 = 2332.16MB/s。

圖 5  MPHY HS-BURST各Gear速率

 

2332.16MB/s 這個帶寬已經很高了,不過現在UFS3.0的器件已經測出2279.8MB/s的性能,已經很接近這個理論帶寬了,當然器件的性能也會推動協議的演進,比如后面可能會推出HS-G5,8b/10b的編碼方式變為效率更高的128b/130b。

圖 6  某UFS3.0器件的androbench跑分數據

 

MPHY是個很復雜的模擬IP,目前市場基本被synopsys公司占領,各UFS器件廠家都從它那里購買這個IP,里面涉及到串行並行轉換,編解碼,信號放大,CDR時鍾恢復,采樣,以及上面的HS-G4還是HS-G1的擋位選擇,那么MPHY是怎樣被控制的呢?如下3個寄存器就是MPHY私有的寄存器,分別用來控制模式,rate,擋位。

圖 7  UFS速度控制相關MPHY的寄存器

 

Unipro

和所有的OSI(Open Systems Interconnection) model一樣,UFS采用了和OSI能夠對應上的模型,即Unipro(Unified Protocol),Unipro和MPHY一樣,也來源於MIPI alliance,目前UFS上面采用的是Unipro Version 1.8。

圖 8  Unipro定義的層次關系

Unipro定義了各層package的格式,從下往上看,Medium層傳輸的是差分信號,PHY Adaptor(L1.5)傳輸的是PACP frame,LA應用層傳輸的就是UPIU(UFS protocol information units),我們通用的讀寫請求就會被打包進UPIU里面,然后自上而下層層傳遞,最后通過差分信號傳遞給UFS器件,而器件里面擁有和HOST完全對等的層次關系和協議格式,從而實現數據通信。

DME(Device Management Entity)對Unipro的所有層次進行控制和管理,提供各層次所有的寄存器的訪問接口。這個接口通過UIC實現,Unipro各個層次的寄存器都是通過UIC來訪問的。那么統一的UIC接口是如何實現各層次寄存器路由的呢,就是通過下面的LayerID實現的,通過寄存器address的bits【14:12】做掩碼。

圖 9  Unipro各層寄存器地址路由

 

所以可以直接從寄存器地址來判斷這個寄存器是Unipro的哪一個層次的寄存器,比如,MPHY層的寄存器地址都是0xXX,而PA層的地址是0x15xx,DME層本身的地址是0xDxxx。

當然,MPHY的寄存器地址有點特殊,是因為MPHY里面有多個lane的時候,需要通過其他的mask來進行區分,目前是通過在最低位的0x0,0x1,0x4,0x5來進行區分的,分別表示TX的lane0,lane1,RX的lane0,lane1。

UFSHCI

Unipro層是封裝在UFS這個IP里面的,其中的寄存器也是CPU不能直接訪問的。UFS整個模塊對外的唯一接口就是UFSHCI(UFS Host Controller Interface)。CPU通過兩條總線來實現對UFS的控制和數據交互,分別是APB和AXI總線。在下圖中,左邊的方框就是UFSHCI,通過APB總線訪問,其地址空間通過ioremap在內核申請虛擬地址空間即可被CPU直接訪問,右邊方框則是數據部分,由dma_alloc接口進行申請,通過AXI進行訪問。

圖 10  UFSHCI經典數據結構

這個數據結構圖覆蓋了如下信息:

a.左框UFSHCI寄存器分布,分為6塊,host Controller Capability ~ Vendor Specific

b.UTP Transfer Request這一塊的寄存器提供了指向UTRD (UTP Transfer Request Descriptor)List的指針地址

c.UTRD有0~31個,即32個,意味着UFS擁有32個slot,SOC層可以同時接受32個請求

d.32個UTRD是物理連續的,這點很重要,因為連續,可以直接根據slot序號直接獲取到UTRD

e.UTRD里面包含了UPIU的地址,UPIU的size是固定的,否則AXI怎么能准確的把response信息填充到對應請求的Response UPIU里面呢

f.同樣Response UPIU數據格式固定

g.如果UTRD里面有數據讀寫需求,那么需要填充PRDT(Physical Region Description Table)

h.PRDT指向的Data buffer不是連續的,而是離散狀,因為PRDT是個表,所以這個表里面可以存放很多不連續的Data buffer地址,對應一個個的segment

i.1個Data buffer的size最大不能超過64K,這個是由芯片內部決定的,因為這個size涉及到一個數據包單元DATA OUT/IN UPIU的長度,也是一次底層數據包傳輸的長度,但是PRDT表的個數可以自己確定,一般軟件定義為128個,那么一個UTRD也就是一個請求可以最大傳輸64K * 128 = 8M

j.在實際應用中一個讀寫請求如果size過大,如1000M,則會被上層切割,比如1M,所以底層的size是足夠的

k.除了32個UTRD外還有8個UTMR,顧名思義,這個是任務管理請求,對上面的32個請求的狀態進行查詢,如果說32個UTRD理解為工人,這8個UTMD可以理解監工,查詢是否工作完成,如果工作在預期時間內沒有完成的也可以執行abort操作,然后重新下發請求或者進行復位器件等相關的異常處理。

 

圖 11  UFSHCI常用寄存器

 

上面的HCI寄存器cpu可以通過APB總線直接讀寫,而Unipro的寄存器則可以通過上面的4個UIC Command寄存器完成,分別是UICCMD,UCMDARG1, UCMDARG2,UCMDARG3。寄存器就是芯片的API接口,通過這4個UIC寄存器就可以實現對Unipro各層和MPHY的所有寄存器進行讀寫操作。

初始化流程

 

圖 12  UFS初始化流程

函數

主要功能

ufs_qcom_probe

platform_driver probe,高通平台驅動入口

ufshcd_pltfrm_init

申請IO空間,獲取中斷號,申請hba資源

ufshcd_init

完成數據結構初始化,注冊中斷,申請和配置UFS   controller所需要的DMA內存,初始化並使能UFS controller,復位器件

ufshcd_async_scan

異步初始化函數

ufshcd_probe_hba

Linkup建鏈,獲取器件信息,注冊scsi

 

總之,和通用的驅動初始化流程一樣,ufs驅動的初始化也主要包含資源申請,controller初始化和使能,建立鏈接,完成中斷注冊,注冊中斷上半部和中斷下半部處理函數。

 

申請好的兩端dma內存寫進UFSHCI寄存器,controller最后通過這兩個內存地址完成全部的數據交互過程,其原理就是base + index * unit 的索引方式:

    

UTRD,UCD的request,response,prdt物理地址數據結構填充:

數據傳輸路徑

數據傳輸是驅動程序的本質目的,通過數據的傳輸,來完成作為存儲介質的使命,read & write,在read流程中,ufs向應用程序提供數據,在write流程中,應用程序向ufs存放數據。

本節分三個階段關注數據的流向,分別是:系統調用數據到bio的組成,bio到電梯隊列request的組成,request到controller的數據傳輸。主要圍繞buffer和存儲地址兩個數據流要素,根據讀流程描述各階段這兩個數據流要素的數據結構。

 

圖 13  sys_read->submit_bio數據流流程

如上圖所示,用戶態傳入fd, buf, count的參數被傳入到kiocb和iov_iter里面,kiocb用來傳遞磁盤地址,而iov_iter用來傳遞buf。

iov_iter用來從用戶和內核之間傳遞數據用,通過迭代的方式可以實現物理地址或者虛擬地址不連續的描述:

_blkdev_direct_IO函數中從iocb傳遞磁盤地址bio->bi_sector,同時iov_iter傳遞給bio的bi_iter:

 

bio生成后,就plug到進程的plug_list里面,如果失敗,則進電梯merge,如果依然失敗,則只能等待新的request被釋放出來,兩次蓄流的目的是為了盡可能的讓bio請求得到merge,減少往磁盤驅動下發的頻度,提升綜合性能。

 

圖 14  bio->request數據流流程

 

當plug_list達到設定閾值或進程主動發起或設定時間已到或手機將要關機等,則會進行泄流。從elevator的queue里面取出一個request請求,下發到底層UFS驅動,這個流程從request轉化為scsi協議包,最后封裝在UFS的協議包UPIU包里面,於是就完成了一個請求的host內存准備,最后通過置這個請求對應的UFSHCI的doorbell寄存器中的mask,實現請求往驅動層的發送。

圖 15  request->dma數據流流程

 

__blk_segment_map_sg實現bio到request里面的sglist的數據填充:bio里面的bv_page是將要進行讀的buffer地址,這個地址被掛載到sg鏈表,sg操作將會對應UFS里面的PRDT,這時候的bv_page為DMA可以直接訪問的物理地址。

對於存儲器件的讀寫操作,通過傳遞磁盤地址和buffer,UFS根據磁盤地址讀取到數據后填充到buffer,或UFS從buffer獲取數據寫入磁盤地址。寫的流程和讀原理類似,這里就不再描述了。

 

參考資料

[1]《mipi_M-PHY_specification_v4-1_JEDEC-LIAISON-DISCLOSURE》

[2]《JESD223D》

[3]《JESD220C》

掃碼關注
“內核工匠”微信公眾號
Linux 內核黑科技 | 技術文章 | 精選教程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM