記一次 spinor flash 讀速度優化


背景

某個項目使用的介質是 spinor, 其 bootloader 需要從 flash 中加載 os

啟動速度是一個關鍵指標,需要深入優化。其他部分的優化暫且略過,此篇主要記錄對 nor 讀速度的優化過程。

了解現狀

接到啟動速度優化的任務之后, 首先是了解情況。

當前的 bootloader 實測讀速度只有約 4M/s

為了加快速度已經嘗試過

  • spinor 驅動改為使用四線讀命令讀取數據。速度並沒有明顯改善。待確認改動是否生效。
  • spinor 驅動改為使用 dma 搬運數據。尚未修改成功。

計算上限

既然是要深入優化,那知道終點在哪還是很有必要的。

整個讀取過程,數據主要是從 spinor 到達 socspi 控制器,再由 cpudma 搬運到 dram 中的目標位置。

 spinor --> spi控制器 --> cpu/dma --> dram

先來考慮第一段的速度,這里比較好計算。針對當前的 socflash 的組合,從規格書可得到最高的 spi 時鍾頻率為 100M = 100 * 10^6,且讀數據可使用 4 線讀取,即 socflash 之間有 4 根數據線在並行傳輸數據。那么簡單算下 100 * 10^6 * 4bit = 400 * 10^6 bit/s = 47.68 MB/s , 可知極限速度為 47.68 MB/s

當然較真一點,發送讀命令給 flash 也需要時間,讓我們來算下。

一般一個讀命令需要 5 bytes, 即 cmd + addr[3] + dummy,所以實際的極限速度要考慮每發一次讀命令后讀取多少數據。讀命令是單線傳輸的,數據是四線傳輸。假設發一次命令讀 nbytes 數據,則命令和數據所占時間的比例為 5:(n/4), 那么實際用於傳輸數據的 clk 就只有 (n/4) / (5 + n/4) * 100M4 線傳輸的情況下每個 clk 可傳輸 4bit,從 bit 換算成 byte 再除以 8,於是速度公式為 (n/4) / (5 + n/4) * 100M * 4 / 8 , 這里要注意對於大小 1MB = 1024*1024 Byte, 對於時鍾 100M = 10^6

代入一些具體數據可得

每次讀取bytes 讀速度
64 36.33 MB/s
256 44.23 MB/s
1024 46.77 MB/s
64k 47.67 MB/s
1M 47.68 MB/s

可以看出,如果每次讀取數據量較小,那么發送讀命令消耗的時間就不可忽視。每次讀取的數據量越大,則讀命令對速度造成的整體影響就越小。

后面的部分理論速度暫時沒有很明確的計算方式,那暫時先知道完整的數據是這么流動的就可以了。

確認瓶頸

看了下驅動打印出來的確實是 80Mclk4 線的讀命令,雖然還沒調到最高時鍾 100M,但當前 4M/s 也完全對不上,到底是誰出了問題呢?時鍾不對?四線沒配置成功?驅動存在 bug? nor flash 物料的問題?

思考一下,要確認到底是誰的鍋,最簡單明了的方式還是量下波形,不管軟件驅動上怎么寫,控制器的寄存器怎么配,最終還是得反映在波形上才是最真實的傳輸效果。接上示波器或邏輯分析儀,看看 spi 線上的情況,是誰的問題就一目了然了。

首先量一下 spi clk 線,可以發現讀數據的過程中,clk 的信號不是連續的,在有信號時其頻率是正常的,但大部分時間 clk 線上卻是沒有信號的。再量量數據線,可以確認到確實使用了 4 線讀。

問題很明顯,spi 控制器是在間歇性讀數據,所以雖然讀 nor 的時候是 80M 的時鍾頻率進行讀取,但把 spi 的空閑時間計算進去,均攤下來的總的速度就只有 4M/s 了。

那為什么 spi 控制器會間歇性讀取而不是一直在讀取呢? 這就涉及到剛剛所說的數據流了,spi 控制器本身的 fifo 是有限的,當從 spinor 讀取的數據填滿 fifo 之后,就必須等着 cpu/dma 把數據取走,騰出 fifo 空間來,才能繼續發送指令從 nor 取數據。那么這段空閑時間,應該就是在等 cpu/dma 取數據了。

驗證 CPU

