Davinci的異構多核間通信基礎組件SysLink 2.0

=======================================================================================================

轉載請註明原文地址:http://blog.csdn.net/crushonme/article/details/10287693

部分模塊由於沒有用過,也沒看到SysLink包中提供例子,所以只是簡略介紹。

文中給出的API並不會給出相關解釋,請參考SysLink API Reference Documentation

注:這部分涉及到cfg腳本(XDC)配置,用得比較少,涉及到很多TI及其他公司封裝的java類庫,後續等俺學習了再詳細說明。

=======================================================================================================

緒論:Davinci中的多核系統一般由GPP+DSP構成,也就是所謂的異構多核(同構是指內部核的結構是相同的,而異構是指內部的核結構是不同的),爲了爲異構多核處理器間提供高效的異構多核協作,需要建立異構多核間的通信機制。在TI提供的異構多核間通信組件SysLink中,核間通信機制爲用戶提供了多種實現方法。下面的內容將介紹SysLink架構、特性和相關的API。


關鍵詞

縮寫詞 解釋
HLOS Higher Level Operating System
RTOS Real Time Operating System
CCS Code Composer Studio
IPC Inter-Processor Communication
GPP General Purpose Processor e.g.ARM
DSP Digital Signal Processor e.g. C64X
CGTools Code Gen Tools e.g.Compiler Linker Archiver


SysLink工具包爲異構多核之間的通信提供基礎開發接口,使得多核系統之間更方便的交換信息。在多核異構系統中,每個核心運行的操作系統和所處地位各不相同。所運行的OS可以是HLOS,如Linux、WinCE等,也可以是RTOS如SYS/BIOS或者QNX。異構多核系統中主處理器(Host Processor)肩負着控制從處理器(Slave Processor)的責任。


廣義上的SysLink包含了運行在HLOS上的SysLink和運行在RTOS上的IPC。其基本架構如下圖所示:



SysLink工具包主要針對於嵌入式操作系統中的應用,主要由以下組件構成:

  • 系統管理(System Manager)
  • 處理器管理(Processor Manager——PM)
  • 核間通信(Inter-Processor Communication——IPC)
  • 其他模塊(Utility Modules)

1、系統管理

        系統管理模塊(IPC module)爲方便多核管理提供了簡單快捷的方法,此外也爲系統資源(e.g.系統內存)的管理提供了接口。

        IPC 模塊提供的功能包括:

  • SysLink系統初始化(syslink_setup()syslink_destroy())併爲其他SysLink組件分配內存,包括IPC模塊和PM模塊(MemoryOS_setup()、Ipc_setup(&config))
  • 系統配置:任何系統級別的配置信息是由系統管理;

2、處理器管理

        ProcMgr模塊爲從處理器提供了以下services:具體例子可以參見DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_linux\utils\fw_load中firmware load的例子。

  • boot-loading從處理器
  • 讀寫從處理器的內存區
  • 從處理器電源管理
        因此該模塊爲以上services提供了以下接口:

  • Loader:處理器的Loader接口有多種實現實現方式,被寫入的文件形式可能是如COFF、ELF、動態loader(不太清楚這是啥)或者自定義類型的文件等等;
  • Power Manager:考慮到處理器管理模塊的通用性並且希望電源管理模塊可以自定義,在SysLink中電源管理是可嵌入處理器管理的獨立模塊;
  • Processor Manager:爲處理器提供了加載、MMU管理(A8支持)、讀寫從處理器內存等接口。
Loader流程圖:

Processor Manager系統框架圖如下

        在SysLink系統中,爲了方便管理,每個處理器都會被編碼(即Processor ID);如圖中所示,在該系統中使用了硬件抽象層來屏蔽底層硬件差異,這樣做的好處就是爲不同的底層硬件提供了通用的軟件接口。

注:

  1. SysLink中從處理器的Loader文件理論上支持多種格式,在SysLink Release版本中主要支持COFF和ELF。在TI的編譯系統中,可以以可執行文件的後綴名來區別COFF文件和ELF文件,後綴名中帶有‘e’的是ELF(如:xxx.xe64P),不帶‘e’的是COFF文件(如:xxx.x64P)。
  2. 當前的ELF Loader只支持順序加載,即只有當一個從處理器加載並啓動後才能去加載下一個從處理器,不支持並行加載。

3、處理器間通信協議(Inter-Processor Communication Protocols)

        SysLink下定義了以下幾種通信機制:

  • Notify
  • MessageQ
  • ListMp
  • GateMp
  • HeapBufMp
  • HeapMemMp
  • FrameQ(通常用於raw 視頻數據)
  • RingIO(通常用於音頻數據)
       這些通信機制的接口都有一下幾個共同點:

  1. 所有IPC通信機制的接口都由系統規範化的命名;
  2. 在HLOS端,所有IPC 接口都有<Module>_setup() and <Module>_destroy() API用於初始化或者銷燬相應的IPC Module;部分初始化還需要提供配置接口,<Module>_config();
  3. 所有的實例化都需要使用<Module>_create()來創建,使用<Module>_delete()來刪除;
  4. 在更深層次使用IPC時需要用API <Module>_open()來獲取handle,在結束使用IPC時需要用API <Module>_close()來回收handle;
  5. IPC的配置多數都是在SYS/BIOS下完成配置的,對於支持XDC配置的則可以使用靜態配置方法;
  6. 每個IPC模塊都支持Trace信息用於調試,而且支持不同的trace等級;
  7. 部分IPCs提供了專門的APIs來用於提取分析信息;

3.1、Notify

Notify組件將硬件中斷抽象成多組邏輯事件,是一種簡單快捷的發送低於32bit信息的通信方式。

Notify組件提供了以下接口:

  1. 初始化並配置Notify組件;Notify_attach();
  2. 註冊/註銷事件;Notify_registerEvent()/Notify_unregisterEvent()/Notify_registerEventSingle()/Notify_unregisterEventSingle()
  3. 發送帶參數的事件給某處理器;Notify_sendEvent()
  4. 通過回調函數接收事件;Notify_FnNotifyCbck()
  5. 使能/禁用事件;Notify_diableEvent()/Notify_enableEvent()
  6. 其他邏輯接口;Notify_eventAvailable()/Notify_intLineRegistered()/Notify_numIntLines()/Notify_restore()
注:

  1. 同一個中斷號可以註冊多個事件,同一個事件可以有多個回調函數或者多個宿主(可以是處理器、線程或者任務),事件被觸發後所有宿主都會被喚醒;
  2. 一個事件可以接收多個宿主發送來的通知(notification),事件所攜帶的參數最大支持32bit;
  3. 事件是有優先級的,EventId越小優先級越高,事件0的優先級最高,隨着EventId增大優先級依次遞減;當多個事件被觸發,優先級最高的會最先響應;
  4. Notify模塊使用硬件中斷,因此不能被頻繁調度。

Notify組件常用於傳遞附帶消息少於32bit的場景,如信令傳遞、buffer指針傳遞等。在信令傳遞時使用高優先級的事件,如事件0;而在傳遞buffer指針是可以使用低優先級的事件,如事件30等。

在Notify_sentEvent() API中帶有參數waitClear,該參數爲可選參數,如果waitClear爲TRUE,這就意味着多宿主事件無法及時響應,必須等待前一宿主事件結束後才能響應下一宿主;如果waitClear爲FALSE,最好不要爲事件附帶參數,否則多宿主事件可能會由於消息被覆蓋而出現丟消息的現象。該API最好不要在中斷服務程序(ISR)中調用(特別是waitClear = TRUE時),否則會導致中斷調度出現異常(表現之一:高優先級的中斷響應會延遲);此外該API不能再使用GateMP模塊鎖保護的程序段中調用,否則可能會導致操作系統死鎖。

由於其他模塊使用了Notify機制,因此在SysLink中預留了部分事件號,這部分事件號用戶需要慎重選用(如果你沒有使用其他組建的話,可以考慮佔用這部分事件號),在註冊事件前可以使用Notify_eventAvailable()來檢查該事件是否可用,即該中斷號上的該事件號是否被註冊

Module Event Ids
FrameQBufMgr 0
FrameQ 1
MessageQ(TransportShm) 2
RingIO 3
NameServerRemoteNotify 4

3.2、MessageQ

MessageQ,顧名思義,基於隊列的消息傳遞,可不是MaggieQ噢,哈哈。

MessageQ有以下特點:

  • 實現了處理期間變長消息的傳遞;
  • 消息的傳遞都是通過操作消息隊列來實現的;
  • 每個消息隊列可以有多個寫者,但只能有一個讀者;每個任務(task)可以對多個消息隊列進行讀寫;
  • 一個宿主在準備接收消息時,必須先創建消息隊列,而在發送消息前,需要打開預定的接收消息隊列;

MessageQ組件常用在滿足以下條件的場景中:

  1. 在消息傳遞中有多個寫者,但僅有一個讀者;
  2. 所需要傳遞的消息超過32bit,且長度可變;讀寫者的緩衝區大小相同;
  3. 處理期間需要頻繁傳遞消息,在這種情況下,消息被依次放入隊列,能保證不會丟消息;
  4. 消息隊列爲空時,調用MessageQ_get()獲取消息時會被阻塞,直到消息隊列被寫入消息;
  5. 支持處理器間移動消息隊列,在這種情況下,調用MessageQ_open()來定位隊列位置,而消息傳遞部分代碼不需要改動;

MessageQ組件提供了以下幾個API:

  1. 消息隊列初始化:MessageQ_Params_init()
  2. 消息隊列創建/銷燬:MessageQ_create()/MessageQ_delete(),create創建消息隊列,並分配相應存儲空間
  3. 消息隊列打開/關閉:MessageQ_open()/MessageQ_close(),open時會返回遠程處理器上的QueID的地址。
  4. 爲消息隊列分配堆內存:MessageQ_alloc()/MessageQ_free()
  5. 爲消息隊列註冊/註銷堆內存:MessageQ_registerHeap()/MessageQ_unregisterHeap()
  6. 向消息隊列中放入/獲取消息:MessageQ_put()/MessageQ_get()
  7. 其他邏輯API:
  • 獲取消息隊列ID:MessageQ_getQueueId()
  • 獲取消息隊列中消息數:MessageQ_count()
  • 在消息隊列中嵌入消息:MessageQ_setReplyQueue()
  • 爲消息隊列解阻塞:MessageQ_unblock()
  • 爲調試消息隊列加入Trace:MessageQ_setMsgTrace()


3.3、ListMP

ListMP實現了多宿主雙向循環鏈表,即該雙向循環鏈表爲多個處理器共同擁有,可以由多個處理器共同維護,共同使用。

ListMP的實現區別於一般的雙向循環鏈表,因此它不僅具有雙向循環鏈表的特性外,還增添了其他的特性,比如以下幾點:

  • 實現了簡單的多宿主協議,支持多個讀寫者(multi-reader、multi-writee);
  • 使用Gate作爲內部保護機制,防止多個宿主處理器同時訪問該鏈表;
ListMP的實現並未加入通知機制,如果需要的話,可以在外部封裝是引入Notify機制來實現;使用ListMP機制來管理的buffers都需要從共享內存區分配,包括從堆內存分配的buffers以及動態分配的內存。

ListMP組件常用於滿足一下條件的場景中:

  1. 需要被多個宿主訪問並且需要頻繁傳遞消息或者數據;
  2. 可用於無規則的消息傳遞,基於鏈表實現,因此讀者可以遍歷所有對象,並選出需要的對象進行處理;如果硬件支持快速隊列,則無法完成隊列遍歷操作(WHY)
  3. 可以自定義消息優先級,同樣是基於鏈表實現,讀者可以隨意的選擇在鏈表頭部還是鏈表的尾部來插入消息或者實現鏈表對象的位置調整,進而實現消息的優先級選擇;如果硬件支持快速隊列,則無法完成隊列遍歷操作(WHY);
  4. 無內置通知機制,可以靈活的外部通知機制來實現。譬如根據實際情況,選用Notify來實現,亦或是使用選用MessageQ則可以使用最少的中斷資源實現性能優良的通知機制,缺點是需要額外的代碼實現通知機制。
ListMP組件提供了以下API接口:

  1. ListMP參數初始化:ListMP_Params_init()
  2. ListMP創建/銷燬:ListMP_create()/ListMP_delete()
  3. ListMP打開/關閉:ListMP_open()/ListMP_close()
  4. ListMP相關鏈表操作:
  • 判斷鏈表空:ListMP_empty()
  • 獲取保護鎖:ListMP_getGate()
  • 獲取鏈表頭/表尾:ListMP_getHead()/ListMP_getTail()
  • 鏈表插入操作:ListMP_insert()
  • 獲取鏈表上游元素/下游元素:ListMP_next()/ListMP_prev()
  • 插入元素到鏈表頭/尾:ListMP_putHead()/ListMP_putTail()
  • 刪除元素:ListMP_remove()


3.4、GateMP

GateMP是針對於多處理器共享資源的一種保護機制,就如其名字一樣,把共享資源比作房子,那麼GateMP就是這個房子的門。GateMP組件實現了開關門的機制,用於保護共享資源一次只被一個處理器讀寫。根據SOC硬件資源配置的不同,GateMP的實現有所不同。對於硬件支持Hardware Spinlock的可以基於H/W spinlock來實現GateHwSpinlock;而對於沒有該硬件資源的系統中,則使用軟件方法(Peterson算法)來實現GatePeterson。

GateMP組件框架如下:


GateMP組件對用戶提供了以下API接口:

  1. GateMP初始化:GateMP_Params_init();
  2. GateMP創建/刪除:GateMP_create()/GateMP_delete();
  3. GateMP打開/關閉:GateMP_open()/GateMP_close();
  4. 進入/離開GateMP保護:GateMP_enter()/GateMP_leave();
  5. 獲取當前GateMP的保護類型:GateMP_getLocalProtect()/GateMP_getRemoteProtect();

注:如果某個處理器在想使用被某個GateMP保護的共享資源,那麼該處理器會被阻塞,直到該資源被釋放(即GateMP_leave())。


3.5、HeapMP

HeapMP主要包括HeapBufMP和HeapMemMP,用於共享內存區的堆內存配置和管理。

HeapMP具備以下幾個特徵:

  • 支持多宿主,即無論是運行HLOS的主處理器還是運行SYS/BIOS的從處理器都可以配置和管理堆內存;
  • 可以將共享內存區配置成緩衝池(buffer pools);
  • 可以從共享內存區分配和釋放緩衝區;

3.5.1、HeapBufMP

HeapBufMP爲用戶提供了固定大小的緩衝池管理接口;

HeapBufMP組件爲用戶提供的API接口如下:

  1. HeapBufMP創建/刪除:HeapBufMP_create();HeapBufMP_delete();
  2. HeapBufMP打開/關閉:HeapBufMP_open();HeapBufMP_close();
  3. HeapBufMP參數初始化:HeapBufMP_Params_init();
  4. HeapBufMP分配/釋放內存:HeapBufMP_alloc();HeapBufMP_free();
  5. HeapBufMP獲取所有狀態:HeapBufMP_getExtendedStats();HeapBufMP_getStats();


3.5.2、HeapMultiBufMP

在SysLink包中並沒有找到相關API,但SysLink UserGuide中有提到.

HepMultiBufMP爲用戶提供了可配置大小的緩衝池管理接口。


3.5.3、HeapMemMP

HeapMemMp爲用戶提供了基於堆的可變大小的內存管理機制。

HeapMemMp組件爲用戶提供的接口如下:

  1. HeapMemMP參數初始化:HeapMemMP_Params_init();
  2. HeapMemMP創建/刪除:HeapMemMP_create()/HeapMemMP_delete();
  3. HeapMemMP打開/關閉:HeapMemMP_open()/HeapMemMP_close();
  4. HeapMemMP分配/釋放內存:HeapMemMP_alloc()/HeapMemMP_free();
  5. HeapMemMP獲取內存狀態:HeapMemMP_getExtendedStats()/HeamMemMP_getStats();
  6. HeapMemMP恢復內存初始狀態:HeapMemMP_restore();

3.6、FrameQ

FrameQ是專門爲傳遞視頻幀而設計出來的組件。FrameQ的基本數據結構是可用於queue/dequeue數據的數據隊列,封裝了視頻幀緩存指針、幀數據類型、幀寬、幀高、時間戳等信息。
對於FrameQ模塊具有以下特徵:
  • 支持多個讀者,但寫者唯一;
  • 可以分配和釋放Frames;
  • 可以對指向同一塊內存區多次分配和初始化成新的幀buffer;
  • FrameQ允許有多個隊列,在多通道的運用中,視頻幀會根據通道號被分配到相應的幀隊列中;
FrameQ中用於buffer管理的模塊稱爲FrameQBufMgr,該模塊用於提供buffer管理接口和通知機制。

FrameQ提供以下API接口:
  1. FrameQ組件初始化/銷燬:FrameQ_setup()/FrameQ_destroy();
  2. 創建/刪除FrameQ實例:FrameQ_create()/FrameQ_delete();
  3. 打開/關閉FrameQ實例:FrameQ_open()/FrameQ_close();FrameQ_openByAddr();
  4. 爲FrameQ實例分配/釋放內存:FrameQ_alloc()/FrameQ_free();FrameQ_allocv/FrameQ_freev();
  5. 插入/釋放FrameQ中幀:FrameQ_put()/FrameQ_get();FrameQ_putv()/FrameQ_getv();
  6. 複製給定的幀:FrameQ_dup();
  7. 註冊/註銷FrameQ通知:FrameQ_registerNotifier()/FrameQ_unregisterNotifier();
  8. 強制發送通知:FrameQ_sendNotify()
  9. 獲取FrameQ中有效幀數/已被釋放的幀數:FrameQ_getNumFrames()/FrameQ_getNumFreeFrames();                   FrameQ_getvNumFrames()/FrameQ_getvNumFreeFrames()
  10. FrameQ控制:FrameQ_control()
  11. 獲取FrameQ的頭指針:FrameQ_getExtendedHeaderPtr();
  12. 獲取幀buffer/幀大小/幀數:FrameQ_getFrameBuffer()/FrameQ_getFrameBufSize()/FrameQ_getNumFrameBuffers();
  13. 獲取空數據幀大小/位置:FrameQ_getFrameBufValidSize()/FrameQ_getFrameBufDataStartOffset();
  14. 設置空數據幀大小/位置:FrameQ_setFrameBufValidSize()/FrameQ_setFrameBufDataStartOffset();
  15. 獲取FrameQ默認設置:FrameQ_getConfig();

3.7、RingIO

RingIO是基於數據流的環形緩衝buffer,而且針對於音視頻數據的特性做了優化。
RingIO支持一下特性:
  • 僅支持一個讀者和一個寫者;
  • 讀寫相對獨立,可以在不同的進程或者處理器中同時進行讀寫操作;
RingIO爲用戶提供了以下接口:
  1. RingIO參數初始化:RingIO_Params_init();
  2. 創建/刪除RingIO對象:RingIO_create()/RingIO_delete();
  3. 打開/關閉RingIO對象:RingIO_open()/RingIO_close();RingIO_openByAddr();
  4. 獲取共享內存請求:RingIO_sharedMemReq();
  5. 註冊/註銷RingIO通知:RingIO_registerNotifier()/RingIO_unregisterNotifier();
  6. 強制發送RingIO通知:RingIO_sendNotify();
  7. 獲取RingIO通知類型:RingIO_setNotifyType();
  8. 設置/獲取水印標誌/通知類型:RIngIO_setWaterMark()/RIngIO_getWaterMark()
  9. 獲取/釋放RingIO數據:RingIO_acquire()/RingIO_release();
  10. 設置/獲取RingIO屬性:RingIO_setvAttribute()/RingIO_getvAttribute();
  11. 設置/獲取RingIO固定大小的屬性:RingIO_setAttribute()/RingIO_getAttribute();
  12. 刷新RingIO的buffer:RingIO_flush();
  13. 獲取有效/空buffer大小:RingIO_getValidSize()/RingIO_getEmptySize();
  14. 獲取有效/空屬性大小:RingIO_getValidAttrSize()/RingIO_getEmptyAttrSize();
  15. 獲取用戶需求buffer的大小/位置:RingIO_getAcquiredSize()/RingIO_getAcquiredOffset();


4、公共組件(基礎組件)

Utility Modules包括SharedRegion(IPC中屬於類庫ti.sdo.ipc.SharedRegion)、ListTraceMultiProcNameServer等,這些模塊是上層組件實現的基礎。在IPC包中,該組件對應於類庫ti.sdo.utils.


4.1、SharedRegion(非常重要,SysLink模塊最基礎的模塊)

4.1.1、SharedRegion總覽

SharedRegion顧名思義,是共享內存區的意思。SharedRegion模塊負責管理共享內存區。在一個有共享內存的多核架構中,普遍會遇到共享內存映射虛擬地址轉換問題,如下圖所示:


SharedRegion有兩種配置方式,即靜態配置方法(對於SYS/BIOS側可以通過cfg腳本配置,而對於HLOS則當從處理器被加載的時候會通過讀取SYS/BIOS共享內存區配置信息來獲取,請參考內核driver/dsp/syslink/notify_shmdriver/notify_shm_drv.c中實現)和動態配置方法(通過SharedRegion模塊提供的API SharedRegion_setEntry()來設置,但值得注意的是這個API只是把入口信息放入該處理器對應的共享內存查找表中,而其他處理器也需要在自己的系統中使用該API來加入該入口)。實際配置中需要指明共享內存區在各個處理器中映射的虛擬地址及堆棧設置等,如上圖所示,對於proc0來說,SR0映射出的虛擬地址爲0x80000000,而對於Proc[1..3]映射出的地址則是0x90000000;SR0中有部分預留區域且被配置成HeapMemMP(見3.5.3節);此外由上圖還可以知道,SharedRegion 1是Proc1--Proc6構成的子系統的內部共享內存,且配置成使用HeapMemMP來管理。

       SharedRegion模塊由於其狀態都存在處理器本地的內存中,因此其本身並不會佔用共享內存區空間。所有的SharedRegion模塊API都是用Gate用於進程互斥操作。
       SharedRegion模塊會爲系統中每個處理器創建一個共享內存查找表。在這個查找表中包含了所有處理器與共享內存區的關係及相關設置。如果某塊共享內存區對於某處理器是不能訪問,那麼在表中會設置爲空。
       在runtime時,共享內存查找表與共享內存區指針一起被用於快速的地址轉換操作;

       在共享內存查找表中最大入口數(即SharedRegion的個數)使用ShareRegion.numEntries靜態配置。在系統runtime中可以使用靜態配置或者動態配置增減入口數,但必須在更改後更新所有處理器的表。共享內存入口數越多耗費在地址轉換上的時間越長,因此考慮到效率,儘可能設計少的入口數。

       SharedRegion 0的意義比較特殊,在所有使用IPC組建的環境中都必須配置並且所有的處理器都有權限訪問該共享區域,雖然應用程序也可以使用這部分內存,但不建議用戶在不瞭解該區域詳細的內存分佈時使用,否則容易造成系統掛死。由DM8168的配置DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_bios6\cfg\ti816x\SYSLINK_common.cfg可以看出該區域用於MsgQ。

4.1.2、SharedRegion配置方式舉例

一般來說配置一個SharedRegion需要設置以下幾個:

  • base - The base address共享內存區的基地址,這個所謂的基地址實際上是映射後的虛擬地址,並非物理地址;
  • len - The length共享內存區的大小,對於同一片共享內存,其所有者的查找表中該項值應該是相同的;
  • name - The name of the region該共享內存區的名字;
  • isValid - Whether the region is valid對於該處理器而言,是否具有權限去訪問該共享內存區;
  • ownerProcId - The id of the processor which owns the region管理該內存區的處理器ID,該處理器具有創建HeapMemMP的權限,而其他處理器只有使用的權限;
  • cacheEnable - Whether the region is cacheable是否爲該共享內存區創建cache;
  • cacheLineSize - The cache line size  cache的大小;
  • createHeap - Whether a heap is created for the region.是否使用Heap(堆)管理該內存區域;

靜態配置方法e.g.:DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_bios6\cfg\ti816x\SYSLINK_common.cfg

01 /* Set Shared Region variables by picking up the information from Platform
02  * memory map
03  */
04 var sr0MemSection           = Program.cpu.memoryMap['SR0']; //此處值都是有config_xxx.bld文件讀取的,下同
05 var sr1MemSection           = Program.cpu.memoryMap['SR1'];
06 var sr2MemSection           = Program.cpu.memoryMap['SR2_FRAME_BUFFER_MEM'];
07 var sr3MemSection           = Program.cpu.memoryMap['SR3_FRAME_BUFFER_EXTRA'];
08 /*
09  *  Need to define the shared region. The IPC modules use this
10  *  to make portable pointers. All processors need to add this
11  *  call with their base address of the shared memory region.
12  *  If the processor cannot access the memory, do not add it.
13  
14         This section is the SR0 section of syslink and is
15         used for MsgQ's that are present on different processors.
16  
17  
18         A8  - NON-CACHED
19         M3  - NON-CACHED
20         DSP - NON-CACHED
21 */
22 SharedRegion.setEntryMeta( 0,
23     {
24       base:        sr0MemSection.base,
25       len:         sr0MemSection.len,
26       name:        sr0MemSection.name,
27       isValid:     true,
28       ownerProcId: srOwnerProcId,
29       cacheEnable: false,
30       cacheLineSize: 128,
31       createHeap:  true
32     }
33 );


