驚喜發現:龍芯最新處理器實現了睿頻功能

最開始拿到龍芯3A4000 PMON Bootloader代碼的時候,我是震驚的,一眼看過去又全部是彙編,從DDR訓練到HT和7A初始化,屬實大工程。

真的很佩服龍芯那些工程師,是我用匯編寫這麼大個工程早就寫出114514個Bug了。

不過裡面有段彙編出乎我意料,名叫ls132_core.S,結合之前在Lemote看到的資料,推測這就是3A4000內置的GS132管理核的代碼。

一波通讀,說實話看不懂,大致明白了主要實現了DVFS功能,運行時重設PLL和FreqScale寄存器進行調頻,並通過I2C指揮PMIC進行調壓,這不和AMD SMU在做差不多的事麼?之前各種折騰SMU,感嘆於其功能之強大,但是看著這段彙編,實在和強大扯不上半點關係,於是就萌生了重構管理核中代碼的想法,我稱之為Project Miku。


驚喜發現:龍芯最新處理器實現了睿頻功能

首先,頂層設計是必不可少的,參見AMD SMU,其功能包括與主核軟件通訊,控制Sensor Hub,控制HWMon(Thermal),控制DVFS,控制片上總線QoS。

那麼龍芯的SMC可以達成些哪些功能呢?分析自PMON的彙編代碼(辣眼睛!),GS132核可以訪問片上IORING設施,包括MISC和HT,也就是可以訪問confbus下的所有寄存器和部分7A寄存器(GS132 只有32Bit訪存能力,個人推測對於64Bit地址可以通過地址窗口的形式重映射訪問,根據從龍芯開源計劃拿到的GS132 RTL代碼,GS132沒有實現MMU。)。

總而言之GS132有能力控制片上I2C用於調壓,UART用於Debug,7A的MISCBUS用於風扇和其他電源管理,以及最重要的時鐘控制。而“工欲成其事,必先利其器”,要在小核上舒舒服服的寫業務邏輯,就必須有成熟的RTOS框架。

左顧右盼之下,我選定了國產實時操作系統RT-Thread,一來之前在1C上玩過,大致熟悉其結構,二來採用了Apache開源協議,不會斷絕將來商業應用的可能。

開始我還沒拿到3A4000的機器,就只能做一些外圍工作了,主要是寫寫GS132的RT-Thread BSP。

拿到機器之後,簡單測試了一下GS132,各種彙編操作串口打印OK,確定了他確確實實存在在3A4000裡,就開始上Port的RT-Thread,哪知道現實給了我當頭一棒,根本起不來!

PC指向RT-Thread的頭部之後串口就徹底偃旗息鼓了。一番推論,我提出了個我自己都不敢相信的可能性,這玩意可能根本沒有內存!之前一直覺得和採用GS132的1C101一樣,這玩意片內應該有SRAM。如果沒有內存,沒有棧堆,那就沒有用任何操作系統的可能性了。

於是寫了一堆彙編做實驗,發現他應該是有內存的,並且內存應該是直接落到DDR控制器上,和主核共享。那為啥不能用呢?繼續寫彙編做Relocation實驗,最後得出的結論是GS132可以訪存DDR部分主存,但是無法從主存取指,好一個奇葩設計,估計是內部CrossBAR上對取指請求做出了某種限制,無奈之下只能採取常在單片機上用的Address Layout,將代碼段與只讀數據段放在ROM中,bss data stack heap放在RAM中,RAM中的數據放在操作系統為固件保留的地址,並且小心的避開了固件已經使用的部分。

操作系統起來了,下一個要關心的就是和主核軟件的通訊了。

根據彙編版本代碼,0x1fe0051c處有個Mailbox寄存器,大核和小核都能訪問,說是Mailbox,其實就是個ScratchPad,存進去的東西兩邊都能讀寫而已。大核寫完中斷GS132讓GS132上的軟件來讀取或者直接由小核輪詢,處理完成後再由大核輪詢處理結果。