有了懷疑方向,那就得看下代碼了。目前驅動中使用的是 cpu 來搬運數據,正常讀取過程中,cpu 在執行以下代碼

while 待讀取數據計數值大於0
    if (查詢spi寄存器,判斷到fifo中存在數據)
        讀取spi fifo寄存器數據,寫到dram的buffer中
        待讀取數據計數值減1

如果是這里成為了瓶頸,那就有兩個地方比較有嫌疑,一是讀取 spi 寄存器,而是寫 dram

做點實驗確認下

實驗一,嘗試下把寫 dram 的操作去掉,使用如下操作,並由讀取前后的 log 時間戳來判斷耗時。

while 待讀取數據計數值大於0
    if (查詢spi寄存器,判斷到fifo中存在數據)
        讀取spi fifo寄存器數據
        待讀取數據計數值減1

重新測試下,發現速度沒有明顯變化。

實驗二,嘗試下減少讀 spi 寄存器的操作

while 待讀取數據計數值大於0
    讀取spi fifo寄存器數據
    待讀取數據計數值減1

重新測試下,發現讀速度翻倍了,達到了 8M/s,看來果然是這里成為了瓶頸。沒想到 cpu 讀個 spi 寄存器竟然這么耗時。

改用 DMA

cpu 太慢,那就指望 dma 了。

先來解決 dma 驅動異常問題,了解下情況,原來這個 dma 驅動的支持是從另一個分支上移植過來的,原本工作正常,到了這個分支就翻車了。

這就是一個找不同的問題了,先比較下兩個分支的差異,再將可疑的地方 checkout/cherry-pick 到另一個分支來驗證。很快找到了關鍵因素 dcache

這個分支上是默認打開了 dcache 的,可見舊文 記一個bootloader的cache問題,而這就導致了 dma 驅動工作異常。

簡單點,關掉 dcache 試試,果然 dma 就正常了。測下速度,達到了 21M/s

再測試下不關 dcache,在配置了 dma 描述符之后,刷一次 cache 再啟動 dma 傳輸,也是正常的了。

優化配置

21M/s 的速度,看來瓶頸還是在 dma 這里。此時可以嘗試將 spi clk80M 提高到 100M,可以發現整體讀速度沒有變化,這也可以佐證當前瓶頸仍然不在 nor 的讀取速度上面。

測個波形看看,果然 clk 線上還是間歇性的,不過空閑時間比之前少了很多。

dma 的速度能不能改進呢? 這就涉及到具體的芯片了,需要深究下 dma 控制器和 spi 控制器的配置。

優化 dmaspi 控制器的配置后,dmaspi 控制器取數據的速度,終於超過了 80M 時鍾下的 spinor 讀取速度,將 spi clk 修改為 100M,測得讀速度約 36M/s

優化驅動

前面說到,發送讀命令給 flash 也需要時間,在 os 中受限於 buffer 大小等,可能會限制每次讀取和處理的數據量,但對於 bootloader 來說則完全可以一口氣將所需的數據讀入,無需分段。

另外可查看驅動中是否有無用的清空 buffer 之類的操作,一並優化掉。

提高時鍾

驅動邏輯和寄存器上無法優化之后,還想提速,那么可以試試提高時鍾。

提高 cpu 時鍾和 dma 時鍾,提高后測得速度約 47M/s,基本就是理論極限了。

但具體能否提高時鍾還是得謹慎評估,單個板子可以正常運行,不意味能夠穩定量產。

壓縮鏡像

在讀取速度無法進一步優化的情況下,要提高啟動速度,那就得減少讀入的數據量了。

可以評估下使用壓縮的鏡像來減少讀入的數據量,只要多出的解壓時間不長於節省掉的讀取 flash 時間,那就是划算的。

是否壓縮,選擇哪種壓縮算法,就跟 io 速度,cpu 解壓速度直接相關了,最好經過實測確認,綜合啟動速度和 flash 占用來選擇。

其他

如果是帶壓縮的鏡像,那啟動速度就是讀取時間+解壓時間。

讀取時主要是 io 操作,解壓則主要是 cpu 操作。那么是否有可能實現邊讀取邊解壓,使得總的啟動時間進一步縮短呢?這個待研究

blog: https://www.cnblogs.com/zqb-all/p/12824908.html
公眾號:https://sourl.cn/4X3jE7


免責聲明!

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



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