DM814X系列SysLink异构核心通信组件介绍

来源:互联网 发布:怎么进入淘宝图片空间 编辑:程序博客网 时间:2024/06/07 08:49

1:异构多核间通信的基本原理

本文主要基于TMS320DM814x系列达芬奇异构多核处理器进行介绍。DM814x集成ARMcortex-A8核、c674xDSP核、高清视频处理子系统(HDVPSS)以及高清视频/图像协处理器(HD-VICP2)。HDVICP2由基于ARM968内核的Video M3核管理,可完成H.264、MPEG_4、MJPEG编解码;HDVPSS由VPSS M3核管理,具有2路高清视频捕获通道及显示通道。

异构多核处理器大多采用主从式的结构。主从式结构根据不同核的功能把处理器核分为主核和从核。主核的结构和功能一般较为复杂,负责全局资源、任务的管理和调度并完成从核的引导加载。从核主要接受主核的管理,负责运行主核分配的任务,并具有本地任务调度与管理功能。在多核处理器中,根据不同核的结构,各个核可运行相同或不同的操作系统。在DM814x中ARM为主核、DSP和协处理器为从核,ARM 核运行开源的Liunx系统,也可以运行TI的实时操作系统SYS/BIOS,DSP核和M3核运行实时操作系统SYS/BIOS。

主从式的异构多核处理器核间的互联结构如图1所示。

图1  主从式异构多核互联结构

从图1可知,为了实现异构多核之间的通信,在芯片内设计了核间中断控制器以及核间互联的总线。核间中断是多核问任务同步与通信的桥梁,核间中断寄存器各标志位分配给芯片内不同的核,通过核间中断向另一个核发送中断请求,执行相应的中断服务程序或通过中断寄存器传递地址,配合共享内存实现数据的传递与共享。各个核心对于外设的访问则通过配置总线等实现。

综上,实现各个处理器核有效的管理和通信需要具备以下功能:
    1)主处理器对从处理器进行管理;

2)内部处理器之间信息的传输和交换。

前者可通过片上互联实现,后者则由核间中断和内存共享来实现。下面将以DM814x为例详细说明上述功能的实现。

1.1       核间中断

为了实现高效的片上核间通信,DM814x系列达芬奇处理器片上集成硬件邮箱中断(Mailbox Interrupts)和自旋锁(Spinlocks)。DM814x有12个邮箱,每个邮箱有4个中断源以向4个核发送中断,并且提供4个消息深度的FIFO,每个消息32位宽。每个邮箱都可以由任意一个核读写,通过相应的寄存器设置中断发送者以及接收者,通过消息寄存器传递消息圳。ARM、DSP和2个M3媒体控制器之间通过系统级的邮箱进行通信,每个HDVICP2有各自独立的邮箱,可以向自身内部模块和其他核发送中断。

1.2       共享内存

共享内存的实现首先需要系统对内存进行合理的映射与管理,每一个子系统都有自己的内存和内存映射寄存器,为了简化软件的开发,DM814x使用统一的映射,从而使得芯片资源具有一致性。

DM814x中运行Linux和SYS/BIOS两套操作系统,它们分别采用makefile机制与XDC构建系统。Linux在运行时通过内核启动参数来配置由内核管理的内存空间,SYS/BIOS在构建时采用XDC配置文件进行数据区、代码区等内存区的分配。系统构建与运行时需要对各个核所使用的内存以及共享内存进行划分。作为共享内存,可供不同处理器共享使用,为了实现共享资源的互斥访问,芯片集成硬件自旋锁,以解决多核间共享资源的访问互斥问题。

2:异构多核间任务通信的实现

异构多核处理器实现高效的核间通信与协作,不仅需要片上硬件模块的支持,还需要在软件中提供任务间通信的机制。Linux和SYS/BIOS都提供了本操作系统上进程通信的机制,在Linux中有管道、消息队列、信号量、共享内存等任务间同步与互斥的方式,SYS/BIOS中有 信号量,邮箱,事件等方式,而对于核间的通信,TI提供了 一套异构多核间通信组件SysLink,为用户核间通信提供了多种的实现方法下面将介绍SysLink特性和相关的API。

SysLink组件主要由以下组件构成:

系统管理(System Manager)

处理器管理(Processor Manager——PM)

核间通信(Inter-Processor Communication——IPC)

其他模块(Utility Modules)

2.1、系统管理

系统管理模块(IPC module)为方便多核管理提供了简单快捷的方法,此外也为系统资源(系统内存)的管理提供了接口。

IPC模块提供的功能包括:

SysLink系统初始化(syslink_setup()、syslink_destroy())并为其他SysLink组件分配内存,包括IPC模块和PM模块(MemoryOS_setup()、Ipc_setup(&config))

系统配置:任何系统级别的配置信息是由系统管理;

2.2、处理器管理

ProcMgr模块为从处理器提供了以下services

1)boot-loading从处理器

2)读写从处理器的内存区

3)从处理器电源管理

因此该模块为以上services提供了以下接口:

Loader:处理器的Loader接口有多种实现实现方式,被写入的文件形式可能是如COFF、ELF、动态loader(不太清楚这是啥)或者自定义类型的文件等等;

PowerManager:考虑到处理器管理模块的通用性并且希望电源管理模块可以自定义,在SysLink中电源管理是可嵌入处理器管理的独立模块;

ProcessorManager:为处理器提供了加载、MMU管理(A8支持)、读写从处理器内存等接口。在SysLink系统中,为了方便管理,每个处理器都会被编码(即Processor ID);如图中所示,在该系统中使用了硬件抽象层来屏蔽底层硬件差异,这样做的好处就是为不同的底层硬件提供了通用的软件接口。SysLink中从处理器的Loader文件理论上支持多种格式,在SysLink Release版本中主要支持COFF和ELF。在TI的编译系统中,可以以可执行文件的后缀名来区别COFF文件和ELF文件。当前的ELF Loader只支持顺序加载,即只有当一个从处理器加载并启动后才能去加载下一个从处理器,不支持并行加载。

图2:Loader流程图

2.3、处理器间通信协议(Inter-Processor CommunicationProtocols)

SysLink下定义了以下几种通信机制:

Notify、MessageQ、ListMp、GateMp、HeapBufMp、HeapMemMp、FrameQ(通常用于raw 视频数据)、RingIO(通常用于音频数据)

这些通信机制的接口都有一下几个共同点:

所有IPC通信机制的接口都由系统规范化的命名;在HLOS端,所有IPC 接口都有<Module>_setup() and<Module>_destroy()。API用于初始化或者销毁相应的IPC Module;部分初始化还需要提供配置接口,<Module>_config();所有的实例化都需要使用<Module>_create()来创建,使用<Module>_delete()来删除;在更深层次使用IPC时需要用API <Module>_open()来获取handle,在结束使用IPC时需要用API <Module>_close()来回收handle;IPC的配置多数都是在SYS/BIOS下完成配置的,对于支持XDC配置的则可以使用静态配置方法;每个IPC模块都支持Trace信息用于调试,而且支持不同的trace等级;部分IPCs提供了专门的APIs来用于提取分析信息;

2.3.1、Notfiy

Notify组件将硬件中断抽象成多组逻辑事件,是一种简单快捷的发送低于32bit信息的通信方式。Notify模块使用硬件中断,因此不能被频繁调度。事件是有优先级的,EventId越小优先级越高,事件0的优先级最高,随着EventId增大优先级依次递减;当多个事件被触发,优先级最高的会最先响应。如信令传递、buffer指针传递等。在信令传递时使用高优先级的事件,如事件0;而在传递buffer指针是可以使用低优先级的事件,如事件30等。由于其他模块使用了Notify机制,因此在SysLink中预留了部分事件号,这部分事件号用户需要慎重选用(如果你没有使用其他组建的话,可以考虑占用这部分事件号),在注册事件前可以使用Notify_eventAvailable()来检查该事件是否可用,即该中断号上的该事件号是否被注册。

2.3.2、MessageQ

MessageQ,基于队列的消息传递,有以下特点:

实现了处理期间变长消息的传递;消息的传递都是通过操作消息队列来实现的;每个消息队列可以有多个写者,但只能有一个读者;每个任务(task)可以对多个消息队列进行读写;一个宿主在准备接收消息时,必须先创建消息队列,而在发送消息前,需要打开预定的接收消息队列;

2.3.3、ListMP

ListMP实现了多宿主双向循环链表,即该双向循环链表为多个处理器共同拥有,可以由多个处理器共同维护,共同使用。ListMP的实现区别于一般的双向循环链表,因此它不仅具有双向循环链表的特性外,还增添了其他的特性,比如以下几点:

实现了简单的多宿主协议,支持多个读写者(multi-reader、multi-write);

使用Gate作为内部保护机制,防止多个宿主处理器同时访问该链表;

ListMP的实现并未加入通知机制,如果需要的话,可以在外部封装是引入Notify机制来实现;使用ListMP机制来管理的buffers都需要从共享内存区分配,包括从堆内存分配的buffers以及动态分配的内存。

2.3.4、GateMp

GateMP是针对于多处理器共享资源的一种保护机制,就如其名字一样,把共享资源比作房子,那么GateMP就是这个房子的门。GateMP组件实现了开关门的机制,用于保护共享资源一次只被一个处理器读写。根据SOC硬件资源配置的不同,GateMP的实现有所不同。对于硬件支持Hardware Spinlock的可以基于H/W spinlock来实现GateHwSpinlock;而对于没有该硬件资源的系统中,则使用软件方法(Peterson算法)来实现GatePeterson。

2.3.5、HeapMP

HeapMP主要包括HeapBufMP和HeapMemMP,用于共享内存区的堆内存配置和管理。

HeapMP具备以下几个特征:

支持多宿主,即无论是运行HLOS的主处理器还是运行SYS/BIOS的从处理器都可以配置和管理堆内存;可以将共享内存区配置成缓冲池(buffer pools);可以从共享内存区分配和释放缓冲区;

HeapBufMP为用户提供了固定大小的缓冲池管理接口;HepMultiBufMP为用户提供了可配置大小的缓冲池管理接口。

2.3.6、FrameQ

FrameQ是专门为传递视频帧而设计出来的组件。FrameQ的基本数据结构是可用于queue/dequeue数据的数据队列,封装了视频帧缓存指针、帧数据类型、帧宽、帧高、时间戳等信息。

对于FrameQ模块具有以下特征:支持多个读者,但写者唯一;可以分配和释放Frames;可以对指向同一块内存区多次分配和初始化成新的帧buffer;FrameQ允许有多个队列,在多通道的运用中,视频帧会根据通道号被分配到相应的帧队列中;

2.3.7、RingIO

RingIO是基于数据流的环形缓冲buffer,而且针对于音视频数据的特性做了优化。

RingIO支持一下特性:仅支持一个读者和一个写者;读写相对独立,可以在不同的进程或者处理器中同时进行读写操作;

2.4、公共组件(基础组件)

Utility Modules包括SharedRegion、List、Trace、MultiProc、NameServer等,这些模块是上层组件实现的基础。

2.4.1、SharedRegion

SharedRegion有两种配置方式,即静态配置方法和动态配置方法。实际配置中需要指明共享内存区在各个处理器中映射的虚拟地址及堆栈设置等,SharedRegion模块由于其状态都存在处理器本地的内存中,因此其本身并不会占用共享内存区空间。所有的SharedRegion模块API都是用Gate用于进程互斥操作。

SharedRegion模块会为系统中每个处理器创建一个共享内存查找表。在这个查找表中包含了所有处理器与共享内存区的关系及相关设置。如果某块共享内存区对于某处理器是不能访问,那么在表中会设置为空。

2.4.2、MultiProc

MultiProc模块用于多核处理器中唯一的标识处理器(多处理器ID管理,在 fwload的程序中,其中调用MultiProc_getId获取ProcId用于ProcMgr_open的参数),在使用该模块前,需要在IPC环境中使用*.cfg脚本来配置多处理器环境。

3:基于link的McFW的软件框架介绍

基于sysLinkIPc底层通信模块,TI设计了一个高清音视频采集、编码、传输的McFW软件框架,这个框架将运行在各个核上的线程统一为一个Link结构。

3.1 Link介绍

每一个link就是一个具有一定功能的线程和相关数据结构的组合,每一个link都有一个唯一的ID,可以从这个ID中可以看出这个Link是运行在哪一个核上的,每个link可以有多个输入队列和输出队列以及Notify机制通知新数据是否准备好。

    并且在Link创建的时候,要告诉这个Link的上一个link,和下一个要连接的link,从而把所有的link连接到一起,组成一个chain。

    而Link中的各个线程则是通过MessageQ信号量等线程通信机制进行同步与互斥,对于视频数据则是通过核间共享内存避免数据的转移,从而可以实现高效的核间数据共享。

3.2 Link 的工作机制

在每个link中必须实现一些函数并在初始化时注册这些函数指针给link管理的核心模块,用于帧数据的获取、释放、dump相关状态等。

对于任一个link想从它的上游link获取帧数据都需要调用link管理核心函数System_getLinksFullFrames(),该函数内部会发送消息到对应的上游link,触发该link向管理模块注册的回调函数System_LinkGetOutputFramesCb()将帧数据传递给该link;

同样的,在当一个link想释放处理完毕的帧buffer给上游link时需要调用link管理核心函数System_putLinksEmptyFrames(),该函数内部会发送消息到对应的上游link,触发它注册的回调函数System_LinkPutEmptyFramesCb()将帧buffer回收,用于后续的数据处理;

建立chain时,所有的下游link的link都会注册一个System_GetLinkInfoCb()的回调函数,在下游link的driver中会在创建driver时调用System_linkGetInfo()函数来获取上游link的相关参数。

通过上述的方法,对于一个link来说就不需要关心和它交互的是哪一个link,所有的寻址都通过linkID来自动查找,并且同一个link实现可以和不同的link交互,而不需要改变函数的实现。

0 0