李红兵
(中国电子科技集团公司第十研究所, 成都 610036)
目前,国内二次雷达系统的显控终端通常采用X86架构CPU为核心的硬件平台,对外数据交互通过千兆以太网或者PCIE接口,以完成雷达系统的控制、状态显示和人机交互等功能。[1]千兆以太网存在速率低、包开销大、对处理器有特定要求等问题。PCIE总线形成树形层级架构,适合点对点通信,不支持多设备间数据交换功能。为了满足二次雷达系统高速通信的需求,使用新的总线来替代原有的通信接口。
RapidIO总线是当前广泛应用的一种嵌入式系统内部互联架构,具有高带宽、低延迟、支持多处理器等特征。它比千兆以太网提供更高的传输速率,比PCIE更适合组建平行通信网络,能满足当前二次雷达系统中的数据传输需求。
本文在某型二次雷达系统的工程研制中设计并实现了Linux操作系统下PCIE to RapidIO桥芯片Tsi721的驱动程序,将RapidIO总线技术成功应用于显控终端,使得整个二次雷达系统形成基于RapidIO网络的高速互联架构,提高了该雷达系统的作战性能。
Tsi721是美国IDT公司生产的PCIE to RapidIO桥接芯片。它提供了在PCIE与RapidIO总线间进行协议无缝转换的硬件解决方案。Tsi721芯片能够将数据传输从PCIE总线转换到RapidIO总线,或者相反从RapidIO总线转换到PCIE总线,并保证数据传输在转换过程中的高效性和可靠性。[2]通过Tsi721,可以设计一个系统以提供基于RapidIO的网络连接性能,同时使用只有PCIE能够支持的处理器结构。图1为Tsi721的功能框图。
该芯片具有以下硬件特性:
◆ PCIE接口兼容PCIE 2.1规范,速率支持5/2.5Gbps,物理链路支持x4/x2/x1连接,12KB输入输出阻塞/非阻塞TLP缓存;
◆ RapidIO接口兼容RapidIO串行协议2.1规范,速率支持5/3.125/2.5/1.25Gbps,物理链路支持x4/x2/x1连接;
◆ 集成映射引擎,实现PCIE到RapidIO地址转换(PC2SR)和RapidIO到PCIE地址转换(SR2PC);
◆ 集成消息引擎,实现PCIE接口与RapidIO接口之间的消息通信,包含8路输出消息DMA通道和8路输入消息DMA通道,消息中传送的数据最大可达4 KB;
◆ 集成BDMA引擎,支持块DMA传输,每个BDMA通道均以链式描述符的方式工作,用于数据包或维护包的读写访问。
显控终端使用Tsi721芯片实现RapidIO接口功能,使得显控终端能通过RapidIO接口连接到图2所示的二次雷达系统中。
该雷达系统以交换模块为核心,显控终端、信号处理、信息处理、综控等各个模块通过交换模块连接在一起。每个模块与交换模块之间都存在一条单独的x1 RapidIO通道。模块通过唯一的节点ID来定位。节点间数据包传输采用RapidIO协议中的Nwrite和Nread命令。数据传输可以是点对点、广播或者组播的形式。相比以太网或者PCIE总线的树形架构,该系统内部通信方式更灵活,性能更高。
Linux内核集成的RapidIO子系统驱动在内核中形成了全局层、总线层和设备层共3层数据结构,用于维护、管理RapidIO网络中各节点的枚举、地址分配、路由表建立、节点动态入网出网等。[3]内核把Tsi721芯片虚拟为一个以太网设备,驱动通过RapidIO的message机制通信。这就要求RapidIO网络上其他设备节点也通过message机制和Tsi721芯片通信。本文的二次雷达系统要求RapidIO网络中各节点间采用Nwrite命令和Nread命令通信,这就不能满足系统要求。因此本文借助Linux字符设备的驱动框架,将Tsi721芯片实现的RapidIO节点设计成为一个字符设备,对应用层提供字符设备的读写访问方式,驱动采用全局共享存储器的方式实现Nwrite命令和Nread命令。[4]
Tsi721桥芯片驱动由PCIE设备驱动、Tsi721及RapidIO子系统配置及字符设备驱动部分组成。
PCIE总线是一种即插即用的总线,在Linux内核的支持下,当探测到设备以后能够确定其总线号、设备号和功能号[5],然后自动地为设备分配所需要的IO端口、内存资源和中断号。
如图3所示,驱动作为模块加载以后,tsi721_probe函数先根据Tsi721芯片的设备标识Device ID(0x80A)和供应商标识Vendor ID(0x111D)遍历内核中PCIE设备链表,一一进行匹配。匹配之后,从pci_device结构中获取内核分配给Tsi721芯片设备的资源。然后,调用函数pci_enable_device把Tsi721配置空间的Command域的bit 0和bit 1置成1,从而达到开启该PCIE设备的目的,再调用函数pci_request_regions通知内核该设备对应的IO端口和内存资源已经使用。其他的PCIE设备不能再使用这个区域。调用pci_ioremap_bar把刚刚申请到得物理内存映射成为虚拟内存以供驱动访问。再根据分配的中断号调用函数reques_irq挂载中断服务程序,中断服务程序处理BDMA中断、doorbell中断和message中断等。
Tsi721作为PCIE设备初始化完成以后,驱动就可以通过PCIE的配置空间访问Tsi721芯片内部的寄存器,以完成芯片的其他初始化工作。如图4所示,函数tsi721_init_pc2sr_mapping和tsi721_init_sr2pc_mappin实现PC2SR和SR2PC引擎的初始化,逐一配置8个输出、输入窗口。然后,驱动调用tsi721_bdma_maint_init初始化块DMA通道,申请DMA缓存为每个通道建立链式描述符,用于维护包的读写访问。tsi721_doorbell_init函数使能输入doorbell的接收,建立doorbell接收缓存队列。函数tsi721_messages_init配置消息请求和相应的超时时间,清除上电中断标志位及状态位。tsi721_setup_mport函数向RapidIO子系统注册Tsi721作为RapidIO网络的管理端口。函数rio_request_inb_dbell注册doorbell的回调函数,用于收到doorbell之后的处理。驱动最后调用函数rio_map_inb_region映射dma_alloc_coherent申请的DMA缓存区到RapidIO子系统,用于全局共享存储器的方式实现Nwrite命令和Nread命令。
Linux系统字符设备是能够像字节流一样被访问的设备,即对数据的读写是以字节为单位的,应用程序通过字符设备文件(比如/dev/xyz)来访问对应的硬件设备。[6]Tsi721字符设备驱动设计包括字符设备初始化及文件操作函数(open、close、read、write 等标准系统调用)的实现。
Tsi721字符设备的初始化步骤如5所示。先调用cdev_init函数初始化一个字符设备tsi721_cdev,并注册其操作函数结构体tsi721_file_operations,然后调用alloc_chrdev_region为该字符设备动态分配“主设备号”和“次设备号”,再调用cdev_add函数向内核中增加该字符设备tsi721_cdev,驱动最后调用class_create( )函数和device_create( )函数,在sysfs中注册该字符设备自己的class以及在/dev目录下创建一个tsi721的设备文件,当系统启动时udev能自动产生相应的设备节点/dev/tsi721_rio。驱动中实现的字符设备文件操作函数如图6所示。
(1) tsi721_dev_read读函数
static ssize_t tsi721_dev_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
当二次雷达系统中信号处理模块、信息处理模块或综控模块通过RapidIO写入数据到显控终端的内存中后,通过“门铃”消息机制通知显控终端,驱动程序从本地内存中读取数据,然后调用copy_to_user( )将size个内核数据复制到用户空间buf中。
(2) tsi721_dev_write读函数
static ssize_t tsi721_dev_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
驱动程序调用copy_from_user( )从用户空间buf中将size个数据拷贝到内核地址空间,然后调用tsi721_nwrite( )函数启动BDMA向其他RapidIO节点的内存中写入数据。
(3) tsi721_dev_open函数
static int tsi721_dev_open(struct inode *inode, struct file *filp)
设备打开函数,该函数主要实现获取设备资源信息。
(4) tsi721_dev_ioctl函数
static long tsi721_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
该函数提供设备相关控制命令的实现,如命令RIO_LC_WRITE(本地配置写Tsi721寄存器)、RIO_LC_READ(本地配置读Tsi721寄存器)、RIO_DBELL_TX(门铃发送)、RIO_DBELL_RX(门铃接收)、RIO_LOCAL_ID_SET(本地RapidO节点ID设置)。
(5) tsi721_dev_release函数
static int tsi721_dev_release(struct inode *inode, struct file *filp)
设备释放函数,该函数释放注册的中断资源等。
(6) 驱动测试
Tsi721驱动以内核模块的形式编译及加载[7],以方便对驱动程序的修改和测试,最后为该驱动程序编写1个简单的Makefile文件:
obj-m=tsi721.o
KVERSION=$(shell uname-r)
all:
make-C/lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:
make-C/lib/modules/$(KVERSION)/build M=$(PWD) clean
在控制台窗口使用insmod tsi721.ko命令将装载该驱动。
测试平台见图2。RapidIO网络的速率为2.5 GHz,物理连接方式为x1。显控终端分别安装windows 7操作系统和基于Linux内核的Centos 7操作系统。windows平台下Tsi721的驱动由芯片厂家IDT公司提供。Centos平台下驱动由自己开发,分别测试在不同操作系统平台下RapidIO网络的通信速率。
模块间通信速率主要取决于Tsi721芯片的BDMA传输速度及内存读写速度,二者均受到硬件条件限制。测试用数据包大小分别设置为4、8、16、32、64、128、256、512 KB和1 MB。测试流程如图7所示。显控终端使用Nwrite命令类型发送数据,经过交换模块写入综控模块的内存中。写入数据前后分别记录当前的系统时间,然后根据时间和数据包大小计算出写速率。使用Nread命令类型从综控模块的内存中读取数据,读取数据前后分别记录当前的系统时间,然后根据时间和数据包大小计算出读速率。测试结果见表1。从表1可以看出,基于Linux内核的显控终端通信速率远高于基于windows系统的显控终端。
表1 通信速率对比结果 (MByte/s)
经过测试,基于Linux系统开发的Tsi721桥芯片驱动程序实现了RapidIO通信的主要功能,通信速率相比windows系统下有明显提升。该驱动程序已经成功应用于某型号二次雷达显示终端中,取得了良好的经济、社会效益。X86+Linux的构架为各种嵌入式显示应用提供了一个友好的开发平台。本文基于模块化开发的驱动程序可以广泛应用于其他基于Linux内核的X86平台上。