注:在IPC中所給的例子除了設置以上需要設置SharedRegion.cacheLineSize、SharedRegion.numEnties、SharedRegion.translate等,如果不知道入口地址,可以講isValid設置成false,在runtime時通過計算來得到,然後是中SharedRegion_getEntry()來設置。

e.g.

1 var SharedRegion = xdc.useModule('ti.sdo.ipc.SharedRegion');
2 SharedRegion.cacheLineSize = 32;//cache行緩衝字節數,暫時還沒明白這個設置於上面例子中cacheLineSize: 128有何區別,如何不指定則使用默認值;
3 SharedRegion.numEntries = 4;//總的共享內存區個數(入口數);
4 SharedRegion.translate = true;//是否需要做地址轉換,如果設置爲false,因爲不需要做地址轉換,則對總體性能有所提升;

動態配置方法e.g.:DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_bios6\utils\src\utils_mem.c

01 SharedRegion_Entry srEntry;
02 Int                                   srStatus = SharedRegion_S_SUCCESS;
03 UInt32                           srId;
04 SharedRegion_entryInit(&srEntry);
05 SharedRegion_getEntry(srId[i], &srEntry);
06  Vps_printf (" %d: MEM: Shared Region %d: Base = 0x%08x, Length = 0x%08x (%d MB) \n",\
07                     Utils_getCurTimeInMsec(), srId[i],srEntry.base,srEntry.len, srEntry.len/(1024*1024));
08 if ((FALSE == srEntry.isValid)&&(0 != srEntry.len))
09  {
10             srEntry.isValid     = TRUE;
11             do {
12                 srStatus = SharedRegion_setEntry(srId[i], &srEntry);
13  
14  
15                 if (srStatus != SharedRegion_S_SUCCESS) {
16                     Vps_printf(" %d: MEM: ERROR: SharedRegion_setEntry (%d, 0x%08x) FAILED !!! "
17                                " (status=%d) \n", Utils_getCurTimeInMsec(), srId[i], &srEntry, srStatus);
18                     Task_sleep(1000);
19                      }
20                   while (srStatus != SharedRegion_S_SUCCESS);
21  }
22  if (srEntry.len)
23  {
24         gUtils_heapMemHandle[i] = SharedRegion_getHeap(srId[i]);
25         UTILS_assert(gUtils_heapMemHandle[i] != NULL);
26         gUtils_memClearBuf[i] = FALSE;
27 }


注:通常來說動態創建入口的方式不常用,一般只是用來更改原有配置。另外,如果想完全重新配置一個共享內存,可以在每個處理器上調用SharedRegion_clear()來清除該共享內存的入口信息。

4.1.3、如何使用SharedRegion中的內存

SharedRegion中的內存可以使用Memory_alloc(IHeap_Handle heap, SizeT size, SizeT align, Ptr eb)來動態分配。IHeap_Handle獲取方式如上例中gUtils_heapMemHandle[i] = SharedRegion_getHeap(srId[i]);


4.1.4、相關API

  • SharedRegion_clearEntry()
  • ShareRegion_entryInit()
  • SharedRegion_getCacheLineSize()
  • SharedRegion_getEntry()、SharedRegion_setEntry()
  • SharedRegion_getHeap()
  • SharedRegion_getId
  • SharedRegion_getIdByName()
  • SharedRegion_getNumRegions()
  • SharedRegion_getPtr()
  • SharedRegion_getSRPtr()
  • SharegRegion_isCacheEnabled()
  • SharedRegion_translateEnabled()
  • SharedRegion_inValidSRPtr()

4.2、List

List模塊封裝了雙向循環鏈表的操作API,SYS/BIOS側見“ti.sdo.utils.List”實現,HLOS側見 “DVRRDK_xx.xx.xx.xx\ti_tools\syslink\syslink_x_xx_xx_xx\packages\ti\syslink\utils\hlos\List.c”中實現。提供的API也就是通常用於操作鏈表的一些api接口,這裏就不多介紹了。


4.3、Trace

用於打印相關調試是使用,有點像CCS下的探針,在SysLink中根據所帶的參數分了7種不同的探針,不多介紹,具體實現參考“DVRRDK_xx.xx.xx.xx\ti_tools\syslink\syslink_x_xx_xx_xx\packages\ti\syslink\utils\common\Trace.c

在調試TI的各種開發包(如HDVPSS  ISS等)時非常方便,加載syslink.ko時需要附加參數TRACE,如:

1 insmod syslink.ko TRACE=1
2 insmod syslink.ko TRACE=1 TRACEFAILURE=1 TRACECLASS=3
3 insmod syslink.ko TRACE=1 TRACEFAILURE=1 TRACEENTER=1 TRACECLASS=3

4.4、MultiProc

MultiProc模塊用於多核處理器中唯一的標識處理器(多處理器ID管理,如果你看了fwload的程序,肯定注意到其中調用MultiProc_getId獲取ProcId用於ProcMgr_open的參數),在使用該模塊前,需要在IPC環境中使用*.cfg腳本來配置多處理器環境。

如:在DVRRDK_xx.xx.xx.xx\dvr_rdk\mcfw\src_bios6\cfg\ti816x\SYSLINK_c6xdsp.cfg中

1 /*******************************************************************************
2 * SysLink  SysMgr initializations - IPC is a part of sysLink
3 *
4 ******************************************************************************/
5 var MultiProc              = xdc.useModule('ti.sdo.utils.MultiProc');
6 var Notify                 = xdc.useModule('ti.sdo.ipc.Notify');
7  
8 /* The DSP is processor id 0 and there are 3 other cores */
9 MultiProc.setConfig("DSP", ["DSP""VIDEO-M3""VPSS-M3""HOST"]);


除了上述的靜態設置方法外,還可以主處理器起來後(此時從處理器均未startup,不能強制配置其Proc_ID)通過GPIO、Nand、EEPROM等手段動態獲取,使用MultiProc_setLocalId() API設置,但cfg文件配置還是需要的,只不過此時相應處理器名稱設置爲NULL。



MultiProc模塊提供的API主要有:

  1. 獲取/設置多核系統的基ID:MultiProc_getBaseIdOfCluster()/MultiProc_setBaseIdOfCluster();
  2. 通過處理器名字檢索其ID:MultiProc_getId();
  3. 通過處理器ID檢索其名字:MultiProc_getName();
  4. 查詢多核系統的處理器數:MultiProc_getNumProcessors()/MultiProc_getNumProcsInCluster();
  5. 返回當前處理器的ID:MultiProc_self();
  6. 設置處理器ID:MultiProc_setLocalId();

4.5、NameServer

NameServer直譯爲名稱服務器,大致看了下實現過程,有點像簡單的網絡中的DNS(Domain Name Server),即可以根據名字查找某對象(DNS中可以根據網址查找到對應網址的IP)。
NameServer的實現原理:基於鏈表的結構,並且可以根據設置決定是否對value域進行Hash編碼(查了下資料,這個可能是從java中吸其精華而改造來的),其基本數據結構如下:
01 typedef struct NameServer_TableEntry_tag {
02     List_Elem                 elem;
03     /* List element */
04     UInt32                    hash;
05     /* Hash value */
06     String                    name;
07     /* Name portion of the name/value pair. */
08     UInt                      len;
09     /* Length of the value field. */
10     Ptr                       value;
11     /* Value portion of the name/value entry. */
12     Bool                      collide;
13     /* Does the hash collides? */
14     struct NameServer_TableEntry_tag * next;
15     /* Pointer to the next entry, used incase of collision only */
16 } NameServer_TableEntry;


NameServer提供了以下API:

  • NameServer_Params_init()
  • NameServer_create()/NameServer_delete()
  • NameServer_getHandle()
  • NameServer_add()
  • NameServer_addUInt32()
  • NameServer_get()/NameServer_getUInt32
  • NameServer_getLocal()/NameServer_getLocalUInt32()
  • NameServer_removeEntry()/NameServer_remove()

在SysLink中很多組件都用到了NameServer,如FrameQ、HeapMemMP、GateMP、ListMP、MessageQ。RingIO等等。


=======================================================================================================

部分模塊由於沒有用過,也沒看到SysLink包中提供例子,所以只是簡略介紹。

文中給出的API並不會給出相關解釋,請參考SysLink API Reference Documentation

注:這部分涉及到cfg腳本(XDC)配置,用得比較少,涉及到很多TI及其他公司封裝的java類庫,後續等俺學習了再詳細說明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章