看了龍芯之前的設計,基本也是這個思路,就是有幾個弊端,一是命令的硬件操作也在命令處理部分完成,導致單條命令的處理時間不確定,可能很長以至於內核輪詢超時。二是缺乏可靠的功能探測與版本表達機制,不利於之後擴展。眾所周知,在頂層設計欠下的債,以後都要還的。不破不立,因此我拋開了已有設計,參考AMD SMU的體制設計了一套”Service Request”協議進行通訊。引入了Feature Flag,並且確保每個請求都會以最快速度處理返回。

在通訊機制確立之後,作為這種機制的Proof of Conecpt,風扇控制功能和傳感器功能都被我很快地完成了,剩下最具挑戰性的DVFS/Boost功能。

在高PLL頻率的情況下,僅僅通過FreqScale把頻率拉回來並不能達成降壓的目的,一降壓就死機。原來,FreqScale和PLL的原理不一樣,他的7/8分頻僅僅是每8個邊沿中摘掉一個邊沿,單個上升沿/下降沿的時間並沒有變化。也就是說,除非Scale小於4/8,片內的時序並不會隨著Scale的變化而放寬,所以對電壓的需求也沒有放寬,僅僅是為了達成減小翻轉率以降低功耗的目的。此路不通,看來針對睿頻重設PLL是必須的。但是,我又希望在睿頻的同時Stable Counter的頻率可以保持不變。

還好,Stable Counter也有自己的Scale寄存器,也就是說,通過巧妙的計算,是有辦法讓Stable Counter的頻率保持一致的。比如,睿頻頻率是2000MHz,基礎頻率是1750MHz,那麼我們可以在睿頻狀態下對Stable Counter進行7/8分頻,使Stable Counter保持在1750MHz的頻率。進一步實驗證明了這種方案的可行性。於是到了實現環節,這裡遇到了一個問題,小核操作I2C指揮PMIC一致調不通,我也缺乏相應的設備進行邏輯分析,於是先擱置了這部分。直到後來做內核中超頻的時候從PMON裡參考來了邏輯才調通。

然後寫出了基礎邏輯,PLL分為兩個狀態,正常狀態和Boost狀態,每個狀態中再根據內核的需求進行FreqScale分頻。

然而做出來的原型又遇到了問題,降頻會死機。先是解決了一個邏輯順序問題,降頻時應該先降頻在調壓防止芯片瞬間處於高頻低電壓態。但是問題還是沒有徹底解決,問題出在在通過FreqScale降頻的時候竟然會死機?一番分析,發現死機一般出現在Scale小於2的狀況。

雖然可以簡單的過濾掉Scale < 2的狀況,但是不知道原因始終是個隱患。又是一波東問西問,得知原因是在核頻率過低時,可能不能及時返回SCache的一致性請求導致片內超時死鎖。龍芯給出的解決方案是調節芯片配置寄存器,放寬超時時間(但是會影響整體性能)。我思考了一下這個問題,覺得還有個解決方案,就是當芯片整體負載較低時,對Node(包含SCache)也進行分頻,大家都慢就不會超時了。於是在算法中加入了Idle擋位,當所有核負載都小於2/1 Normal時,將Node也進行4/8分頻,否則不允許單個核的FreqScale低於4/8分頻。

針對“雙表制”的問題,我參考了AMD的Shadow P-State設計,即暴露給內核的頻率表並不是真實頻率表,只是一層影子表,小核根據Shadow Frequency選定合適的PLL和FreqScale組合,以更好的適配cpufreq機制,並且減少對PLL的動作,畢竟操作PLL和電壓還是比較耗時的。

最後就是一些調優,加入溫度保護,調節單個擋位上維持的時間避免頻繁降頻,加入SRAM寄存器配置以適配低電壓情況,進一步降低Idle擋位的電壓以進一步減小待機功耗。並且成功通過加壓的方法,將Boost擋提高到了2200MHz,獲得了可觀的性能提升。

現在SMC的各功能在我這裡測試表現良好,期望可以早日在設備中實裝投入使用: -)。


分享到:


相關文章: